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): handle more complex projects for react component testing #11725

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion docs/generated/packages/react.json
Original file line number Diff line number Diff line change
Expand Up @@ -1207,7 +1207,7 @@
"name": "cypress-component-configuration",
"factory": "./src/generators/cypress-component-configuration/cypress-component-configuration#cypressComponentConfigGenerator",
"schema": {
"$schema": "http://json-schema.org/schema",
"$schema": "https://json-schema.org/schema",
"cli": "nx",
"$id": "NxReactCypressComponentTestConfiguration",
"title": "Add Cypress component testing",
Expand All @@ -1230,6 +1230,11 @@
"$default": { "$source": "projectName" },
"x-prompt": "What project should we add Cypress component testing to?"
},
"buildTarget": {
"type": "string",
"description": "A build target used to configure Cypress component testing in the format of `project:target[:configuration]`. The build target should be from a React app. If not provided we will try to infer it from your projects usage.",
"pattern": "^[^:\\s]+:[^:\\s]+(:\\S+)?$"
},
"generateTests": {
"type": "boolean",
"description": "Generate default component tests for existing components in the project",
Expand Down
27 changes: 24 additions & 3 deletions e2e/react/src/cypress-component-tests.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { newProject, runCLI, uniq } from '../../utils';
import { createFile, newProject, runCLI, uniq, updateFile } from '../../utils';

describe('React Cypress Component Tests', () => {
beforeAll(() => newProject());
Expand All @@ -17,14 +17,35 @@ describe('React Cypress Component Tests', () => {
);
}, 1000000);

it('should successfully test react app', () => {
it('should successfully test react lib', () => {
const libName = uniq('cy-react-lib');
const appName = uniq('cy-react-app-target');
runCLI(`generate @nrwl/react:app ${appName} --no-interactive`);
runCLI(`generate @nrwl/react:lib ${libName} --component --no-interactive`);
runCLI(
`generate @nrwl/react:setup-tailwind --project=${libName} --no-interactive`
);
runCLI(
`generate @nrwl/react:component fancy-component --project=${libName} --no-interactive`
);
createFile(
`libs/${libName}/src/styles.css`,
`
@tailwind components;
@tailwind base;
@tailwind utilities;
`
);
updateFile(
`libs/${libName}/src/lib/fancy-component/fancy-component.tsx`,
(content) => {
return `
import '../../styles.css';
${content}`;
}
);
runCLI(
`generate @nrwl/react:cypress-component-configuration --project=${libName} --generate-tests`
`generate @nrwl/react:cypress-component-configuration --project=${libName} --build-target=${appName}:build --generate-tests`
);
expect(runCLI(`component-test ${libName} --no-watch`)).toContain(
'All specs passed!'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
// mock so we can test multiple versions
jest.mock('@nrwl/cypress/src/utils/cypress-version');

// mock bc the nxE2EPreset uses fs for path normalization
jest.mock('fs', () => {
return {
...jest.requireActual('fs'),
lstatSync: jest.fn(() => ({
isDirectory: jest.fn(() => true),
})),
};
});
import { installedCypressVersion } from '@nrwl/cypress/src/utils/cypress-version';
import {
joinPathFragments,
Expand All @@ -13,6 +21,7 @@ import {
writeJson,
} from '@nrwl/devkit';
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
import { lstatSync } from 'fs';
import { E2eMigrator } from './e2e.migrator';
import { MigrationProjectConfiguration } from './types';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ export class E2eMigrator extends ProjectMigrator<SupportedTargets> {
}

private updateCypress10ConfigFile(configFilePath: string): void {
this.cypressPreset = nxE2EPreset(this.project.newRoot);
this.cypressPreset = nxE2EPreset(configFilePath);

const fileContent = this.tree.read(configFilePath, 'utf-8');
let sourceFile = tsquery.ast(fileContent);
Expand Down
6 changes: 6 additions & 0 deletions packages/cypress/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
"version": "12.8.0-beta.0",
"description": "Remove Typescript Preprocessor Plugin",
"factory": "./src/migrations/update-12-8-0/remove-typescript-plugin"
},
"update-cypress-configs-preset": {
"cli": "nx",
"version": "14.6.1-beta.0",
"description": "Change Cypress e2e and component testing presets to use __filename instead of __dirname and include a devServerTarget for component testing.",
"factory": "./src/migrations/update-14-6-1/update-cypress-configs-presets"
}
},
"packageJsonUpdates": {
Expand Down
12 changes: 9 additions & 3 deletions packages/cypress/plugins/cypress-preset.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { workspaceRoot } from '@nrwl/devkit';
import { join, relative } from 'path';
import { dirname, join, relative } from 'path';
import { lstatSync } from 'fs';

interface BaseCypressPreset {
videosFolder: string;
Expand All @@ -9,8 +10,13 @@ interface BaseCypressPreset {
}

export function nxBaseCypressPreset(pathToConfig: string): BaseCypressPreset {
const projectPath = relative(workspaceRoot, pathToConfig);
const offset = relative(pathToConfig, workspaceRoot);
// prevent from placing path outside the root of the workspace
// if they pass in a file or directory
const normalizedPath = lstatSync(pathToConfig).isDirectory()
? pathToConfig
: dirname(pathToConfig);
const projectPath = relative(workspaceRoot, normalizedPath);
const offset = relative(normalizedPath, workspaceRoot);
const videosFolder = join(offset, 'dist', 'cypress', projectPath, 'videos');
const screenshotsFolder = join(
offset,
Expand Down
3 changes: 2 additions & 1 deletion packages/cypress/src/executors/cypress/cypress.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ export default async function cypressExecutor(
context: ExecutorContext
) {
options = normalizeOptions(options, context);

// this is used by cypress component testing presets to build the executor contexts with the correct configuration options.
process.env.NX_CYPRESS_TARGET_CONFIGURATION = context.configurationName;
let success;

for await (const baseUrl of startDevServer(options, context)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
addProjectConfiguration,
ProjectConfiguration,
readJson,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
Expand Down Expand Up @@ -118,6 +119,19 @@ describe('Cypress Component Project', () => {
expect(projectConfig.targets['component-test']).toMatchSnapshot();
});

it('should update cacheable operations', async () => {
mockedInstalledCypressVersion.mockReturnValue(10);
await cypressComponentProject(tree, {
project: 'cool-lib',
skipFormat: false,
});

expect(
readJson(tree, 'nx.json').tasksRunnerOptions.default.options
.cacheableOperations
).toEqual(expect.arrayContaining(['component-test']));
});

it('should not error when rerunning on an existing project', async () => {
mockedInstalledCypressVersion.mockReturnValue(10);
tree.write('libs/cool-lib/cypress.config.ts', '');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
ProjectConfiguration,
readProjectConfiguration,
Tree,
updateJson,
updateProjectConfiguration,
NxJsonConfiguration,
} from '@nrwl/devkit';
import { installedCypressVersion } from '../../utils/cypress-version';

Expand Down Expand Up @@ -35,7 +37,7 @@ export async function cypressComponentProject(

addProjectFiles(tree, projectConfig, options);
addTargetToProject(tree, projectConfig, options);

addToCacheableOperations(tree);
if (!options.skipFormat) {
await formatFiles(tree);
}
Expand Down Expand Up @@ -87,3 +89,25 @@ function addTargetToProject(

updateProjectConfiguration(tree, options.project, projectConfig);
}

export function addToCacheableOperations(tree: Tree) {
updateJson(tree, 'nx.json', (json) => ({
...json,
tasksRunnerOptions: {
...json.tasksRunnerOptions,
default: {
...json.tasksRunnerOptions?.default,
options: {
...json.tasksRunnerOptions?.default?.options,
cacheableOperations: Array.from(
new Set([
...(json.tasksRunnerOptions?.default?.options
?.cacheableOperations ?? []),
'component-test',
])
),
},
},
},
}));
}
Loading