Skip to content
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

fix(testing): e2e-ci should use serve-static or vite preview for playwright and cypress #27240

Merged
merged 19 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
48210eb
fix(vite): preview should dependOn build
Coly010 Jul 31, 2024
3a5041e
fix(react): playwright should use vite preview
Coly010 Jul 31, 2024
62b9d9f
fix(vue): playwright should use vite preview
Coly010 Jul 31, 2024
cc9c2ad
fix(web): playwright should use vite preview
Coly010 Jul 31, 2024
4e0a785
chore(testing): add e2e test
Coly010 Jul 31, 2024
d538764
fix(web): static-serve configuration should add dependsOn
Coly010 Aug 1, 2024
735bdc3
feat(testing): add ciBaseUrl for configuring a different url for ciWe…
Coly010 Aug 1, 2024
453ae0e
fix(testing): cypress should use preview and serve static with correc…
Coly010 Aug 1, 2024
4e00ea9
fix(webpack): inferred serve-static target should dependOn buildTarget
Coly010 Aug 1, 2024
bc79053
fix(vite): add migration to add dependsOn for preview
Coly010 Aug 1, 2024
25a07c9
fix(testing): add migration for cypress should use preview for vite a…
Coly010 Aug 1, 2024
60637a2
fix(testing): add migration for playwright to use serve-static or pre…
Coly010 Aug 1, 2024
80fb3ce
fix(react-native): call addE2eReact correctly
Coly010 Aug 1, 2024
1a072b9
fix(web): remove circular-dep
Coly010 Aug 1, 2024
512b14e
fix(web): fix webservercommand
Coly010 Aug 1, 2024
bd7efe0
chore(repo): update snapshot
Coly010 Aug 1, 2024
5fcfd75
fix(web): remove cypress conditional for normalise option
Coly010 Aug 1, 2024
3d66565
chore(testing): point migrations to 19.6 release
Coly010 Aug 2, 2024
0962161
fix(web): generate serve-static targets
Coly010 Aug 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion e2e/react/src/playwright.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('React Playwright e2e tests', () => {
packages: ['@nx/react'],
});
runCLI(
`generate @nx/react:app ${appName} --e2eTestRunner=playwright --projectNameAndRootFormat=as-provided --no-interactive`
`generate @nx/react:app ${appName} --e2eTestRunner=playwright --bundler=vite --projectNameAndRootFormat=as-provided --no-interactive`
);
});

