Skip to content

Commit

Permalink
feat: vue-cli and nuxt preset for CT object API architecture (#20956)
Browse files Browse the repository at this point in the history
  • Loading branch information
lmiller1990 committed Apr 8, 2022
1 parent 9970bfb commit 57659c4
Show file tree
Hide file tree
Showing 38 changed files with 26,450 additions and 53 deletions.
19 changes: 13 additions & 6 deletions npm/vite-dev-server/cypress/components/vue/Card/Card.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
// in the render options are directly passed through to the Utils mount().

/// <reference types="cypress" />
import { mount } from '@cypress/vue'

import { h } from 'vue'
import Card from './Card.vue'
import { mount } from '@cypress/vue'

describe('Card', () => {
it('skipped slots', () => {
Expand All @@ -15,10 +16,18 @@ describe('Card', () => {
})

it('renders slots', () => {
// TODO: use HTML syntax (not render function with `h`)
// when it's working.
// Blocked by upstream bug in Test Utils: https://github.com/vuejs/test-utils/issues/1166
// mount(Card, {
// slots: {
// header: `<h1>HEADER</h1>`
// },
// })
mount(Card, {
slots: {
header: '<h1>HEADER</h1>',
footer: '<div>FOOTER</div>',
header: () => h('h1', 'HEADER'),
footer: () => h('div', 'FOOTER'),
},
})

Expand All @@ -29,9 +38,7 @@ describe('Card', () => {
it('renders scopedSlots', () => {
mount(Card, {
slots: {
default: `<template #default="props">
<p>Yay! {{props.content}}</p>
</template>`,
default: ({ content }) => h('div', {}, h('p', `Yay! ${content}`)),
},
})

Expand Down
15 changes: 12 additions & 3 deletions npm/vue/cypress/component/basic/slots/Card.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

/// <reference types="cypress" />

import { h } from 'vue'
import Card from './Card.vue'
import { mount } from '@cypress/vue'

Expand All @@ -15,10 +16,18 @@ describe('Card', () => {
})

it('renders slots', () => {
// TODO: use HTML syntax (not render function with `h`)
// when it's working.
// Blocked by upstream bug in Test Utils: https://github.com/vuejs/test-utils/issues/1166
// mount(Card, {
// slots: {
// header: `<h1>HEADER</h1>`
// },
// })
mount(Card, {
slots: {
header: '<h1>HEADER</h1>',
footer: '<div>FOOTER</div>',
header: () => h('h1', 'HEADER'),
footer: () => h('div', 'FOOTER'),
},
})

Expand All @@ -29,7 +38,7 @@ describe('Card', () => {
it('renders scopedSlots', () => {
mount(Card, {
slots: {
default: '<template #default="props"><p>Yay! {{props.content}}</p></template>',
default: ({ content }) => h('div', {}, h('p', `Yay! ${content}`)),
},
})

Expand Down
11 changes: 10 additions & 1 deletion npm/vue/cypress/component/basic/small-examples/AppInput.cy.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="cypress" />

import { h } from 'vue'
import AppInput from './AppInput.vue'
import { mount } from '@cypress/vue'

Expand All @@ -11,7 +12,15 @@ it('renders label', () => {
},
// passing slots to the component #364
slots: {
label: `<label for="username">Enter Username</label>`,
// TODO: use HTML syntax (not render function with `h`)
// when it's working.
// Blocked by upstream bug in Test Utils: https://github.com/vuejs/test-utils/issues/1166
// mount(AppInput, {
// slots: {
// label: `<label for="username">Enter Username<label>`
// },
// })
label: () => h('label', { for: 'username' }, 'Enter Username'),
},
})

Expand Down
2 changes: 1 addition & 1 deletion npm/vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
},
"dependencies": {
"@cypress/mount-utils": "*",
"@vue/test-utils": "^2.0.0-rc.10"
"@vue/test-utils": "2.0.0-rc.19"
},
"devDependencies": {
"@babel/core": "7.9.0",
Expand Down
31 changes: 31 additions & 0 deletions npm/webpack-dev-server-fresh/cypress/e2e/nuxt.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// <reference types="cypress" />
/// <reference path="../support/e2e.ts" />
import type { ProjectFixtureDir } from '@tooling/system-tests/lib/fixtureDirs'

const PROJECTS: ProjectFixtureDir[] = ['nuxtjs2']

// Add to this list to focus on a particular permutation
// TODO: run vuecli4-vue2 tests once cypress/vue-2 is bundled
const ONLY_PROJECTS: ProjectFixtureDir[] = []

for (const project of PROJECTS) {
if (ONLY_PROJECTS.length && !ONLY_PROJECTS.includes(project)) {
continue
}

// TODO: This will work once `cypress/vue2` is bundled in the binary
// Since Nuxt.js 2 is based on `vue@2`.
describe.skip(`Working with ${project}`, () => {
beforeEach(() => {
cy.scaffoldProject(project)
cy.openProject(project)
cy.startAppServer('component')
})

it('should mount a passing test', () => {
cy.visitApp()
cy.contains('Tutorial.cy.js').click()
cy.get('.passed > .num').should('contain', 1)
})
})
}
29 changes: 29 additions & 0 deletions npm/webpack-dev-server-fresh/cypress/e2e/vue-cli.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// <reference types="cypress" />
/// <reference path="../support/e2e.ts" />
import type { ProjectFixtureDir } from '@tooling/system-tests/lib/fixtureDirs'

const PROJECTS: ProjectFixtureDir[] = ['vuecli4-vue2', 'vuecli4-vue3', 'vuecli5-vue3']

// Add to this list to focus on a particular permutation
// TODO: run vuecli4-vue2 tests once cypress/vue-2 is bundled
const ONLY_PROJECTS: ProjectFixtureDir[] = ['vuecli4-vue3', 'vuecli5-vue3']

for (const project of PROJECTS) {
if (ONLY_PROJECTS.length && !ONLY_PROJECTS.includes(project)) {
continue
}

describe(`Working with ${project}`, () => {
beforeEach(() => {
cy.scaffoldProject(project)
cy.openProject(project)
cy.startAppServer('component')
})

it('should mount a passing test', () => {
cy.visitApp()
cy.contains('HelloWorld.cy.js').click()
cy.get('.passed > .num').should('contain', 1)
})
})
}
19 changes: 13 additions & 6 deletions npm/webpack-dev-server-fresh/src/devServer.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
/// <reference types="cypress" />

import type WebpackDevServer from 'webpack-dev-server'
import type { Compiler } from 'webpack'
import type { Compiler, Configuration } from 'webpack'

import { createWebpackDevServer } from './createWebpackDevServer'
import { sourceRelativeWebpackModules } from './helpers/sourceRelativeWebpackModules'
import type { AddressInfo } from 'net'
import debugLib from 'debug'
import type { Server } from 'http'
import { vueCliHandler } from './helpers/vueCliHandler'
import { nuxtHandler } from './helpers/nuxtHandler'

const debug = debugLib('cypress:webpack-dev-server-fresh:devServer')

Expand All @@ -20,7 +22,7 @@ export type WebpackDevServerConfig = {
webpackConfig?: unknown // Derived from the user's webpack
}

const ALL_FRAMEWORKS = ['create-react-app', 'nuxt', 'react'] as const
const ALL_FRAMEWORKS = ['create-react-app', 'nuxt', 'react', 'vue-cli'] as const

/**
* @internal
Expand Down Expand Up @@ -48,8 +50,8 @@ const normalizeError = (error: Error | string) => {
* @param config
*/
export function devServer (devServerConfig: WebpackDevServerConfig): Promise<Cypress.ResolvedDevServerConfig> {
return new Promise((resolve, reject) => {
const result = devServer.create(devServerConfig) as DevServerCreateResult
return new Promise(async (resolve, reject) => {
const result = await devServer.create(devServerConfig) as DevServerCreateResult

// When compiling in run mode
// Stop the clock early, no need to run all the tests on a failed build
Expand Down Expand Up @@ -114,10 +116,10 @@ export function devServer (devServerConfig: WebpackDevServerConfig): Promise<Cyp
*
* @internal
*/
devServer.create = function (devServerConfig: WebpackDevServerConfig) {
devServer.create = async function (devServerConfig: WebpackDevServerConfig) {
const sourceWebpackModulesResult = sourceRelativeWebpackModules(devServerConfig)

let frameworkConfig: object | undefined
let frameworkConfig: Configuration | undefined

// If we have a framework specified, source the associated config
if (typeof devServerConfig.framework === 'string') {
Expand All @@ -128,6 +130,11 @@ devServer.create = function (devServerConfig: WebpackDevServerConfig) {
case 'react':
break
case 'nuxt':
frameworkConfig = await nuxtHandler({ devServerConfig, sourceWebpackModulesResult })
break

case 'vue-cli':
frameworkConfig = vueCliHandler({ devServerConfig, sourceWebpackModulesResult })
break
default:
throw new Error(`Unexpected framework ${devServerConfig.framework}, expected one of ${ALL_FRAMEWORKS.join(', ')}`)
Expand Down
26 changes: 26 additions & 0 deletions npm/webpack-dev-server-fresh/src/helpers/nuxtHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { CreateFinalWebpackConfig } from '../createWebpackDevServer'
import debugLib from 'debug'
import type { Configuration } from 'webpack'

type PresetHandler = Omit<CreateFinalWebpackConfig, 'frameworkConfig'>

const debug = debugLib('cypress:webpack-dev-server-fresh:nuxtHandler')

export async function nuxtHandler ({ devServerConfig }: PresetHandler): Promise<Configuration> {
try {
const nuxt = require.resolve('nuxt', {
paths: [devServerConfig.cypressConfig.projectRoot],
})

const { getWebpackConfig } = require(nuxt)

const webpackConfig = await getWebpackConfig()

debug('webpack config %o', webpackConfig)

return webpackConfig
} catch (e) {
console.error(e) // eslint-disable-line no-console
throw Error(`Error loading nuxt. Looked in ${require.resolve.paths(devServerConfig.cypressConfig.projectRoot)}`)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,20 @@ export function sourceRelativeWebpackModules (config: WebpackDevServerConfig) {
result.htmlWebpackPlugin.importPath = path.dirname(htmlWebpackPluginJsonPath)
result.htmlWebpackPlugin.packageJson = require(htmlWebpackPluginJsonPath)
result.htmlWebpackPlugin.module = require(result.htmlWebpackPlugin.importPath)
result.htmlWebpackPlugin.majorVersion = getMajorVersion(result.htmlWebpackPlugin.packageJson, [4, 5])
try {
result.htmlWebpackPlugin.majorVersion = getMajorVersion(result.htmlWebpackPlugin.packageJson, [4, 5])
} catch (e) {
// html-webpack-plugin@4 works fine with webpack 4, in place of html-webpack-plugin@3.
// This combination of dependencies is commonly found in Vue CLI 4.x.
// In fact, the version of html-webpack-plugin is pegged to the version webpack.
// Vue CLI is technically incorrect.
// In this case, just use 4.x, which we ship as part of the binary.
if (result.webpack.majorVersion === 4 && (e as Error).message.includes('3.2')) {
result.htmlWebpackPlugin.majorVersion = 4
} else {
throw e
}
}

return result
}
Expand Down
24 changes: 24 additions & 0 deletions npm/webpack-dev-server-fresh/src/helpers/vueCliHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { CreateFinalWebpackConfig } from '../createWebpackDevServer'
import debugLib from 'debug'
import type { Configuration } from 'webpack'

type PresetHandler = Omit<CreateFinalWebpackConfig, 'frameworkConfig'>

const debug = debugLib('cypress:webpack-dev-server-fresh:vueCliHandler')

export function vueCliHandler ({ devServerConfig }: PresetHandler): Configuration {
try {
const config = require.resolve('@vue/cli-service/webpack.config', {
paths: [devServerConfig.cypressConfig.projectRoot],
})

const webpackConfig = require(config)

debug('webpack config %o', webpackConfig)

return webpackConfig
} catch (e) {
console.error(e) // eslint-disable-line no-console
throw Error(`Error loading @vue/cli-service/webpack.config.js. Looked in ${require.resolve.paths(devServerConfig.cypressConfig.projectRoot)}`)
}
}
58 changes: 34 additions & 24 deletions npm/webpack-dev-server-fresh/src/makeWebpackConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,35 @@ const posixSeparator = '/'

const CYPRESS_WEBPACK_ENTRYPOINT = path.resolve(__dirname, 'browser.js')

/**
* Removes and/or modifies certain plugins known to conflict
* when used with cypress/webpack-dev-server.
*/
function modifyWebpackConfigForCypress (webpackConfig: Partial<Configuration>) {
if (webpackConfig?.plugins) {
webpackConfig.plugins = webpackConfig.plugins.filter((plugin) => {
if (removeList.includes(plugin.constructor.name)) {
/* eslint-disable no-console */
console.warn(`[@cypress/webpack-dev-server]: removing ${plugin.constructor.name} from configuration.`)

return false
}

return true
})
}

if (typeof webpackConfig?.module?.unsafeCache === 'function') {
const originalCachePredicate = webpackConfig.module.unsafeCache

webpackConfig.module.unsafeCache = (module: any) => {
return originalCachePredicate(module) && !/[\\/]webpack-dev-server[\\/]dist[\\/]browser\.js/.test(module.resource)
}
}

return webpackConfig
}

/**
* Creates a webpack 4/5 compatible webpack "configuration"
* to pass to the sourced webpack function
Expand All @@ -51,6 +80,9 @@ export function makeWebpackConfig (
const { module: webpack } = config.sourceWebpackModulesResult.webpack
const userWebpackConfig = config.devServerConfig.webpackConfig as Partial<Configuration>
const frameworkWebpackConfig = config.frameworkConfig as Partial<Configuration>
const userAndFrameworkWebpackConfig = modifyWebpackConfigForCypress(
merge(frameworkWebpackConfig ?? {}, userWebpackConfig ?? {}),
)

const {
cypressConfig: {
Expand All @@ -62,7 +94,7 @@ export function makeWebpackConfig (
devServerEvents,
} = config.devServerConfig

debug(`User passed in webpack config with values %o`, userWebpackConfig)
debug(`User passed in user and framework webpack config with values %o`, userAndFrameworkWebpackConfig)
debug(`New webpack entries %o`, files)
debug(`Project root`, projectRoot)
debug(`Support file`, supportFile)
Expand All @@ -89,30 +121,8 @@ export function makeWebpackConfig (
],
}

if (userWebpackConfig?.plugins) {
userWebpackConfig.plugins = userWebpackConfig.plugins.filter((plugin) => {
if (removeList.includes(plugin.constructor.name)) {
/* eslint-disable no-console */
console.warn(`[@cypress/webpack-dev-server]: removing ${plugin.constructor.name} from configuration.`)

return false
}

return true
})
}

if (typeof userWebpackConfig?.module?.unsafeCache === 'function') {
const originalCachePredicate = userWebpackConfig.module.unsafeCache

userWebpackConfig.module.unsafeCache = (module: any) => {
return originalCachePredicate(module) && !/[\\/]webpack-dev-server[\\/]dist[\\/]browser\.js/.test(module.resource)
}
}

const mergedConfig = merge(
userWebpackConfig ?? {},
frameworkWebpackConfig ?? {},
userAndFrameworkWebpackConfig,
makeDefaultWebpackConfig(config),
dynamicWebpackConfig,
)
Expand Down

3 comments on commit 57659c4

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 57659c4 Apr 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.0.0/linux-x64/10.0-release-57659c42468591265143aae2ff06bae4e440085f/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 57659c4 Apr 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the win32 x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.0.0/win32-x64/10.0-release-57659c42468591265143aae2ff06bae4e440085f/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 57659c4 Apr 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.0.0/darwin-x64/10.0-release-57659c42468591265143aae2ff06bae4e440085f/cypress.tgz

Please sign in to comment.