-
Notifications
You must be signed in to change notification settings - Fork 3.4k
feat: add new webpack-dev-server package based on object API & bundling #20861
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
66dcf80
b115c4f
d512f68
24456d4
7187cf7
7f83ff8
35be22c
223b1ea
5377d71
7fd7a6a
ef3c223
17416d3
bfe2ad4
1f0ed9c
738588b
a4e6389
b82940d
ad77637
f707b34
afa8c5a
91d6dce
1c99864
08c7ea0
cca7a16
a63206e
0cf09cc
fe7a28d
01f9a06
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # @cypress/webpack-dev-server-fresh | ||
|
|
||
| Implements the APIs for the object-syntax of the Cypress Component-testing "webpack dev server". | ||
|
|
||
| Object syntax: | ||
|
|
||
| ```ts | ||
| import { defineConfig } from 'cypress' | ||
|
|
||
| export default defineConfig({ | ||
| component: { | ||
| devServer: { | ||
| framework: 'create-react-app', | ||
| bundler: 'webpack', | ||
| // webpackConfig?: Will try to infer, if passed it will be used as is | ||
| } | ||
| } | ||
| }) | ||
| ``` | ||
|
|
||
| Function syntax: | ||
|
|
||
| ```ts | ||
| import { devServer } from '@cypress/webpack-dev-server' | ||
| import { defineConfig } from 'cypress' | ||
|
|
||
| export default defineConfig({ | ||
| component: { | ||
| devServer(cypressConfig) { | ||
| return devServer({ | ||
| cypressConfig, | ||
| framework: 'react', | ||
| webpackConfig: require('./webpack.config.js') | ||
| }) | ||
| } | ||
| } | ||
| }) | ||
| ``` | ||
|
|
||
| ## Testing | ||
|
|
||
| Unit tests can be run with `npm test`. Integration tests can be run with `yarn cypress:run` | ||
|
|
||
| This module should be primarily covered by system-tests / open-mode tests. All system-tests directories should be created using the notation: | ||
|
|
||
| `webpack${major}_wds${devServerMajor}-$framework{-$variant}` | ||
|
|
||
| - webpack4_wds3-react | ||
| - webpack4_wds4-next-11 | ||
| - webpack5_wds3-next-12 | ||
| - webpack4_wds4-create-react-app | ||
|
|
||
| ## Architecture | ||
|
|
||
| There should be a single publicly-exported entrypoint for the module, `devServer`, all other types and functions should be considered internal/implementation details, and types stripped from the output. | ||
|
|
||
| The `devServer` will first source the modules from the user's project, falling back to our own bundled versions of libraries. This ensures that the user has installed the current modules, and throws an error if the user does not have the library installed. | ||
|
|
||
| From there, we check the "framework" field to source or define any known webpack transforms to aid in the compilation. | ||
|
|
||
| We then merge the sourced config with the user's webpack config, and layer on our own transforms, and provide this to a webpack instance. The webpack instance used to create a webpack-dev-server, which is returned. | ||
|
|
||
| ## Changelog | ||
|
|
||
| [Changelog](./CHANGELOG.md) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| exports['makeWebpackConfig ignores userland webpack `output.publicPath` 1'] = { | ||
| "output": { | ||
| "publicPath": "/test-public-path/", | ||
| "filename": "[name].js" | ||
| }, | ||
| "mode": "development", | ||
| "optimization": { | ||
| "splitChunks": { | ||
| "chunks": "all" | ||
| } | ||
| }, | ||
| "plugins": [ | ||
| "HtmlWebpackPlugin", | ||
| "CypressCTWebpackPlugin" | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import { defineConfig } from 'cypress' | ||
|
|
||
| export default defineConfig({ | ||
| projectId: 'ypt4pf', | ||
| e2e: { | ||
| defaultCommandTimeout: 10000, // these take a bit longer b/c they're e2e open mode test | ||
| async setupNodeEvents (on, config) { | ||
| if (!process.env.HTTP_PROXY_TARGET_FOR_ORIGIN_REQUESTS) { | ||
| throw new Error('HTTP_PROXY_TARGET_FOR_ORIGIN_REQUESTS is missing. Close Cypress and run tests using the `yarn cypress:*` commands from the `packages/app` directory') | ||
| } | ||
|
|
||
| // Delete this as we only want to honor it on parent Cypress when doing E2E Cypress in Cypress testing | ||
| delete process.env.HTTP_PROXY_TARGET_FOR_ORIGIN_REQUESTS | ||
| process.env.CYPRESS_INTERNAL_E2E_TESTING_SELF = 'true' | ||
| const { e2ePluginSetup } = require('@packages/frontend-shared/cypress/e2e/e2ePluginSetup') as typeof import('@packages/frontend-shared/cypress/e2e/e2ePluginSetup') | ||
|
|
||
| return await e2ePluginSetup(on, config) | ||
| }, | ||
| }, | ||
| // @ts-ignore We are setting these namespaces in order to properly test Cypress in Cypress | ||
| clientRoute: '/__app/', | ||
| namespace: '__cypress-app', | ||
| socketIoRoute: '/__app-socket', | ||
| socketIoCookie: '__app-socket', | ||
| devServerPublicPathRoute: '/__cypress-app/src', | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /// <reference types="cypress" /> | ||
| /// <reference path="../support/e2e.ts" /> | ||
| import type { e2eProjectDirs } from '@packages/frontend-shared/cypress/e2e/support/e2eProjectDirs' | ||
|
|
||
| type ProjectDirs = typeof e2eProjectDirs | ||
|
|
||
| const WEBPACK_REACT: ProjectDirs[number][] = ['webpack4_wds3-react', 'webpack4_wds4-react', 'webpack5_wds3-react', 'webpack5_wds4-react'] | ||
|
|
||
| // Add to this list to focus on a particular permutation | ||
| const ONLY_PROJECTS: ProjectDirs[number][] = [] | ||
|
|
||
| for (const project of WEBPACK_REACT) { | ||
| 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('App.cy.jsx').click() | ||
| cy.get('.passed > .num').should('contain', 1) | ||
| }) | ||
|
|
||
| it('MissingReact: should fail, rerun, succeed', () => { | ||
| cy.once('uncaught:exception', () => { | ||
| // Ignore the uncaught exception in the AUT | ||
| return false | ||
| }) | ||
|
|
||
| cy.visitApp() | ||
| cy.contains('MissingReact.cy.jsx').click() | ||
| cy.get('.failed > .num').should('contain', 1) | ||
| cy.withCtx(async (ctx) => { | ||
| await ctx.actions.file.writeFileInProject(`src/MissingReact.jsx`, | ||
| `import React from 'react'; | ||
| ${await ctx.actions.file.readFileInProject('src/MissingReact.jsx')}`) | ||
| }) | ||
|
Comment on lines
+39
to
+43
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tests in open mode that the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New infra 💯 I think this is a good one to demo next biweekly demo - if we don't show this stuff off and champion it, most people won't know. I think a lot of people are not using system-tests in the most productive way for this reason. |
||
|
|
||
| cy.get('.passed > .num').should('contain', 1) | ||
| }) | ||
|
|
||
| it('MissingReactInSpec: should fail, rerun, succeed', () => { | ||
| cy.visitApp() | ||
| cy.contains('MissingReactInSpec.cy.jsx').click() | ||
| cy.get('.failed > .num').should('contain', 1) | ||
| cy.withCtx(async (ctx) => { | ||
| await ctx.actions.file.writeFileInProject(`src/MissingReactInSpec.cy.jsx`, | ||
| await ctx.actions.file.readFileInProject('src/App.cy.jsx')) | ||
| }) | ||
|
Comment on lines
+50
to
+55
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tests in open mode that the |
||
|
|
||
| cy.get('.passed > .num').should('contain', 1) | ||
| }) | ||
| }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| /// <reference types="cypress" /> | ||
| // *********************************************** | ||
| // This example commands.ts shows you how to | ||
| // create various custom commands and overwrite | ||
| // existing commands. | ||
| // | ||
| // For more comprehensive examples of custom | ||
| // commands please read more here: | ||
| // https://on.cypress.io/custom-commands | ||
| // *********************************************** | ||
| // | ||
| // | ||
| // -- This is a parent command -- | ||
| // Cypress.Commands.add('login', (email, password) => { ... }) | ||
| // | ||
| // | ||
| // -- This is a child command -- | ||
| // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) | ||
| // | ||
| // | ||
| // -- This is a dual command -- | ||
| // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) | ||
| // | ||
| // | ||
| // -- This will overwrite an existing command -- | ||
| // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) | ||
| // | ||
| // declare global { | ||
| // namespace Cypress { | ||
| // interface Chainable { | ||
| // login(email: string, password: string): Chainable<void> | ||
| // drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element> | ||
| // dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element> | ||
| // visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element> | ||
| // } | ||
| // } | ||
| // } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| // *********************************************************** | ||
| // This example support/e2e.ts is processed and | ||
| // loaded automatically before your test files. | ||
| // | ||
| // This is a great place to put global configuration and | ||
| // behavior that modifies Cypress. | ||
| // | ||
| // You can change the location of this file or turn off | ||
| // automatically serving support files with the | ||
| // 'supportFile' configuration option. | ||
| // | ||
| // You can read more here: | ||
| // https://on.cypress.io/configuration | ||
| // *********************************************************** | ||
|
|
||
| // Import commands.js using ES2015 syntax: | ||
| import '@packages/frontend-shared/cypress/e2e/support/e2eSupport' | ||
|
|
||
| // Alternatively you can use CommonJS syntax: | ||
| // require('./commands') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit... seems inconsistent w.r.t.
_and-.We could do packages separated w/
_? Egwebpack4_wds_create-react-app5.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I had this to distinguish between the webpack variants & frameworks. Don't mind if we do trailing
_