feat(testing): support cypress v13 (#18899)
This commit is contained in:
parent
83ebf0f799
commit
193206ac86
@ -145,6 +145,10 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "If passed, Cypress output will not be printed to stdout. Only output from the configured Mocha reporter will print.",
|
"description": "If passed, Cypress output will not be printed to stdout. Only output from the configured Mocha reporter will print.",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"runnerUi": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Displays the Cypress Runner UI. Useful for when Test Replay is enabled and you would still like the Cypress Runner UI to be displayed for screenshots and video."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
|
|||||||
@ -59,6 +59,12 @@
|
|||||||
"version": "16.4.0-beta.10",
|
"version": "16.4.0-beta.10",
|
||||||
"description": "Remove tsconfig.e2e.json and add settings to project tsconfig.json. tsConfigs executor option is now deprecated. The project level tsconfig.json file should be used instead.",
|
"description": "Remove tsconfig.e2e.json and add settings to project tsconfig.json. tsConfigs executor option is now deprecated. The project level tsconfig.json file should be used instead.",
|
||||||
"implementation": "./src/migrations/update-16-4-0/tsconfig-sourcemaps"
|
"implementation": "./src/migrations/update-16-4-0/tsconfig-sourcemaps"
|
||||||
|
},
|
||||||
|
"update-16-8-0-cypress-13": {
|
||||||
|
"cli": "nx",
|
||||||
|
"version": "16.8.0-beta.4",
|
||||||
|
"description": "Update to Cypress v13. Most noteable change is video recording is off by default. This migration will only update if the workspace is already on Cypress v12. https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-130",
|
||||||
|
"implementation": "./src/migrations/update-16-8-0/cypress-13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packageJsonUpdates": {
|
"packageJsonUpdates": {
|
||||||
|
|||||||
@ -43,7 +43,7 @@
|
|||||||
"@nx/linter": "file:../linter"
|
"@nx/linter": "file:../linter"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"cypress": ">= 3 < 13"
|
"cypress": ">= 3 < 14"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"cypress": {
|
"cypress": {
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import vitePreprocessor from '../src/plugins/preprocessor-vite';
|
|||||||
interface BaseCypressPreset {
|
interface BaseCypressPreset {
|
||||||
videosFolder: string;
|
videosFolder: string;
|
||||||
screenshotsFolder: string;
|
screenshotsFolder: string;
|
||||||
video: boolean;
|
|
||||||
chromeWebSecurity: boolean;
|
chromeWebSecurity: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +46,6 @@ export function nxBaseCypressPreset(
|
|||||||
return {
|
return {
|
||||||
videosFolder,
|
videosFolder,
|
||||||
screenshotsFolder,
|
screenshotsFolder,
|
||||||
video: true,
|
|
||||||
chromeWebSecurity: false,
|
chromeWebSecurity: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,7 @@ export interface CypressExecutorOptions extends Json {
|
|||||||
tag?: string;
|
tag?: string;
|
||||||
port?: number | 'cypress-auto';
|
port?: number | 'cypress-auto';
|
||||||
quiet?: boolean;
|
quiet?: boolean;
|
||||||
|
runnerUi?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NormalizedCypressExecutorOptions extends CypressExecutorOptions {
|
interface NormalizedCypressExecutorOptions extends CypressExecutorOptions {
|
||||||
@ -258,6 +259,7 @@ async function runCypress(
|
|||||||
options.tag = opts.tag;
|
options.tag = opts.tag;
|
||||||
options.exit = opts.exit;
|
options.exit = opts.exit;
|
||||||
options.headed = opts.headed;
|
options.headed = opts.headed;
|
||||||
|
options.runnerUi = opts.runnerUi;
|
||||||
|
|
||||||
if (opts.headless) {
|
if (opts.headless) {
|
||||||
options.headless = opts.headless;
|
options.headless = opts.headless;
|
||||||
|
|||||||
@ -164,6 +164,10 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "If passed, Cypress output will not be printed to stdout. Only output from the configured Mocha reporter will print.",
|
"description": "If passed, Cypress output will not be printed to stdout. Only output from the configured Mocha reporter will print.",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"runnerUi": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Displays the Cypress Runner UI. Useful for when Test Replay is enabled and you would still like the Cypress Runner UI to be displayed for screenshots and video."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
|
|||||||
243
packages/cypress/src/migrations/update-16-8-0/cypress-13.spec.ts
Normal file
243
packages/cypress/src/migrations/update-16-8-0/cypress-13.spec.ts
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
import { Tree, addProjectConfiguration, readJson } from '@nx/devkit';
|
||||||
|
import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
|
||||||
|
import { updateToCypress13 } from './cypress-13';
|
||||||
|
|
||||||
|
describe('Cypress 13', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update deps to cypress v13', async () => {
|
||||||
|
setup(tree, { name: 'my-app' });
|
||||||
|
|
||||||
|
await updateToCypress13(tree);
|
||||||
|
expect(readJson(tree, 'package.json').devDependencies.cypress).toEqual(
|
||||||
|
'^13.0.0'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update videoUploadOnPasses from config w/setupNodeEvents', async () => {
|
||||||
|
setup(tree, { name: 'my-app-video-upload-on-passes' });
|
||||||
|
await updateToCypress13(tree);
|
||||||
|
expect(
|
||||||
|
tree.read('apps/my-app-video-upload-on-passes/cypress.config.ts', 'utf-8')
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
"import fs from 'fs';
|
||||||
|
|
||||||
|
import { defineConfig } from 'cypress';
|
||||||
|
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
||||||
|
import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
something: 'blah',
|
||||||
|
// nodeVersion: 'system',
|
||||||
|
// videoUploadOnPasses: false ,
|
||||||
|
e2e: {
|
||||||
|
...nxE2EPreset(__filename),
|
||||||
|
setupNodeEvents(on, config) {
|
||||||
|
const a = '';
|
||||||
|
removePassedSpecs(on);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
component: {
|
||||||
|
...nxComponentTestingPreset(__filename),
|
||||||
|
setupNodeEvents: (on, config) => {
|
||||||
|
const b = '';
|
||||||
|
removePassedSpecs(on);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete videos for specs that do not contain failing or retried tests.
|
||||||
|
* This function is to be used in the 'setupNodeEvents' configuration option as a replacement to
|
||||||
|
* 'videoUploadOnPasses' which has been removed.
|
||||||
|
*
|
||||||
|
* https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests
|
||||||
|
**/
|
||||||
|
function removePassedSpecs(on) {
|
||||||
|
on('after:spec', (spec, results) => {
|
||||||
|
if (results && results.vide) {
|
||||||
|
const hasFailures = results.tests.some((t) =>
|
||||||
|
t.attempts.some((a) => a.state === 'failed')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hasFailures) {
|
||||||
|
fs.unlinkSync(results.video);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
it('should remove nodeVersion from config', async () => {
|
||||||
|
setup(tree, { name: 'my-app-node-version' });
|
||||||
|
await updateToCypress13(tree);
|
||||||
|
expect(tree.read('apps/my-app-node-version/cypress.config.ts', 'utf-8'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
"import fs from 'fs';
|
||||||
|
|
||||||
|
import { defineConfig } from 'cypress';
|
||||||
|
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
||||||
|
import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
something: 'blah',
|
||||||
|
// nodeVersion: 'system',
|
||||||
|
// videoUploadOnPasses: false ,
|
||||||
|
e2e: {
|
||||||
|
...nxE2EPreset(__filename),
|
||||||
|
setupNodeEvents(on, config) {
|
||||||
|
const a = '';
|
||||||
|
removePassedSpecs(on);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
component: {
|
||||||
|
...nxComponentTestingPreset(__filename),
|
||||||
|
setupNodeEvents: (on, config) => {
|
||||||
|
const b = '';
|
||||||
|
removePassedSpecs(on);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete videos for specs that do not contain failing or retried tests.
|
||||||
|
* This function is to be used in the 'setupNodeEvents' configuration option as a replacement to
|
||||||
|
* 'videoUploadOnPasses' which has been removed.
|
||||||
|
*
|
||||||
|
* https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests
|
||||||
|
**/
|
||||||
|
function removePassedSpecs(on) {
|
||||||
|
on('after:spec', (spec, results) => {
|
||||||
|
if (results && results.vide) {
|
||||||
|
const hasFailures = results.tests.some((t) =>
|
||||||
|
t.attempts.some((a) => a.state === 'failed')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hasFailures) {
|
||||||
|
fs.unlinkSync(results.video);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should comment about overriding readFile command', async () => {
|
||||||
|
setup(tree, { name: 'my-app-read-file' });
|
||||||
|
const testContent = `describe('something', () => {
|
||||||
|
it('should do the thing', () => {
|
||||||
|
cy.readFile('my-data.json').its('name').should('eq', 'Nx');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`;
|
||||||
|
tree.write('apps/my-app-read-file/src/something.cy.ts', testContent);
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
'apps/my-app-read-file/cypress/support/commands.ts',
|
||||||
|
`declare namespace Cypress {
|
||||||
|
interface Chainable<Subject> {
|
||||||
|
login(email: string, password: string): void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// -- This is a parent command --
|
||||||
|
Cypress.Commands.add('login', (email, password) => {
|
||||||
|
console.log('Custom command example: Login', email, password);
|
||||||
|
});
|
||||||
|
Cypress.Commands.overwrite('readFile', () => {});
|
||||||
|
|
||||||
|
`
|
||||||
|
);
|
||||||
|
await updateToCypress13(tree);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tree.read('apps/my-app-read-file/src/something.cy.ts', 'utf-8')
|
||||||
|
).toEqual(testContent);
|
||||||
|
expect(
|
||||||
|
tree.read('apps/my-app-read-file/cypress/support/commands.ts', 'utf-8')
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
"declare namespace Cypress {
|
||||||
|
interface Chainable<Subject> {
|
||||||
|
login(email: string, password: string): void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// -- This is a parent command --
|
||||||
|
Cypress.Commands.add('login', (email, password) => {
|
||||||
|
console.log('Custom command example: Login', email, password);
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* TODO(@nx/cypress): This command can no longer be overridden
|
||||||
|
* Consider using a different name like 'custom_readFile'
|
||||||
|
* More info: https://docs.cypress.io/guides/references/migration-guide#readFile-can-no-longer-be-overwritten-with-CypressCommandsoverwrite
|
||||||
|
**/
|
||||||
|
Cypress.Commands.overwrite('readFile', () => {});
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function setup(tree: Tree, options: { name: string }) {
|
||||||
|
tree.write(
|
||||||
|
`apps/${options.name}/cypress.config.ts`,
|
||||||
|
`
|
||||||
|
import { defineConfig} from 'cypress';
|
||||||
|
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
||||||
|
import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
something: 'blah',
|
||||||
|
nodeVersion: 'system',
|
||||||
|
videoUploadOnPasses: false,
|
||||||
|
e2e: {
|
||||||
|
...nxE2EPreset(__filename),
|
||||||
|
videoUploadOnPasses: false,
|
||||||
|
nodeVersion: 'bundled',
|
||||||
|
setupNodeEvents(on, config) {
|
||||||
|
const a = '';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
component: {
|
||||||
|
...nxComponentTestingPreset(__filename),
|
||||||
|
videoUploadOnPasses: false,
|
||||||
|
nodeVersion: 'something',
|
||||||
|
setupNodeEvents: (on, config) => {
|
||||||
|
const b = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
`
|
||||||
|
);
|
||||||
|
tree.write(
|
||||||
|
'package.json',
|
||||||
|
JSON.stringify({ devDependencies: { cypress: '^12.16.0' } })
|
||||||
|
);
|
||||||
|
addProjectConfiguration(tree, options.name, {
|
||||||
|
root: `apps/${options.name}`,
|
||||||
|
sourceRoot: `apps/${options.name}/src`,
|
||||||
|
targets: {
|
||||||
|
e2e: {
|
||||||
|
executor: '@nx/cypress:cypress',
|
||||||
|
options: {
|
||||||
|
testingType: 'e2e',
|
||||||
|
cypressConfig: `apps/${options.name}/cypress.config.ts`,
|
||||||
|
devServerTarget: 'app:serve',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'component-test': {
|
||||||
|
executor: '@nx/cypress:cypress',
|
||||||
|
options: {
|
||||||
|
testingType: 'component',
|
||||||
|
cypressConfig: `apps/${options.name}/ct-cypress.config.ts`,
|
||||||
|
skipServe: true,
|
||||||
|
devServerTarget: 'app:build',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
246
packages/cypress/src/migrations/update-16-8-0/cypress-13.ts
Normal file
246
packages/cypress/src/migrations/update-16-8-0/cypress-13.ts
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
import {
|
||||||
|
updateJson,
|
||||||
|
installPackagesTask,
|
||||||
|
getProjects,
|
||||||
|
visitNotIgnoredFiles,
|
||||||
|
formatFiles,
|
||||||
|
type Tree,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import { installedCypressVersion } from '../../utils/cypress-version';
|
||||||
|
import {
|
||||||
|
isObjectLiteralExpression,
|
||||||
|
isCallExpression,
|
||||||
|
type CallExpression,
|
||||||
|
type MethodDeclaration,
|
||||||
|
type PropertyAccessExpression,
|
||||||
|
type PropertyAssignment,
|
||||||
|
} from 'typescript';
|
||||||
|
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||||
|
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
|
||||||
|
import type { CypressExecutorOptions } from '../../executors/cypress/cypress.impl';
|
||||||
|
|
||||||
|
const JS_TS_FILE_MATCHER = /\.[jt]sx?$/;
|
||||||
|
|
||||||
|
export async function updateToCypress13(tree: Tree) {
|
||||||
|
if (installedCypressVersion() < 12) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const projects = getProjects(tree);
|
||||||
|
|
||||||
|
forEachExecutorOptions<CypressExecutorOptions>(
|
||||||
|
tree,
|
||||||
|
'@nx/cypress:cypress',
|
||||||
|
(options, projectName) => {
|
||||||
|
if (!options.cypressConfig || !tree.exists(options.cypressConfig)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const projectConfig = projects.get(projectName);
|
||||||
|
|
||||||
|
removeNodeVersionOption(tree, options.cypressConfig);
|
||||||
|
removeVideoUploadOnPassesOption(tree, options.cypressConfig);
|
||||||
|
|
||||||
|
visitNotIgnoredFiles(tree, projectConfig.root, (filePath) => {
|
||||||
|
if (!JS_TS_FILE_MATCHER.test(filePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
shouldNotOverrideReadFile(tree, filePath);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.devDependencies ??= {};
|
||||||
|
json.devDependencies.cypress = '^13.0.0';
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await formatFiles(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeVideoUploadOnPassesOption(tree: Tree, configPath: string) {
|
||||||
|
const config = tree.read(configPath, 'utf-8');
|
||||||
|
const isUsingDeprecatedOption =
|
||||||
|
tsquery.query(config, getPropertyQuery('videoUploadOnPasses'))?.length > 0;
|
||||||
|
|
||||||
|
if (!isUsingDeprecatedOption) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const importStatement = configPath.endsWith('.ts')
|
||||||
|
? "import fs from 'fs';"
|
||||||
|
: "const fs = require('fs');";
|
||||||
|
|
||||||
|
const replacementFunction = `/**
|
||||||
|
* Delete videos for specs that do not contain failing or retried tests.
|
||||||
|
* This function is to be used in the 'setupNodeEvents' configuration option as a replacement to
|
||||||
|
* 'videoUploadOnPasses' which has been removed.
|
||||||
|
*
|
||||||
|
* https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests
|
||||||
|
**/
|
||||||
|
function removePassedSpecs(on) {
|
||||||
|
on('after:spec', (spec, results) => {
|
||||||
|
if(results && results.vide) {
|
||||||
|
const hasFailures = results.tests.some(t => t.attempts.some(a => a.state === 'failed'));
|
||||||
|
|
||||||
|
if(!hasFailures) {
|
||||||
|
fs.unlinkSync(results.video);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}`;
|
||||||
|
|
||||||
|
const withReplacementFn = `${importStatement}\n${config}\n${replacementFunction}`;
|
||||||
|
|
||||||
|
// setupNodeEvents can be a property or method.
|
||||||
|
const setupNodeEventsQuery =
|
||||||
|
'ExportAssignment ObjectLiteralExpression > :matches(PropertyAssignment:has(Identifier[name="setupNodeEvents"]), MethodDeclaration:has(Identifier[name="setupNodeEvents"]))';
|
||||||
|
|
||||||
|
const hasSetupNodeEvents =
|
||||||
|
tsquery.query(withReplacementFn, setupNodeEventsQuery)?.length > 0;
|
||||||
|
|
||||||
|
let updatedWithSetupNodeEvents = withReplacementFn;
|
||||||
|
if (hasSetupNodeEvents) {
|
||||||
|
// if have setupNodeEvents, update existing fn to use removePassedSpecs helper and remove videoUploadOnPasses
|
||||||
|
const noVideoUploadOption = tsquery.replace(
|
||||||
|
withReplacementFn,
|
||||||
|
getPropertyQuery('videoUploadOnPasses'),
|
||||||
|
(node: PropertyAssignment) => {
|
||||||
|
if (isObjectLiteralExpression(node.initializer)) {
|
||||||
|
// is a nested config object
|
||||||
|
const key = node.name.getText().trim();
|
||||||
|
const listOfProperties = node.initializer.properties
|
||||||
|
.map((j) => j.getText())
|
||||||
|
.filter((j) => !j.includes('videoUploadOnPasses'))
|
||||||
|
.join(',\n');
|
||||||
|
|
||||||
|
return `${key}: {
|
||||||
|
${listOfProperties}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
if (isPropertyTopLevel(node)) {
|
||||||
|
return `// ${node.getText()} `;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
updatedWithSetupNodeEvents = tsquery.replace(
|
||||||
|
noVideoUploadOption,
|
||||||
|
`${setupNodeEventsQuery} Block`,
|
||||||
|
(node: PropertyAssignment | MethodDeclaration) => {
|
||||||
|
const blockWithoutBraces = node
|
||||||
|
.getFullText()
|
||||||
|
.trim()
|
||||||
|
.slice(1, -1)
|
||||||
|
.trim();
|
||||||
|
return `{
|
||||||
|
${blockWithoutBraces}
|
||||||
|
removePassedSpecs(on);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
{ visitAllChildren: false }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// if don't have setupNodeEvents, replace videoUploadOnPasses with setupNodeEvents method
|
||||||
|
updatedWithSetupNodeEvents = tsquery.replace(
|
||||||
|
withReplacementFn,
|
||||||
|
getPropertyQuery('videoUploadOnPasses'),
|
||||||
|
() => {
|
||||||
|
return `setupNodeEvents(on, config) {
|
||||||
|
removePassedSpecs(on);
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.write(configPath, updatedWithSetupNodeEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove the nodeVersion option from the config file
|
||||||
|
**/
|
||||||
|
function removeNodeVersionOption(tree: Tree, configPath: string) {
|
||||||
|
const config = tree.read(configPath, 'utf-8');
|
||||||
|
|
||||||
|
const updated = tsquery.replace(
|
||||||
|
config,
|
||||||
|
getPropertyQuery('nodeVersion'),
|
||||||
|
(node: PropertyAssignment) => {
|
||||||
|
if (isObjectLiteralExpression(node.initializer)) {
|
||||||
|
// is a nested config object
|
||||||
|
const key = node.name.getText().trim();
|
||||||
|
const listOfProperties = node.initializer.properties
|
||||||
|
.map((j) => j.getFullText())
|
||||||
|
.filter((j) => !j.includes('nodeVersion'))
|
||||||
|
.join(', ');
|
||||||
|
return `${key}: {
|
||||||
|
${listOfProperties}
|
||||||
|
}`;
|
||||||
|
} else {
|
||||||
|
if (isPropertyTopLevel(node)) {
|
||||||
|
return `// ${node.getText()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (updated !== config) {
|
||||||
|
tree.write(configPath, updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* leave a comment on all usages of overriding built-ins that are now banned
|
||||||
|
**/
|
||||||
|
export function shouldNotOverrideReadFile(tree: Tree, filePath: string) {
|
||||||
|
const content = tree.read(filePath, 'utf-8');
|
||||||
|
const markedOverrideUsage = tsquery.replace(
|
||||||
|
content,
|
||||||
|
'PropertyAccessExpression:has(Identifier[name="overwrite"]):has(Identifier[name="Cypress"])',
|
||||||
|
(node: PropertyAccessExpression) => {
|
||||||
|
if (isAlreadyCommented(node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const expression = node.expression.getText().trim();
|
||||||
|
// prevent grabbing other Cypress.<something>.defaults
|
||||||
|
|
||||||
|
if (expression === 'Cypress.Commands') {
|
||||||
|
// get value.
|
||||||
|
const overwriteExpression = node.parent as CallExpression;
|
||||||
|
|
||||||
|
const command = (overwriteExpression.arguments?.[0] as any)?.text; // need string without quotes
|
||||||
|
if (command === 'readFile') {
|
||||||
|
// overwrite
|
||||||
|
return `/**
|
||||||
|
* TODO(@nx/cypress): This command can no longer be overridden
|
||||||
|
* Consider using a different name like 'custom_${command}'
|
||||||
|
* More info: https://docs.cypress.io/guides/references/migration-guide#readFile-can-no-longer-be-overwritten-with-CypressCommandsoverwrite
|
||||||
|
**/
|
||||||
|
${node.getText()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
tree.write(filePath, markedOverrideUsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAlreadyCommented(node: PropertyAccessExpression) {
|
||||||
|
return node.getFullText().includes('TODO(@nx/cypress)');
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPropertyTopLevel(node: PropertyAssignment) {
|
||||||
|
return (
|
||||||
|
node.parent &&
|
||||||
|
isObjectLiteralExpression(node.parent) &&
|
||||||
|
node.parent.parent &&
|
||||||
|
isCallExpression(node.parent.parent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPropertyQuery = (propertyName: string) =>
|
||||||
|
`ExportAssignment ObjectLiteralExpression > PropertyAssignment:has(Identifier[name="${propertyName}"])`;
|
||||||
|
|
||||||
|
export default updateToCypress13;
|
||||||
@ -2,7 +2,7 @@ export const nxVersion = require('../../package.json').version;
|
|||||||
export const eslintPluginCypressVersion = '^2.13.4';
|
export const eslintPluginCypressVersion = '^2.13.4';
|
||||||
export const typesNodeVersion = '16.11.7';
|
export const typesNodeVersion = '16.11.7';
|
||||||
export const cypressViteDevServerVersion = '^2.2.1';
|
export const cypressViteDevServerVersion = '^2.2.1';
|
||||||
export const cypressVersion = '^12.16.0';
|
export const cypressVersion = '^13.0.0';
|
||||||
export const cypressWebpackVersion = '^2.0.0';
|
export const cypressWebpackVersion = '^2.0.0';
|
||||||
export const webpackHttpPluginVersion = '^5.5.0';
|
export const webpackHttpPluginVersion = '^5.5.0';
|
||||||
export const viteVersion = '~4.3.9';
|
export const viteVersion = '~4.3.9';
|
||||||
|
|||||||
@ -61,7 +61,6 @@ export function nxComponentTestingPreset(
|
|||||||
devServer: ViteDevServer | WebpackDevServer;
|
devServer: ViteDevServer | WebpackDevServer;
|
||||||
videosFolder: string;
|
videosFolder: string;
|
||||||
screenshotsFolder: string;
|
screenshotsFolder: string;
|
||||||
video: boolean;
|
|
||||||
chromeWebSecurity: boolean;
|
chromeWebSecurity: boolean;
|
||||||
} {
|
} {
|
||||||
const normalizedProjectRootPath = ['.ts', '.js'].some((ext) =>
|
const normalizedProjectRootPath = ['.ts', '.js'].some((ext) =>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user