nx/packages/devkit/src/generators/target-defaults-utils.spec.ts
Jack Hsu 9ce301f30c
fix(testing): fix cypress and playwright atomized targetDefaults so they match correctly (#30717)
Currently, we provide `targetDefaults` for atomized targets (e.g.
`e2e-ci`) with a glob pattern that may not match nested paths.

i.e.

```
"e2e-ci--**/*": {
  "dependsOn": [
    "^build",
  ],
},
```

The `e2e-ci--**/*` pattern should be `e2e-ci--**/**`.

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
The generated `e2e-ci` pattern in `nx.json` does not match nested paths
for split tasks.

## Expected Behavior
The generated `e2e-ci` pattern should apply to all split tasks.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #28842
2025-04-15 11:03:52 -04:00

378 lines
9.9 KiB
TypeScript

import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
import { readNxJson, updateNxJson, type Tree } from 'nx/src/devkit-exports';
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
import { addE2eCiTargetDefaults } from './target-defaults-utils';
describe('target-defaults-utils', () => {
describe('addE2eCiTargetDefaults', () => {
let tree: Tree;
let tempFs: TempFs;
beforeEach(() => {
tempFs = new TempFs('target-defaults-utils');
tree = createTreeWithEmptyWorkspace();
tree.root = tempFs.tempDir;
});
afterEach(() => {
tempFs.cleanup();
jest.resetModules();
});
it('should add e2e-ci--**/** target default for e2e plugin for specified build target when it does not exist', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins ??= [];
nxJson.plugins.push({
plugin: '@nx/cypress/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'e2e-ci',
},
});
updateNxJson(tree, nxJson);
tree.write('apps/myapp-e2e/cypress.config.ts', '');
await tempFs.createFile('apps/myapp-e2e/cypress.config.ts', '');
// ACT
await addE2eCiTargetDefaults(
tree,
'@nx/cypress/plugin',
'^build',
'apps/myapp-e2e/cypress.config.ts'
);
// ASSERT
const newNxJson = readNxJson(tree);
expect(newNxJson.targetDefaults['e2e-ci--**/**']).toMatchInlineSnapshot(`
{
"dependsOn": [
"^build",
],
}
`);
});
it('should update existing e2e-ci--**/** target default for e2e plugin for specified build target when it does not exist in dependsOn', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins ??= [];
nxJson.plugins.push({
plugin: '@nx/cypress/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'e2e-ci',
},
});
nxJson.targetDefaults ??= {};
nxJson.targetDefaults['e2e-ci--**/**'] = {
dependsOn: ['^build'],
};
updateNxJson(tree, nxJson);
tree.write('apps/myapp-e2e/cypress.config.ts', '');
await tempFs.createFile('apps/myapp-e2e/cypress.config.ts', '');
// ACT
await addE2eCiTargetDefaults(
tree,
'@nx/cypress/plugin',
'^build-base',
'apps/myapp-e2e/cypress.config.ts'
);
// ASSERT
const newNxJson = readNxJson(tree);
expect(newNxJson.targetDefaults['e2e-ci--**/**']).toMatchInlineSnapshot(`
{
"dependsOn": [
"^build",
"^build-base",
],
}
`);
});
it('should read the ciTargetName and add a new entry when it does not exist', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins ??= [];
nxJson.plugins.push({
plugin: '@nx/cypress/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'cypress:e2e-ci',
},
});
nxJson.targetDefaults ??= {};
nxJson.targetDefaults['e2e-ci--**/**'] = {
dependsOn: ['^build'],
};
updateNxJson(tree, nxJson);
tree.write('apps/myapp-e2e/cypress.config.ts', '');
await tempFs.createFile('apps/myapp-e2e/cypress.config.ts', '');
// ACT
await addE2eCiTargetDefaults(
tree,
'@nx/cypress/plugin',
'^build-base',
'apps/myapp-e2e/cypress.config.ts'
);
// ASSERT
const newNxJson = readNxJson(tree);
expect(newNxJson.targetDefaults['e2e-ci--**/**']).toMatchInlineSnapshot(`
{
"dependsOn": [
"^build",
],
}
`);
expect(newNxJson.targetDefaults['cypress:e2e-ci--**/**'])
.toMatchInlineSnapshot(`
{
"dependsOn": [
"^build-base",
],
}
`);
});
it('should not add additional e2e-ci--**/** target default for e2e plugin when it already exists with build target', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins ??= [];
nxJson.plugins.push({
plugin: '@nx/cypress/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'e2e-ci',
},
});
nxJson.targetDefaults ??= {};
nxJson.targetDefaults['e2e-ci--**/**'] = {
dependsOn: ['^build'],
};
updateNxJson(tree, nxJson);
tree.write('apps/myapp-e2e/cypress.config.ts', '');
await tempFs.createFile('apps/myapp-e2e/cypress.config.ts', '');
// ACT
await addE2eCiTargetDefaults(
tree,
'@nx/cypress/plugin',
'^build',
'apps/myapp-e2e/cypress.config.ts'
);
// ASSERT
const newNxJson = readNxJson(tree);
expect(newNxJson.targetDefaults).toMatchInlineSnapshot(`
{
"build": {
"cache": true,
},
"e2e-ci--**/**": {
"dependsOn": [
"^build",
],
},
"lint": {
"cache": true,
},
}
`);
});
it('should do nothing when there are no nxJson.plugins does not exist', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins = undefined;
updateNxJson(tree, nxJson);
tree.write('apps/myapp-e2e/cypress.config.ts', '');
await tempFs.createFile('apps/myapp-e2e/cypress.config.ts', '');
// ACT
await addE2eCiTargetDefaults(
tree,
'@nx/cypress/plugin',
'^build',
'apps/myapp-e2e/cypress.config.ts'
);
// ASSERT
const newNxJson = readNxJson(tree);
expect(newNxJson.targetDefaults).toMatchInlineSnapshot(`
{
"build": {
"cache": true,
},
"lint": {
"cache": true,
},
}
`);
});
it('should do nothing when there are nxJson.plugins but e2e plugin is not registered', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins ??= [];
nxJson.plugins.push({
plugin: '@nx/playwright/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'e2e-ci',
},
});
updateNxJson(tree, nxJson);
tree.write('apps/myapp-e2e/cypress.config.ts', '');
await tempFs.createFile('apps/myapp-e2e/cypress.config.ts', '');
// ACT
await addE2eCiTargetDefaults(
tree,
'@nx/cypress/plugin',
'^build',
'apps/myapp-e2e/cypress.config.ts'
);
// ASSERT
const newNxJson = readNxJson(tree);
expect(newNxJson.targetDefaults).toMatchInlineSnapshot(`
{
"build": {
"cache": true,
},
"lint": {
"cache": true,
},
}
`);
});
it('should choose the correct plugin when there are includes', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins ??= [];
nxJson.plugins.push({
plugin: '@nx/cypress/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'e2e-ci',
},
include: ['libs/**'],
});
nxJson.plugins.push({
plugin: '@nx/cypress/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'cypress:e2e-ci',
},
include: ['apps/**'],
});
updateNxJson(tree, nxJson);
tree.write('apps/myapp-e2e/cypress.config.ts', '');
await tempFs.createFile('apps/myapp-e2e/cypress.config.ts', '');
// ACT
await addE2eCiTargetDefaults(
tree,
'@nx/cypress/plugin',
'^build',
'apps/myapp-e2e/cypress.config.ts'
);
// ASSERT
const newNxJson = readNxJson(tree);
expect(newNxJson.targetDefaults['cypress:e2e-ci--**/**'])
.toMatchInlineSnapshot(`
{
"dependsOn": [
"^build",
],
}
`);
});
it('should choose the correct plugin when there are excludes', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins ??= [];
nxJson.plugins.push({
plugin: '@nx/cypress/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'e2e-ci',
},
exclude: ['apps/**'],
});
nxJson.plugins.push({
plugin: '@nx/cypress/plugin',
options: {
targetName: 'e2e',
ciTargetName: 'cypress:e2e-ci',
},
exclude: ['libs/**'],
});
updateNxJson(tree, nxJson);
tree.write('apps/myapp-e2e/cypress.config.ts', '');
await tempFs.createFile('apps/myapp-e2e/cypress.config.ts', '');
// ACT
await addE2eCiTargetDefaults(
tree,
'@nx/cypress/plugin',
'^build',
'apps/myapp-e2e/cypress.config.ts'
);
// ASSERT
const newNxJson = readNxJson(tree);
expect(newNxJson.targetDefaults['cypress:e2e-ci--**/**'])
.toMatchInlineSnapshot(`
{
"dependsOn": [
"^build",
],
}
`);
});
it('should use the default name when the plugin registration is a string', async () => {
// ARRANGE
const nxJson = readNxJson(tree);
nxJson.plugins ??= [];
nxJson.plugins.push('@nx/cypress/plugin');
updateNxJson(tree, nxJson);
tree.write('apps/myapp-e2e/cypress.config.ts', '');
await tempFs.createFile('apps/myapp-e2e/cypress.config.ts', '');
// ACT
await addE2eCiTargetDefaults(
tree,
'@nx/cypress/plugin',
'^build',
'apps/myapp-e2e/cypress.config.ts'
);
// ASSERT
const newNxJson = readNxJson(tree);
expect(newNxJson.targetDefaults['e2e-ci--**/**']).toMatchInlineSnapshot(`
{
"dependsOn": [
"^build",
],
}
`);
});
});
});