feat(testing): add migration for moving test target defaults (#19993)
This commit is contained in:
parent
95ae6fd2a3
commit
b0d179904d
@ -29,6 +29,11 @@
|
|||||||
"version": "16.5.0-beta.2",
|
"version": "16.5.0-beta.2",
|
||||||
"description": "Add test-setup.ts to ignored files in production input",
|
"description": "Add test-setup.ts to ignored files in production input",
|
||||||
"implementation": "./src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore"
|
"implementation": "./src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore"
|
||||||
|
},
|
||||||
|
"move-options-to-target-defaults": {
|
||||||
|
"version": "17.1.0-beta.2",
|
||||||
|
"description": "Move jest executor options to nx.json targetDefaults",
|
||||||
|
"implementation": "./src/migrations/update-17-1-0/move-options-to-target-defaults"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packageJsonUpdates": {
|
"packageJsonUpdates": {
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import {
|
|||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
getProjects,
|
getProjects,
|
||||||
joinPathFragments,
|
|
||||||
readNxJson,
|
readNxJson,
|
||||||
removeDependenciesFromPackageJson,
|
removeDependenciesFromPackageJson,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
@ -27,7 +26,6 @@ import {
|
|||||||
typesNodeVersion,
|
typesNodeVersion,
|
||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import { JestInitSchema } from './schema';
|
import { JestInitSchema } from './schema';
|
||||||
import { JestExecutorOptions } from '../../executors/jest/schema';
|
|
||||||
|
|
||||||
interface NormalizedSchema extends ReturnType<typeof normalizeOptions> {}
|
interface NormalizedSchema extends ReturnType<typeof normalizeOptions> {}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,562 @@
|
|||||||
|
import { createTree } from '@nx/devkit/testing';
|
||||||
|
|
||||||
|
let projectGraph: ProjectGraph;
|
||||||
|
jest.mock('@nx/devkit', () => ({
|
||||||
|
...jest.requireActual<any>('@nx/devkit'),
|
||||||
|
createProjectGraphAsync: jest.fn().mockImplementation(async () => {
|
||||||
|
return projectGraph;
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
import {
|
||||||
|
addProjectConfiguration as _addProjectConfiguration,
|
||||||
|
ProjectGraph,
|
||||||
|
readNxJson,
|
||||||
|
readProjectConfiguration,
|
||||||
|
Tree,
|
||||||
|
updateNxJson,
|
||||||
|
writeJson,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
|
||||||
|
function addProjectConfiguration(tree, name, project) {
|
||||||
|
_addProjectConfiguration(tree, name, project);
|
||||||
|
projectGraph.nodes[name] = {
|
||||||
|
name: name,
|
||||||
|
type: 'lib',
|
||||||
|
data: {
|
||||||
|
root: project.root,
|
||||||
|
targets: project.targets,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
import update from './move-options-to-target-defaults';
|
||||||
|
|
||||||
|
describe('move-options-to-target-defaults migration', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTree();
|
||||||
|
|
||||||
|
writeJson(tree, 'nx.json', {
|
||||||
|
namedInputs: {
|
||||||
|
production: ['default'],
|
||||||
|
},
|
||||||
|
targetDefaults: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
projectGraph = {
|
||||||
|
nodes: {},
|
||||||
|
dependencies: {},
|
||||||
|
externalNodes: {},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add config to nx.json and remove it from projects', async () => {
|
||||||
|
addProjectConfiguration(tree, 'proj1', {
|
||||||
|
root: 'proj1',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.js',
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
addProjectConfiguration(tree, 'proj2', {
|
||||||
|
root: 'proj2',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.js',
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await update(tree);
|
||||||
|
|
||||||
|
expect(readProjectConfiguration(tree, 'proj1').targets.test).toEqual({
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.js',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(readProjectConfiguration(tree, 'proj2').targets.test).toEqual({
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.js',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readNxJson(tree).targetDefaults).toEqual({
|
||||||
|
'@nx/jest:jest': {
|
||||||
|
cache: true,
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
options: {
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use test target defaults if all jest targets are test', async () => {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
nxJson.targetDefaults['test'] = {
|
||||||
|
cache: false,
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
watch: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
|
||||||
|
addProjectConfiguration(tree, 'proj1', {
|
||||||
|
root: 'proj1',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.js',
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await update(tree);
|
||||||
|
|
||||||
|
expect(readProjectConfiguration(tree, 'proj1').targets.test).toEqual({
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.js',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readNxJson(tree).targetDefaults).toEqual({
|
||||||
|
'@nx/jest:jest': {
|
||||||
|
cache: false,
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
passWithNoTests: true,
|
||||||
|
watch: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not remove config which does not match', async () => {
|
||||||
|
addProjectConfiguration(tree, 'proj1', {
|
||||||
|
root: 'proj1',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.js',
|
||||||
|
passWithNoTests: true,
|
||||||
|
watch: false,
|
||||||
|
},
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await update(tree);
|
||||||
|
|
||||||
|
expect(readProjectConfiguration(tree, 'proj1').targets.test).toEqual({
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.js',
|
||||||
|
watch: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readNxJson(tree).targetDefaults).toEqual({
|
||||||
|
'@nx/jest:jest': {
|
||||||
|
cache: true,
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
options: {
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not remove defaults if target uses other executors', async () => {
|
||||||
|
addProjectConfiguration(tree, 'proj1', {
|
||||||
|
root: 'proj1',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.js',
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
addProjectConfiguration(tree, 'proj2', {
|
||||||
|
root: 'proj2',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/vite:vitest',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await update(tree);
|
||||||
|
|
||||||
|
expect(readProjectConfiguration(tree, 'proj1').targets.test).toEqual({
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.js',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(readProjectConfiguration(tree, 'proj2').targets.test).toEqual({
|
||||||
|
executor: '@nx/vite:vitest',
|
||||||
|
options: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readNxJson(tree).targetDefaults).toEqual({
|
||||||
|
'@nx/jest:jest': {
|
||||||
|
cache: true,
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
options: {
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle when jest and vite are used for test and jest and cypress are used for e2e', async () => {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
nxJson.targetDefaults['test'] = {
|
||||||
|
cache: false,
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
watch: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
nxJson.targetDefaults['e2e'] = {
|
||||||
|
cache: false,
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
watch: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
|
||||||
|
addProjectConfiguration(tree, 'proj1', {
|
||||||
|
root: 'proj1',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.ts',
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
e2e: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.ts',
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
addProjectConfiguration(tree, 'proj2', {
|
||||||
|
root: 'proj2',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/vite:vitest',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
e2e: {
|
||||||
|
executor: '@nx/cypress:cypress',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await update(tree);
|
||||||
|
|
||||||
|
expect(readProjectConfiguration(tree, 'proj1').targets).toEqual({
|
||||||
|
e2e: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readProjectConfiguration(tree, 'proj2').targets).toEqual({
|
||||||
|
e2e: {
|
||||||
|
executor: '@nx/cypress:cypress',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
executor: '@nx/vite:vitest',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readNxJson(tree).targetDefaults).toEqual({
|
||||||
|
'@nx/jest:jest': {
|
||||||
|
cache: true,
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
options: {
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
e2e: {
|
||||||
|
cache: false,
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
watch: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
cache: false,
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
watch: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not assign things that had a default already', async () => {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
nxJson.targetDefaults['test'] = {
|
||||||
|
cache: true,
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
options: {
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
|
||||||
|
addProjectConfiguration(tree, 'proj1', {
|
||||||
|
root: 'proj1',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await update(tree);
|
||||||
|
|
||||||
|
expect(readProjectConfiguration(tree, 'proj1').targets).toEqual({
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readNxJson(tree).targetDefaults).toEqual({
|
||||||
|
'@nx/jest:jest': {
|
||||||
|
cache: true,
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
options: {
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove target defaults which are not used anymore', async () => {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
nxJson.targetDefaults['@nx/vite:test'] = {
|
||||||
|
cache: false,
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
};
|
||||||
|
nxJson.targetDefaults['test'] = {
|
||||||
|
cache: false,
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
watch: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
nxJson.targetDefaults['e2e'] = {
|
||||||
|
cache: false,
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
watch: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
|
||||||
|
addProjectConfiguration(tree, 'proj1', {
|
||||||
|
root: 'proj1',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.ts',
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
e2e: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.ts',
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
addProjectConfiguration(tree, 'proj2', {
|
||||||
|
root: 'proj2',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/vite:test',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
e2e: {
|
||||||
|
executor: '@nx/cypress:cypress',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await update(tree);
|
||||||
|
|
||||||
|
expect(readProjectConfiguration(tree, 'proj1').targets).toEqual({
|
||||||
|
e2e: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
options: {
|
||||||
|
jestConfig: 'jest.config.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readProjectConfiguration(tree, 'proj2').targets).toEqual({
|
||||||
|
e2e: {
|
||||||
|
executor: '@nx/cypress:cypress',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
executor: '@nx/vite:test',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readNxJson(tree).targetDefaults).toEqual({
|
||||||
|
'@nx/jest:jest': {
|
||||||
|
cache: true,
|
||||||
|
configurations: {
|
||||||
|
ci: {
|
||||||
|
ci: true,
|
||||||
|
codeCoverage: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
options: {
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'@nx/vite:test': {
|
||||||
|
cache: false,
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
},
|
||||||
|
e2e: {
|
||||||
|
cache: false,
|
||||||
|
inputs: ['default', '^production', '{workspaceRoot}/other-file.txt'],
|
||||||
|
options: {
|
||||||
|
watch: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,185 @@
|
|||||||
|
import {
|
||||||
|
createProjectGraphAsync,
|
||||||
|
formatFiles,
|
||||||
|
getProjects,
|
||||||
|
ProjectConfiguration,
|
||||||
|
ProjectGraphProjectNode,
|
||||||
|
readNxJson,
|
||||||
|
TargetConfiguration,
|
||||||
|
TargetDefaults,
|
||||||
|
Tree,
|
||||||
|
updateNxJson,
|
||||||
|
updateProjectConfiguration,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import { JestExecutorOptions } from '../../executors/jest/schema';
|
||||||
|
import {
|
||||||
|
forEachExecutorOptions,
|
||||||
|
forEachExecutorOptionsInGraph,
|
||||||
|
} from '@nx/devkit/src/generators/executor-options-utils';
|
||||||
|
import { readTargetDefaultsForTarget } from 'nx/src/project-graph/utils/project-configuration-utils';
|
||||||
|
|
||||||
|
export default async function update(tree: Tree) {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
|
||||||
|
// Don't override anything if there are already target defaults for jest
|
||||||
|
if (nxJson.targetDefaults?.['@nx/jest:jest']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxJson.targetDefaults ??= {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of targets which does not use any other executors
|
||||||
|
*/
|
||||||
|
const jestTargets = new Set<string>();
|
||||||
|
|
||||||
|
const graph = await createProjectGraphAsync();
|
||||||
|
|
||||||
|
forEachExecutorOptionsInGraph(
|
||||||
|
graph,
|
||||||
|
'@nx/jest:jest',
|
||||||
|
(value, proj, targetName) => {
|
||||||
|
jestTargets.add(targetName);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Workspace does not use jest?
|
||||||
|
if (jestTargets.size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Use the project graph so targets which are inferred are considered
|
||||||
|
const projects = graph.nodes;
|
||||||
|
const projectMap = getProjects(tree);
|
||||||
|
|
||||||
|
const jestDefaults: TargetConfiguration<Partial<JestExecutorOptions>> =
|
||||||
|
(nxJson.targetDefaults['@nx/jest:jest'] = {});
|
||||||
|
|
||||||
|
// All jest targets have the same name
|
||||||
|
if (jestTargets.size === 1) {
|
||||||
|
const targetName = Array.from(jestTargets)[0];
|
||||||
|
if (nxJson.targetDefaults[targetName]) {
|
||||||
|
Object.assign(jestDefaults, nxJson.targetDefaults[targetName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jestDefaults.cache ??= true;
|
||||||
|
|
||||||
|
const inputs = ['default'];
|
||||||
|
inputs.push(nxJson.namedInputs?.production ? '^production' : '^default');
|
||||||
|
if (tree.exists('jest.preset.js')) {
|
||||||
|
inputs.push('{workspaceRoot}/jest.preset.js');
|
||||||
|
}
|
||||||
|
jestDefaults.inputs ??= inputs;
|
||||||
|
|
||||||
|
// Remember if there were already defaults so we don't assume the executor default
|
||||||
|
const passWithNoTestsPreviouslyInDefaults =
|
||||||
|
jestDefaults.options?.passWithNoTests !== undefined;
|
||||||
|
const ciCiPreviouslyInDefaults =
|
||||||
|
jestDefaults.configurations?.ci?.ci !== undefined;
|
||||||
|
const ciCodeCoveragePreviouslyInDefaults =
|
||||||
|
jestDefaults.configurations?.ci?.codeCoverage !== undefined;
|
||||||
|
|
||||||
|
jestDefaults.options ??= {};
|
||||||
|
jestDefaults.options.passWithNoTests ??= true;
|
||||||
|
jestDefaults.configurations ??= {};
|
||||||
|
jestDefaults.configurations.ci ??= {};
|
||||||
|
jestDefaults.configurations.ci.ci ??= true;
|
||||||
|
jestDefaults.configurations.ci.codeCoverage ??= true;
|
||||||
|
|
||||||
|
// Cleanup old target defaults
|
||||||
|
for (const [targetDefaultKey, targetDefault] of Object.entries(
|
||||||
|
nxJson.targetDefaults
|
||||||
|
)) {
|
||||||
|
if (
|
||||||
|
!isTargetDefaultUsed(
|
||||||
|
targetDefault,
|
||||||
|
nxJson.targetDefaults,
|
||||||
|
projects,
|
||||||
|
projectMap
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
delete nxJson.targetDefaults[targetDefaultKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
|
||||||
|
forEachExecutorOptions<JestExecutorOptions>(
|
||||||
|
tree,
|
||||||
|
'@nx/jest:jest',
|
||||||
|
(value, proj, targetName, configuration) => {
|
||||||
|
const projConfig = projectMap.get(proj);
|
||||||
|
|
||||||
|
if (!configuration) {
|
||||||
|
// Options
|
||||||
|
if (value.passWithNoTests === jestDefaults.options.passWithNoTests) {
|
||||||
|
delete projConfig.targets[targetName].options.passWithNoTests;
|
||||||
|
} else if (!passWithNoTestsPreviouslyInDefaults) {
|
||||||
|
projConfig.targets[targetName].options.passWithNoTests ??= false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(projConfig.targets[targetName].options).length === 0) {
|
||||||
|
delete projConfig.targets[targetName].options;
|
||||||
|
}
|
||||||
|
} else if (configuration === 'ci') {
|
||||||
|
// CI Config
|
||||||
|
if (value.ci === jestDefaults.configurations.ci.ci) {
|
||||||
|
delete projConfig.targets[targetName].configurations.ci.ci;
|
||||||
|
} else if (ciCiPreviouslyInDefaults) {
|
||||||
|
projConfig.targets[targetName].configurations.ci.ci ??= false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
value.codeCoverage === jestDefaults.configurations.ci.codeCoverage
|
||||||
|
) {
|
||||||
|
delete projConfig.targets[targetName].configurations.ci.codeCoverage;
|
||||||
|
} else if (ciCodeCoveragePreviouslyInDefaults) {
|
||||||
|
projConfig.targets[targetName].configurations.ci.codeCoverage ??=
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
Object.keys(projConfig.targets[targetName].configurations.ci)
|
||||||
|
.length === 0
|
||||||
|
) {
|
||||||
|
delete projConfig.targets[targetName].configurations.ci;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
Object.keys(projConfig.targets[targetName].configurations).length ===
|
||||||
|
0
|
||||||
|
) {
|
||||||
|
delete projConfig.targets[targetName].configurations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProjectConfiguration(tree, proj, projConfig);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await formatFiles(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks every target on every project to see if one of them uses the target default
|
||||||
|
*/
|
||||||
|
function isTargetDefaultUsed(
|
||||||
|
targetDefault: Partial<TargetConfiguration>,
|
||||||
|
targetDefaults: TargetDefaults,
|
||||||
|
projects: Record<string, ProjectGraphProjectNode>,
|
||||||
|
projectMap: Map<string, ProjectConfiguration>
|
||||||
|
) {
|
||||||
|
for (const p of Object.values(projects)) {
|
||||||
|
for (const targetName in p.data?.targets ?? {}) {
|
||||||
|
if (
|
||||||
|
readTargetDefaultsForTarget(
|
||||||
|
targetName,
|
||||||
|
targetDefaults,
|
||||||
|
// It might seem like we should use the graph here too but we don't want to pass an executor which was processed in the graph
|
||||||
|
projectMap.get(p.name).targets?.[targetName]?.executor
|
||||||
|
) === targetDefault
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@ -35,6 +35,11 @@
|
|||||||
"description": "Change vite-tsconfig-paths plugin for first party nx-vite-tsconfig-paths plugin",
|
"description": "Change vite-tsconfig-paths plugin for first party nx-vite-tsconfig-paths plugin",
|
||||||
"cli": "nx",
|
"cli": "nx",
|
||||||
"implementation": "./src/migrations/update-16-6-0-change-ts-paths-plugin/change-ts-paths-plugin"
|
"implementation": "./src/migrations/update-16-6-0-change-ts-paths-plugin/change-ts-paths-plugin"
|
||||||
|
},
|
||||||
|
"move-target-defaults": {
|
||||||
|
"version": "17.1.0-beta.2",
|
||||||
|
"description": "Move target defaults",
|
||||||
|
"implementation": "./src/migrations/update-17-1-0/move-target-defaults"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packageJsonUpdates": {
|
"packageJsonUpdates": {
|
||||||
|
|||||||
@ -81,7 +81,7 @@ describe('@nx/vite:init', () => {
|
|||||||
const productionNamedInputs = readJson(tree, 'nx.json').namedInputs
|
const productionNamedInputs = readJson(tree, 'nx.json').namedInputs
|
||||||
.production;
|
.production;
|
||||||
const vitestDefaults = readJson(tree, 'nx.json').targetDefaults[
|
const vitestDefaults = readJson(tree, 'nx.json').targetDefaults[
|
||||||
'@nx/vite:vitest'
|
'@nx/vite:test'
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(productionNamedInputs).toContain(
|
expect(productionNamedInputs).toContain(
|
||||||
|
|||||||
@ -93,9 +93,9 @@ export function createVitestConfig(tree: Tree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nxJson.targetDefaults ??= {};
|
nxJson.targetDefaults ??= {};
|
||||||
nxJson.targetDefaults['@nx/vite:vitest'] ??= {};
|
nxJson.targetDefaults['@nx/vite:test'] ??= {};
|
||||||
nxJson.targetDefaults['@nx/vite:vitest'].cache ??= true;
|
nxJson.targetDefaults['@nx/vite:test'].cache ??= true;
|
||||||
nxJson.targetDefaults['@nx/vite:vitest'].inputs ??= [
|
nxJson.targetDefaults['@nx/vite:test'].inputs ??= [
|
||||||
'default',
|
'default',
|
||||||
productionFileSet ? '^production' : '^default',
|
productionFileSet ? '^production' : '^default',
|
||||||
];
|
];
|
||||||
|
|||||||
@ -0,0 +1,79 @@
|
|||||||
|
import { createTree } from '@nx/devkit/testing';
|
||||||
|
import {
|
||||||
|
addProjectConfiguration as _addProjectConfiguration,
|
||||||
|
ProjectGraph,
|
||||||
|
readNxJson,
|
||||||
|
Tree,
|
||||||
|
writeJson,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
|
||||||
|
import update from './move-target-defaults';
|
||||||
|
|
||||||
|
let projectGraph: ProjectGraph;
|
||||||
|
jest.mock('@nx/devkit', () => ({
|
||||||
|
...jest.requireActual<any>('@nx/devkit'),
|
||||||
|
createProjectGraphAsync: jest.fn().mockImplementation(async () => {
|
||||||
|
return projectGraph;
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
function addProjectConfiguration(tree, name, project) {
|
||||||
|
_addProjectConfiguration(tree, name, project);
|
||||||
|
projectGraph.nodes[name] = {
|
||||||
|
name: name,
|
||||||
|
type: 'lib',
|
||||||
|
data: {
|
||||||
|
root: project.root,
|
||||||
|
targets: project.targets,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('move-target-defaults migration', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTree();
|
||||||
|
writeJson(tree, 'nx.json', {
|
||||||
|
namedInputs: {
|
||||||
|
production: ['default'],
|
||||||
|
},
|
||||||
|
targetDefaults: {
|
||||||
|
test: {
|
||||||
|
cache: true,
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
projectGraph = {
|
||||||
|
nodes: {},
|
||||||
|
dependencies: {},
|
||||||
|
externalNodes: {},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add options to nx.json target defaults and remove them from projects', async () => {
|
||||||
|
addProjectConfiguration(tree, 'proj1', {
|
||||||
|
root: 'proj1',
|
||||||
|
targets: {
|
||||||
|
test: {
|
||||||
|
executor: '@nx/vite:test',
|
||||||
|
options: {
|
||||||
|
passWithNoTests: true,
|
||||||
|
reportsDirectory: '../../reports',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await update(tree);
|
||||||
|
|
||||||
|
expect(readNxJson(tree).targetDefaults).toEqual({
|
||||||
|
'@nx/vite:test': {
|
||||||
|
cache: true,
|
||||||
|
inputs: ['default', '^production'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
import {
|
||||||
|
createProjectGraphAsync,
|
||||||
|
formatFiles,
|
||||||
|
getProjects,
|
||||||
|
ProjectConfiguration,
|
||||||
|
ProjectGraphProjectNode,
|
||||||
|
readNxJson,
|
||||||
|
TargetConfiguration,
|
||||||
|
TargetDefaults,
|
||||||
|
Tree,
|
||||||
|
updateNxJson,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import { forEachExecutorOptionsInGraph } from '@nx/devkit/src/generators/executor-options-utils';
|
||||||
|
import { VitestExecutorOptions } from '../../executors/test/schema';
|
||||||
|
import { readTargetDefaultsForTarget } from 'nx/src/project-graph/utils/project-configuration-utils';
|
||||||
|
|
||||||
|
export default async function update(tree: Tree) {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
|
||||||
|
// Don't override anything if there are already target defaults for vitest
|
||||||
|
if (nxJson.targetDefaults?.['@nx/vite:test']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxJson.targetDefaults ??= {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of targets which does not use any other executors
|
||||||
|
*/
|
||||||
|
const vitestTargets = new Set<string>();
|
||||||
|
const graph = await createProjectGraphAsync();
|
||||||
|
const projectMap = getProjects(tree);
|
||||||
|
|
||||||
|
forEachExecutorOptionsInGraph(
|
||||||
|
graph,
|
||||||
|
'@nx/vite:test',
|
||||||
|
(value, proj, targetName) => {
|
||||||
|
vitestTargets.add(targetName);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Workspace does not use vitest
|
||||||
|
if (vitestTargets.size === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the project graph nodes so that targets which are inferred are considered
|
||||||
|
const projects = graph.nodes;
|
||||||
|
|
||||||
|
const vitestDefaults: TargetConfiguration<Partial<VitestExecutorOptions>> =
|
||||||
|
(nxJson.targetDefaults['@nx/vite:test'] = {});
|
||||||
|
|
||||||
|
// All vitest targets have the same name
|
||||||
|
if (vitestTargets.size === 1) {
|
||||||
|
const targetName = Array.from(vitestTargets)[0];
|
||||||
|
if (nxJson.targetDefaults[targetName]) {
|
||||||
|
Object.assign(vitestDefaults, nxJson.targetDefaults[targetName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vitestDefaults.cache ??= true;
|
||||||
|
|
||||||
|
const inputs = ['default'];
|
||||||
|
inputs.push(nxJson.namedInputs?.production ? '^production' : '^default');
|
||||||
|
vitestDefaults.inputs ??= inputs;
|
||||||
|
|
||||||
|
// Cleanup old target defaults
|
||||||
|
for (const [targetDefaultKey, targetDefault] of Object.entries(
|
||||||
|
nxJson.targetDefaults
|
||||||
|
)) {
|
||||||
|
if (
|
||||||
|
!isTargetDefaultUsed(
|
||||||
|
targetDefault,
|
||||||
|
nxJson.targetDefaults,
|
||||||
|
projects,
|
||||||
|
projectMap
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
delete nxJson.targetDefaults[targetDefaultKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
|
||||||
|
await formatFiles(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks every target on every project to see if one of them uses the target default
|
||||||
|
*/
|
||||||
|
function isTargetDefaultUsed(
|
||||||
|
targetDefault: Partial<TargetConfiguration>,
|
||||||
|
targetDefaults: TargetDefaults,
|
||||||
|
projects: Record<string, ProjectGraphProjectNode>,
|
||||||
|
projectMap: Map<string, ProjectConfiguration>
|
||||||
|
) {
|
||||||
|
for (const p of Object.values(projects)) {
|
||||||
|
for (const targetName in p.data?.targets ?? {}) {
|
||||||
|
if (
|
||||||
|
readTargetDefaultsForTarget(
|
||||||
|
targetName,
|
||||||
|
targetDefaults,
|
||||||
|
// It might seem like we should use the graph here too but we don't want to pass an executor which was processed in the graph
|
||||||
|
projectMap.get(p.name).targets?.[targetName]?.executor
|
||||||
|
) === targetDefault
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user