Expand Down
8 changes: 8 additions & 0 deletions e2e/webpack/src/__snapshots__/webpack.legacy.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,14 @@ exports[`Webpack Plugin (legacy) ConvertConfigToWebpackPlugin, should convert wi
"lint": {
"executor": "@nx/eslint:lint"
},
"serve-static": {
"executor": "@nx/web:file-server",
"dependsOn": ["build"],
"options": {
"buildTarget": "app3224373:build",
"spa": true
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
Expand Down
6 changes: 3 additions & 3 deletions e2e/webpack/src/webpack.legacy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,17 @@ describe('Webpack Plugin (legacy)', () => {
updateFile(
`${appName}/src/main.ts`,
`
document.querySelector('proj-root').innerHTML = '<h1>Welcome</h1>';
document.querySelector('proj-root')!.innerHTML = '<h1>Welcome</h1>';
Coly010 marked this conversation as resolved.
Show resolved Hide resolved
`
);
updateFile(
`${appName}/webpack.config.js`,
`
const { join } = require('path');
const {NxWebpackPlugin} = require('@nx/webpack');
const {NxAppWebpackPlugin} = require('@nx/webpack/app-plugin');
module.exports = {
output: {
path: join(__dirname, '../dist/app9524918'),
Coly010 marked this conversation as resolved.
Show resolved Hide resolved
path: join(__dirname, '../dist/${appName}'),
},
plugins: [
new NxAppWebpackPlugin({
Expand Down
6 changes: 6 additions & 0 deletions packages/cypress/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
"version": "18.1.0-beta.3",
"description": "Update to Cypress ^13.6.6 if the workspace is using Cypress v13 to ensure workspaces don't use v13.6.5 which has an issue when verifying Cypress.",
"implementation": "./src/migrations/update-18-1-0/update-cypress-version-13-6-6"
},
"update-19-6-0-update-ci-webserver-for-vite": {
"cli": "nx",
"version": "19.6.0-beta.0",
"description": "Update ciWebServerCommand to use previewTargetName if Vite is detected for the application.",
"implementation": "./src/migrations/update-19-6-0/update-ci-webserver-for-vite"
}
},
"packageJsonUpdates": {
Expand Down
6 changes: 6 additions & 0 deletions packages/cypress/plugins/cypress-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export function nxE2EPreset(
webServerCommand: options?.webServerCommands?.default,
webServerCommands: options?.webServerCommands,
ciWebServerCommand: options?.ciWebServerCommand,
ciBaseUrl: options?.ciBaseUrl,
},

async setupNodeEvents(on, config) {
Expand Down Expand Up @@ -268,6 +269,11 @@ export type NxCypressE2EPresetOptions = {
*/
ciWebServerCommand?: string;

/**
* The url of the web server for ciWebServerCommand
*/
ciBaseUrl?: string;

/**
* Configures how the web server command is started and monitored.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface CypressE2EConfigSchema {

webServerCommands?: Record<string, string>;
ciWebServerCommand?: string;
ciBaseUrl?: string;
addPlugin?: boolean;
}

Expand Down Expand Up @@ -218,10 +219,12 @@ async function addFiles(
let webServerCommands: Record<string, string>;

let ciWebServerCommand: string;
let ciBaseUrl: string;

if (hasPlugin && options.webServerCommands && options.ciWebServerCommand) {
webServerCommands = options.webServerCommands;
ciWebServerCommand = options.ciWebServerCommand;
ciBaseUrl = options.ciBaseUrl;
} else if (hasPlugin && options.devServerTarget) {
webServerCommands = {};

Expand Down Expand Up @@ -253,6 +256,7 @@ async function addFiles(
bundler: options.bundler === 'vite' ? 'vite' : undefined,
webServerCommands,
ciWebServerCommand: ciWebServerCommand,
ciBaseUrl,
},
options.baseUrl
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
import updateCiWebserverForVite from './update-ci-webserver-for-vite';
import {
type Tree,
type ProjectGraph,
readNxJson,
updateNxJson,
} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';

let projectGraph: ProjectGraph;
jest.mock('@nx/devkit', () => ({
...jest.requireActual<any>('@nx/devkit'),
createProjectGraphAsync: jest.fn().mockImplementation(async () => {
return projectGraph;
}),
}));

describe('updateCiWebserverForVite', () => {
let tree: Tree;
let tempFs: TempFs;

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
tempFs = new TempFs('add-e2e-ci');
tree.root = tempFs.tempDir;
projectGraph = {
nodes: {},
dependencies: {},
externalNodes: {},
};
});

afterEach(() => {
tempFs.reset();
});

it('should do nothing if vite is not found for application', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins = [
{
plugin: '@nx/cypress/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'e2e-ci',
},
},
];
updateNxJson(tree, nxJson);

addProject(tree, tempFs, {
buildTargetName: 'build',
ciTargetName: 'e2e-ci',
appName: 'app',
noVite: true,
});

// ACT
await updateCiWebserverForVite(tree);

// ASSERT
expect(tree.read('app-e2e/cypress.config.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
...nxE2EPreset(__filename, {
cypressDir: 'src',
bundler: 'vite',
webServerCommands: {
default: 'nx run app:serve',
production: 'nx run app:preview',
},
ciWebServerCommand: 'nx run app:serve-static',
}),
baseUrl: 'http://localhost:4200',
},
});
"
`);
});

it('should update ciWebServerCommand to preview for vite app', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins = [
{
plugin: '@nx/cypress/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'e2e-ci',
},
},
{
plugin: '@nx/vite/plugin',
options: {
buildTargetName: 'build',
previewTargetName: 'preview',
},
},
];
updateNxJson(tree, nxJson);

addProject(tree, tempFs);

// ACT
await updateCiWebserverForVite(tree);

// ASSERT
expect(tree.read('app-e2e/cypress.config.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
...nxE2EPreset(__filename, {
cypressDir: 'src',
bundler: 'vite',
webServerCommands: {
default: 'nx run app:serve',
production: 'nx run app:preview',
},
ciWebServerCommand: 'nx run app:preview',
ciBaseUrl: 'http://localhost:4300',
}),
baseUrl: 'http://localhost:4200',
},
});
"
`);
});
});

function addProject(
tree: Tree,
tempFs: TempFs,
overrides: {
ciTargetName: string;
buildTargetName: string;
appName: string;
noCi?: boolean;
noVite?: boolean;
} = { ciTargetName: 'e2e-ci', buildTargetName: 'build', appName: 'app' }
) {
const appProjectConfig = {
name: overrides.appName,
root: overrides.appName,
sourceRoot: `${overrides.appName}/src`,
projectType: 'application',
};
const viteConfig = `/// <reference types='vitest' />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
export default defineConfig({
root: __dirname,
cacheDir: '../../node_modules/.vite/${overrides.appName}',
server: {
port: 4200,
host: 'localhost',
},
preview: {
port: 4300,
host: 'localhost',
},
plugins: [react(), nxViteTsPaths()],
// Uncomment this if you are using workers.
// worker: {
// plugins: [ nxViteTsPaths() ],
// },
build: {
outDir: '../../dist/${overrides.appName}',
emptyOutDir: true,
reportCompressedSize: true,
commonjsOptions: {
transformMixedEsModules: true,
},
},
});`;

const e2eProjectConfig = {
name: `${overrides.appName}-e2e`,
root: `${overrides.appName}-e2e`,
sourceRoot: `${overrides.appName}-e2e/src`,
projectType: 'application',
};

const cypressConfig = `import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
...nxE2EPreset(__filename, {
cypressDir: 'src',
bundler: 'vite',
webServerCommands: {
default: 'nx run ${overrides.appName}:serve',
production: 'nx run ${overrides.appName}:preview',
},
${
!overrides.noCi
? `ciWebServerCommand: 'nx run ${overrides.appName}:serve-static',`
: ''
}
}),
baseUrl: 'http://localhost:4200',
},
});
`;

if (!overrides.noVite) {
tree.write(`${overrides.appName}/vite.config.ts`, viteConfig);
}
tree.write(
`${overrides.appName}/project.json`,
JSON.stringify(appProjectConfig)
);
tree.write(`${overrides.appName}-e2e/cypress.config.ts`, cypressConfig);
tree.write(
`${overrides.appName}-e2e/project.json`,
JSON.stringify(e2eProjectConfig)
);
if (!overrides.noVite) {
tempFs.createFile(`${overrides.appName}/vite.config.ts`, viteConfig);
}
tempFs.createFilesSync({
[`${overrides.appName}/project.json`]: JSON.stringify(appProjectConfig),
[`${overrides.appName}-e2e/cypress.config.ts`]: cypressConfig,
[`${overrides.appName}-e2e/project.json`]: JSON.stringify(e2eProjectConfig),
});

projectGraph.nodes[overrides.appName] = {
name: overrides.appName,
type: 'app',
data: {
projectType: 'application',
root: overrides.appName,
targets: {
[overrides.buildTargetName]: {},
'serve-static': {
options: {
buildTarget: overrides.buildTargetName,
},
},
},
},
};

projectGraph.nodes[`${overrides.appName}-e2e`] = {
name: `${overrides.appName}-e2e`,
type: 'app',
data: {
projectType: 'application',
root: `${overrides.appName}-e2e`,
targets: {
e2e: {},
[overrides.ciTargetName]: {},
},
},
};
}
Loading