fix(nx-plugin): run jest 29 migrations for @nrwl/nx-plugin:e2e (#15551)
This commit is contained in:
parent
d7a008ff5e
commit
a67baaa66e
@ -17,6 +17,18 @@
|
||||
"version": "15.0.0-beta.0",
|
||||
"description": "Migrates executor schema files to v2",
|
||||
"factory": "./src/migrations/update-15-0-0/specify-output-capture"
|
||||
},
|
||||
"update-configs-jest-29": {
|
||||
"version": "15.9.0-beta.0",
|
||||
"cli": "nx",
|
||||
"description": "Update nx plugin jest configs to support jest 29 changes (https://jestjs.io/docs/upgrading-to-jest29)",
|
||||
"factory": "./src/migrations/update-15-9-0/jest-29-configs"
|
||||
},
|
||||
"update-tests-jest-29": {
|
||||
"version": "15.9.0-beta.0",
|
||||
"cli": "nx",
|
||||
"description": "Update nx plugin jest test files to support jest 29 changes (https://jestjs.io/docs/upgrading-to-jest29)",
|
||||
"factory": "./src/migrations/update-15-9-0/jest-29-tests"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
"@nrwl/jest": "file:../jest",
|
||||
"@nrwl/js": "file:../js",
|
||||
"@nrwl/linter": "file:../linter",
|
||||
"@phenomnomnominal/tsquery": "4.1.1",
|
||||
"dotenv": "~10.0.0",
|
||||
"fs-extra": "^11.1.0",
|
||||
"tslib": "^2.3.0"
|
||||
|
||||
@ -12,6 +12,7 @@ import { JestExecutorOptions } from '@nrwl/jest/src/executors/jest/schema';
|
||||
import { jestExecutor } from '@nrwl/jest/src/executors/jest/jest.impl';
|
||||
import type { NxPluginE2EExecutorOptions } from './schema';
|
||||
|
||||
// TODO(Caleb & Craigory): can we get rid of this and just use @nrwl/jest directly?
|
||||
export async function* nxPluginE2EExecutor(
|
||||
options: NxPluginE2EExecutorOptions,
|
||||
context: ExecutorContext
|
||||
|
||||
@ -0,0 +1,457 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should NOT update ts-jest with no globals are preset 1`] = `
|
||||
"const nxPreset = require('@nrwl/jest/preset').default;
|
||||
module.exports = {
|
||||
...nxPreset,
|
||||
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||
transform: {
|
||||
'^.+\\\\.(ts|js|html)$': 'ts-jest',
|
||||
},
|
||||
resolver: '@nrwl/jest/plugins/resolver',
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageReporters: ['html'],
|
||||
/* TODO: Update to latest Jest snapshotFormat
|
||||
* By default Nx has kept the older style of Jest Snapshot formats
|
||||
* to prevent breaking of any existing tests with snapshots.
|
||||
* It's recommend you update to the latest format.
|
||||
* You can do this by removing snapshotFormat property
|
||||
* and running tests with --update-snapshot flag.
|
||||
* Example: \\"nx affected --targets=test --update-snapshot\\"
|
||||
* More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format
|
||||
*/
|
||||
snapshotFormat: { escapeString: true, printBasicPrototype: true }
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should add snapshot config with no root preset 1`] = `
|
||||
"/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'my-lib',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: { },
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
}]
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/libs/my-lib',
|
||||
/* TODO: Update to latest Jest snapshotFormat
|
||||
* By default Nx has kept the older style of Jest Snapshot formats
|
||||
* to prevent breaking of any existing tests with snapshots.
|
||||
* It's recommend you update to the latest format.
|
||||
* You can do this by removing snapshotFormat property
|
||||
* and running tests with --update-snapshot flag.
|
||||
* Example: From within the project directory, run \\"nx test --update-snapshot\\"
|
||||
* More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format
|
||||
*/
|
||||
snapshotFormat: { escapeString: true, printBasicPrototype: true }
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should add snapshot config with no root preset 2`] = `
|
||||
"module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
}]
|
||||
},
|
||||
// I am a comment and shouldn't be removed
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}] },
|
||||
/**
|
||||
* Multi-line comment shouldn't be removed
|
||||
*/
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
/* TODO: Update to latest Jest snapshotFormat
|
||||
* By default Nx has kept the older style of Jest Snapshot formats
|
||||
* to prevent breaking of any existing tests with snapshots.
|
||||
* It's recommend you update to the latest format.
|
||||
* You can do this by removing snapshotFormat property
|
||||
* and running tests with --update-snapshot flag.
|
||||
* Example: From within the project directory, run \\"nx test --update-snapshot\\"
|
||||
* More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format
|
||||
*/
|
||||
snapshotFormat: { escapeString: true, printBasicPrototype: true }
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should be idempotent 1`] = `
|
||||
"/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'my-lib',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: { },
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
}]
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/libs/my-lib'
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should be idempotent 2`] = `
|
||||
"module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
}]
|
||||
},
|
||||
// I am a comment and shouldn't be removed
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}] },
|
||||
/**
|
||||
* Multi-line comment shouldn't be removed
|
||||
*/
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js'
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should update globalThis.ngJest.teardown to testEnvironmentOptions 1`] = `
|
||||
"globalThis.ngJest = {
|
||||
|
||||
}
|
||||
|
||||
export default {
|
||||
globals: { },
|
||||
transform: {
|
||||
'^.+.(ts|mjs|js|html)$': ['jest-preset-angular', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\\\.(html|svg)$',
|
||||
}],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
testEnvironmentOptions: { teardown: true },
|
||||
};"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should update globalThis.ngJest.teardown to testEnvironmentOptions 2`] = `
|
||||
"
|
||||
globalThis.ngJest = {
|
||||
ngcc: true,
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
globals: { },
|
||||
transform: {
|
||||
'^.+.(ts|mjs|js|html)$': ['jest-preset-angular', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\\\.(html|svg)$',
|
||||
}],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
testEnvironmentOptions: {
|
||||
blah: 123,
|
||||
teardown: false
|
||||
},
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should update jest.config.ts 1`] = `
|
||||
"/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'my-lib',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: { },
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
}]
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/libs/my-lib'
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should update jest.config.ts 2`] = `
|
||||
"module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
}]
|
||||
},
|
||||
// I am a comment and shouldn't be removed
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}] },
|
||||
/**
|
||||
* Multi-line comment shouldn't be removed
|
||||
*/
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js'
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should update root preset 1`] = `
|
||||
"
|
||||
const nxPreset = require('@nrwl/jest/preset').default;
|
||||
|
||||
module.exports = {
|
||||
...nxPreset,
|
||||
/* TODO: Update to latest Jest snapshotFormat
|
||||
* By default Nx has kept the older style of Jest Snapshot formats
|
||||
* to prevent breaking of any existing tests with snapshots.
|
||||
* It's recommend you update to the latest format.
|
||||
* You can do this by removing snapshotFormat property
|
||||
* and running tests with --update-snapshot flag.
|
||||
* Example: \\"nx affected --targets=test --update-snapshot\\"
|
||||
* More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format
|
||||
*/
|
||||
snapshotFormat: { escapeString: true, printBasicPrototype: true }
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should update root preset 2`] = `
|
||||
"/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'my-lib',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: { },
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
}]
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/libs/my-lib'
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should update root preset 3`] = `
|
||||
"module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
}]
|
||||
},
|
||||
// I am a comment and shouldn't be removed
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}] },
|
||||
/**
|
||||
* Multi-line comment shouldn't be removed
|
||||
*/
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js'
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should update root preset if ts-jest is preset 1`] = `
|
||||
"const nxPreset = require('@nrwl/jest/preset').default;
|
||||
module.exports = {
|
||||
...nxPreset,
|
||||
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||
globals: { something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}] },
|
||||
transform: {
|
||||
'^.+\\\\.(ts|js|html)$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
}],
|
||||
},
|
||||
resolver: '@nrwl/jest/plugins/resolver',
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageReporters: ['html'],
|
||||
/* TODO: Update to latest Jest snapshotFormat
|
||||
* By default Nx has kept the older style of Jest Snapshot formats
|
||||
* to prevent breaking of any existing tests with snapshots.
|
||||
* It's recommend you update to the latest format.
|
||||
* You can do this by removing snapshotFormat property
|
||||
* and running tests with --update-snapshot flag.
|
||||
* Example: \\"nx affected --targets=test --update-snapshot\\"
|
||||
* More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format
|
||||
*/
|
||||
snapshotFormat: { escapeString: true, printBasicPrototype: true }
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should work if not using ts-jest transformer 1`] = `
|
||||
"export default {
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': 'babel-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should work if not using ts-jest transformer 2`] = `
|
||||
"module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': 'babel-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should work snapshotFormat is defined 1`] = `
|
||||
"export default {
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': 'babel-jest',
|
||||
},
|
||||
globals: { something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}] },
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
snapshotFormat: {escapeString: false, printBasicPrototype: true}
|
||||
};"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should work snapshotFormat is defined 2`] = `
|
||||
"module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
}],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: { something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}] },
|
||||
snapshotFormat: {escapeString: false, printBasicPrototype: true}
|
||||
};"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should work with jest-preset-angular 1`] = `
|
||||
"export default {
|
||||
globals: { },
|
||||
transform: {
|
||||
'^.+.(ts|mjs|js|html)$': ['jest-preset-angular', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\\\.(html|svg)$',
|
||||
}],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should work with jest-preset-angular 2`] = `
|
||||
"module.exports = {
|
||||
globals: { },
|
||||
transform: {
|
||||
'^.+.(ts|mjs|js|html)$': ['jest-preset-angular', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\\\.(html|svg)$',
|
||||
}],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should work with multiple projects + configs 1`] = `
|
||||
"/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'my-lib',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: { },
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
}]
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/libs/my-lib'
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should work with multiple projects + configs 2`] = `
|
||||
"module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
}]
|
||||
},
|
||||
// I am a comment and shouldn't be removed
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}] },
|
||||
/**
|
||||
* Multi-line comment shouldn't be removed
|
||||
*/
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js'
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should work with multiple projects + configs 3`] = `
|
||||
"/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'another-lib',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: { },
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
}]
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/libs/another-lib'
|
||||
};
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 update configs should work with multiple projects + configs 4`] = `
|
||||
"module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\\\\\.[tj]sx?$': ['ts-jest', {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
}]
|
||||
},
|
||||
// I am a comment and shouldn't be removed
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: { something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}] },
|
||||
/**
|
||||
* Multi-line comment shouldn't be removed
|
||||
*/
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js'
|
||||
};
|
||||
"
|
||||
`;
|
||||
@ -0,0 +1,193 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 mocked usage in tests should be idempotent 1`] = `
|
||||
"
|
||||
import{ MaybeMockedDeep, MaybeMocked } from 'jest-mock';
|
||||
import {expect, jest, test} from '@jest/globals';
|
||||
import {song} from './song';
|
||||
|
||||
jest.mock('./song');
|
||||
jest.spyOn(console, 'log');
|
||||
|
||||
const mockedSong = jest.mocked(song, true);
|
||||
// or through \`jest.Mocked<Source>\`
|
||||
// const mockedSong = song as jest.Mocked<typeof song>;
|
||||
|
||||
test('deep method is typed correctly', () => {
|
||||
mockedSong.one.more.time.mockReturnValue(12);
|
||||
|
||||
expect(mockedSong.one.more.time(10)).toBe(12);
|
||||
expect(mockedSong.one.more.time.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('direct usage', () => {
|
||||
jest.mocked(console.log).mockImplementation(() => {
|
||||
return;
|
||||
});
|
||||
|
||||
console.log('one more time');
|
||||
|
||||
expect(jest.mocked(console.log, false).mock.calls).toHaveLength(1);
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 mocked usage in tests should be idempotent 2`] = `
|
||||
"
|
||||
const { MaybeMockedDeep, MaybeMocked } = require('jest-mock');
|
||||
const {expect, jest, test} = require('@jest/globals');
|
||||
const {song} = require('./song');
|
||||
|
||||
jest.mock('./song');
|
||||
jest.spyOn(console, 'log');
|
||||
|
||||
const mockedSong = jest.mocked(song, true);
|
||||
// or through \`jest.Mocked<Source>\`
|
||||
// const mockedSong = song as jest.Mocked<typeof song>;
|
||||
|
||||
test('deep method is typed correctly', () => {
|
||||
mockedSong.one.more.time.mockReturnValue(12);
|
||||
|
||||
expect(mockedSong.one.more.time(10)).toBe(12);
|
||||
expect(mockedSong.one.more.time.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('direct usage', () => {
|
||||
jest.mocked(console.log).mockImplementation(() => {
|
||||
return;
|
||||
});
|
||||
|
||||
console.log('one more time');
|
||||
|
||||
expect(jest.mocked(console.log, false).mock.calls).toHaveLength(1);
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 mocked usage in tests should be idempotent 3`] = `
|
||||
"
|
||||
import{ MaybeMockedDeep, MaybeMocked } from 'jest-mock';
|
||||
import {expect, jest, test} from '@jest/globals';
|
||||
import {song} from './song';
|
||||
|
||||
jest.mock('./song');
|
||||
jest.spyOn(console, 'log');
|
||||
|
||||
const mockedSong = jest.mocked(song, true);
|
||||
// or through \`jest.Mocked<Source>\`
|
||||
// const mockedSong = song as jest.Mocked<typeof song>;
|
||||
|
||||
test('deep method is typed correctly', () => {
|
||||
mockedSong.one.more.time.mockReturnValue(12);
|
||||
|
||||
expect(mockedSong.one.more.time(10)).toBe(12);
|
||||
expect(mockedSong.one.more.time.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('direct usage', () => {
|
||||
jest.mocked(console.log).mockImplementation(() => {
|
||||
return;
|
||||
});
|
||||
|
||||
console.log('one more time');
|
||||
|
||||
expect(jest.mocked(console.log, false).mock.calls).toHaveLength(1);
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 mocked usage in tests should be idempotent 4`] = `
|
||||
"
|
||||
const { MaybeMockedDeep, MaybeMocked } = require('jest-mock');
|
||||
const {expect, jest, test} = require('@jest/globals');
|
||||
const {song} = require('./song');
|
||||
|
||||
jest.mock('./song');
|
||||
jest.spyOn(console, 'log');
|
||||
|
||||
const mockedSong = jest.mocked(song, true);
|
||||
// or through \`jest.Mocked<Source>\`
|
||||
// const mockedSong = song as jest.Mocked<typeof song>;
|
||||
|
||||
test('deep method is typed correctly', () => {
|
||||
mockedSong.one.more.time.mockReturnValue(12);
|
||||
|
||||
expect(mockedSong.one.more.time(10)).toBe(12);
|
||||
expect(mockedSong.one.more.time.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('direct usage', () => {
|
||||
jest.mocked(console.log).mockImplementation(() => {
|
||||
return;
|
||||
});
|
||||
|
||||
console.log('one more time');
|
||||
|
||||
expect(jest.mocked(console.log, false).mock.calls).toHaveLength(1);
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 mocked usage in tests should not update anything if there are no tests 1`] = `
|
||||
"
|
||||
import{ MaybeMockedDeep, MaybeMocked } from 'jest-mock';
|
||||
import {expect, jest, test} from '@jest/globals';
|
||||
import {song} from './song';
|
||||
|
||||
jest.mock('./song');
|
||||
jest.spyOn(console, 'log');
|
||||
|
||||
const mockedSong = jest.mocked(song, true);
|
||||
// or through \`jest.Mocked<Source>\`
|
||||
// const mockedSong = song as jest.Mocked<typeof song>;
|
||||
|
||||
test('deep method is typed correctly', () => {
|
||||
mockedSong.one.more.time.mockReturnValue(12);
|
||||
|
||||
expect(mockedSong.one.more.time(10)).toBe(12);
|
||||
expect(mockedSong.one.more.time.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('direct usage', () => {
|
||||
jest.mocked(console.log).mockImplementation(() => {
|
||||
return;
|
||||
});
|
||||
|
||||
console.log('one more time');
|
||||
|
||||
expect(jest.mocked(console.log, false).mock.calls).toHaveLength(1);
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Nx Plugin Migration - jest 29 mocked usage in tests should not update anything if there are no tests 2`] = `
|
||||
"
|
||||
const { MaybeMockedDeep, MaybeMocked } = require('jest-mock');
|
||||
const {expect, jest, test} = require('@jest/globals');
|
||||
const {song} = require('./song');
|
||||
|
||||
jest.mock('./song');
|
||||
jest.spyOn(console, 'log');
|
||||
|
||||
const mockedSong = jest.mocked(song, true);
|
||||
// or through \`jest.Mocked<Source>\`
|
||||
// const mockedSong = song as jest.Mocked<typeof song>;
|
||||
|
||||
test('deep method is typed correctly', () => {
|
||||
mockedSong.one.more.time.mockReturnValue(12);
|
||||
|
||||
expect(mockedSong.one.more.time(10)).toBe(12);
|
||||
expect(mockedSong.one.more.time.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('direct usage', () => {
|
||||
jest.mocked(console.log).mockImplementation(() => {
|
||||
return;
|
||||
});
|
||||
|
||||
console.log('one more time');
|
||||
|
||||
expect(jest.mocked(console.log, false).mock.calls).toHaveLength(1);
|
||||
});
|
||||
"
|
||||
`;
|
||||
@ -0,0 +1,230 @@
|
||||
import {
|
||||
formatFiles,
|
||||
logger,
|
||||
stripIndents,
|
||||
Tree,
|
||||
createProjectGraphAsync,
|
||||
} from '@nrwl/devkit';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
import * as ts from 'typescript';
|
||||
import { forEachExecutorOptionsInGraph } from '@nrwl/workspace/src/utilities/executor-options-utils';
|
||||
import { TS_QUERY_JEST_CONFIG_PREFIX } from '@nrwl/jest/src/utils/ast-utils';
|
||||
import { findRootJestPreset } from '@nrwl/jest/src/utils/config/find-root-jest-files';
|
||||
import { JestExecutorOptions } from '@nrwl/jest/src/executors/jest/schema';
|
||||
|
||||
// NOTE: this is a copy of the @nrwl/jest v15.8.0 migrations
|
||||
export async function updateConfigsJest29(tree: Tree) {
|
||||
const rootPreset = findRootJestPreset(tree);
|
||||
const targetsWithJest = new Set<string>();
|
||||
// have to use graph so the negative configuration targets are expanded
|
||||
const graph = await createProjectGraphAsync();
|
||||
forEachExecutorOptionsInGraph<JestExecutorOptions>(
|
||||
graph,
|
||||
'@nrwl/nx-plugin:e2e',
|
||||
(options, projectName, targetName) => {
|
||||
if (options.jestConfig && tree.exists(options.jestConfig)) {
|
||||
targetsWithJest.add(targetName);
|
||||
// if the default root preset exists or if the project doesn't have a 'preset' configured
|
||||
// -> update snapshot config
|
||||
if (!rootPreset || !hasPresetConfigured(tree, options.jestConfig)) {
|
||||
addSnapshotOptionsToConfig(
|
||||
tree,
|
||||
options.jestConfig,
|
||||
`From within the project directory, run "nx test --update-snapshot"`
|
||||
);
|
||||
}
|
||||
updateTsJestOptions(tree, options.jestConfig);
|
||||
updateNgJestOptions(tree, options.jestConfig);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (rootPreset && tree.exists(rootPreset)) {
|
||||
const cmd = `"nx affected --targets=${Array.from(targetsWithJest).join(
|
||||
','
|
||||
)} --update-snapshot"`;
|
||||
addSnapshotOptionsToConfig(tree, rootPreset, cmd);
|
||||
updateTsJestOptions(tree, rootPreset);
|
||||
updateNgJestOptions(tree, rootPreset);
|
||||
}
|
||||
|
||||
await formatFiles(tree);
|
||||
logger.info(stripIndents`NX Jest Snapshot format changed in v29.
|
||||
By default Nx kept the older style to prevent breaking of existing tests with snapshots.
|
||||
It's recommend you update to the latest format.
|
||||
You can do this in your project's jest config file.
|
||||
Remove the snapshotFormat property and re-run tests with the --update-snapshot flag.
|
||||
More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format`);
|
||||
}
|
||||
|
||||
function addSnapshotOptionsToConfig(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
updateSnapshotExample: string
|
||||
) {
|
||||
const config = tree.read(configPath, 'utf-8');
|
||||
const hasSnapshotOptions = tsquery.query(
|
||||
config,
|
||||
`${TS_QUERY_JEST_CONFIG_PREFIX} > ObjectLiteralExpression PropertyAssignment:has(Identifier[name="snapshotFormat"])`
|
||||
);
|
||||
if (hasSnapshotOptions.length > 0) {
|
||||
return;
|
||||
}
|
||||
const updatedConfig = tsquery.replace(
|
||||
config,
|
||||
`${TS_QUERY_JEST_CONFIG_PREFIX} > ObjectLiteralExpression`,
|
||||
(node: ts.ObjectLiteralExpression) => {
|
||||
return `{
|
||||
${node.properties.map((p) => getNodeWithComments(config, p)).join(',\n')},
|
||||
/* TODO: Update to latest Jest snapshotFormat
|
||||
* By default Nx has kept the older style of Jest Snapshot formats
|
||||
* to prevent breaking of any existing tests with snapshots.
|
||||
* It's recommend you update to the latest format.
|
||||
* You can do this by removing snapshotFormat property
|
||||
* and running tests with --update-snapshot flag.
|
||||
* Example: ${updateSnapshotExample}
|
||||
* More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format
|
||||
*/
|
||||
snapshotFormat: { escapeString: true, printBasicPrototype: true }
|
||||
}`;
|
||||
},
|
||||
{ visitAllChildren: false }
|
||||
);
|
||||
|
||||
tree.write(configPath, updatedConfig);
|
||||
}
|
||||
|
||||
function hasPresetConfigured(tree: Tree, configPath: string): boolean {
|
||||
const contents = tree.read(configPath, 'utf-8');
|
||||
|
||||
return (
|
||||
tsquery.query(
|
||||
contents,
|
||||
`${TS_QUERY_JEST_CONFIG_PREFIX} > ObjectLiteralExpression PropertyAssignment:has(Identifier[name="preset"])`
|
||||
)?.length > 0
|
||||
);
|
||||
}
|
||||
|
||||
function updateTsJestOptions(tree: Tree, configPath: string) {
|
||||
// query for the globals property, if they don't have one then there's nothing to modify.
|
||||
const contents = tree.read(configPath, 'utf-8');
|
||||
let tsJestGlobalsConfig: string;
|
||||
const noTsJestGlobals = tsquery.replace(
|
||||
contents,
|
||||
`${TS_QUERY_JEST_CONFIG_PREFIX} > ObjectLiteralExpression PropertyAssignment:has(Identifier[name="globals"])`,
|
||||
(node: ts.PropertyAssignment) => {
|
||||
if (tsJestGlobalsConfig) {
|
||||
logger.warn(
|
||||
stripIndents`Found more than one "globals" object in the jest config, ${configPath}
|
||||
Will use the first one`
|
||||
);
|
||||
return;
|
||||
}
|
||||
tsJestGlobalsConfig = getGlobalTsJestConfig(node);
|
||||
return getGlobalConfigWithoutTsJest(node);
|
||||
}
|
||||
);
|
||||
|
||||
if (!tsJestGlobalsConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedTsJestTransformer = tsquery.replace(
|
||||
noTsJestGlobals,
|
||||
`${TS_QUERY_JEST_CONFIG_PREFIX}> ObjectLiteralExpression PropertyAssignment:has(Identifier[name="transform"]) PropertyAssignment > :has(StringLiteral[value="ts-jest"], StringLiteral[value="jest-preset-angular"])`,
|
||||
(node: ts.StringLiteral) => {
|
||||
return `[${node.getText()}, ${tsJestGlobalsConfig}]`;
|
||||
}
|
||||
);
|
||||
|
||||
tree.write(configPath, updatedTsJestTransformer);
|
||||
}
|
||||
|
||||
function updateNgJestOptions(tree: Tree, configPath: string) {
|
||||
const contents = tree.read(configPath, 'utf-8');
|
||||
|
||||
let ngJestTeardownConfig: string;
|
||||
const noTeardownConfig = tsquery.replace(
|
||||
contents,
|
||||
'BinaryExpression:has(PropertyAccessExpression:has(Identifier[name=ngJest])) PropertyAssignment:has(Identifier[name=teardown])',
|
||||
(node: ts.PropertyAssignment) => {
|
||||
ngJestTeardownConfig = node.initializer.getText();
|
||||
return ' ';
|
||||
}
|
||||
);
|
||||
|
||||
if (!ngJestTeardownConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
let maybeUpdatedTestEnvOpts = tsquery.replace(
|
||||
noTeardownConfig,
|
||||
`${TS_QUERY_JEST_CONFIG_PREFIX} > ObjectLiteralExpression PropertyAssignment:has(Identifier[name="testEnvironmentOptions"]) ObjectLiteralExpression`,
|
||||
(node: ts.ObjectLiteralExpression) => {
|
||||
return `{
|
||||
${node.properties
|
||||
.map((p) => getNodeWithComments(noTeardownConfig, p))
|
||||
.join(',\n')},
|
||||
teardown: ${ngJestTeardownConfig}
|
||||
}`;
|
||||
}
|
||||
);
|
||||
|
||||
if (maybeUpdatedTestEnvOpts !== noTeardownConfig) {
|
||||
tree.write(configPath, maybeUpdatedTestEnvOpts);
|
||||
return;
|
||||
}
|
||||
// didn't find existing testEnvironmentOptions, so add the new property
|
||||
|
||||
const updatedConfig = tsquery.replace(
|
||||
maybeUpdatedTestEnvOpts,
|
||||
`${TS_QUERY_JEST_CONFIG_PREFIX} > ObjectLiteralExpression`,
|
||||
(node: ts.ObjectLiteralExpression) => {
|
||||
return `{
|
||||
${node.properties
|
||||
.map((p) => getNodeWithComments(maybeUpdatedTestEnvOpts, p))
|
||||
.join(',\n')},
|
||||
testEnvironmentOptions: { teardown: ${ngJestTeardownConfig} },
|
||||
}`;
|
||||
},
|
||||
{ visitAllChildren: false }
|
||||
);
|
||||
tree.write(configPath, updatedConfig);
|
||||
}
|
||||
|
||||
function getGlobalTsJestConfig(node: ts.PropertyAssignment): string {
|
||||
const globalObject = node.initializer as ts.ObjectLiteralExpression;
|
||||
const foundConfig = globalObject.properties.find(
|
||||
(p) => ts.isPropertyAssignment(p) && p.name.getText().includes('ts-jest')
|
||||
) as ts.PropertyAssignment;
|
||||
|
||||
return foundConfig?.initializer?.getText() || '';
|
||||
}
|
||||
|
||||
function getGlobalConfigWithoutTsJest(node: ts.PropertyAssignment): string {
|
||||
const globalObject = node?.initializer as ts.ObjectLiteralExpression;
|
||||
const withoutTsJest = globalObject?.properties?.filter((p) => {
|
||||
return !(
|
||||
ts.isPropertyAssignment(p) && p.name.getText().includes('ts-jest')
|
||||
);
|
||||
});
|
||||
|
||||
const globalConfigs = withoutTsJest.map((c) => c.getText()).join(',\n');
|
||||
return `globals: { ${globalConfigs} }`;
|
||||
}
|
||||
|
||||
function getNodeWithComments(fullText: string, node: ts.Node) {
|
||||
const commentRanges = ts.getLeadingCommentRanges(
|
||||
fullText,
|
||||
node.getFullStart()
|
||||
);
|
||||
|
||||
if (commentRanges?.length > 0) {
|
||||
const withComments = `${commentRanges
|
||||
.map((r) => fullText.slice(r.pos, r.end))
|
||||
.join('\n')}\n${node.getText()}`;
|
||||
return withComments;
|
||||
}
|
||||
return node.getText();
|
||||
}
|
||||
export default updateConfigsJest29;
|
||||
@ -0,0 +1,97 @@
|
||||
import {
|
||||
createProjectGraphAsync,
|
||||
formatFiles,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
visitNotIgnoredFiles,
|
||||
} from '@nrwl/devkit';
|
||||
import { JestExecutorOptions } from '@nrwl/jest/src/executors/jest/schema';
|
||||
import { TEST_FILE_PATTERN } from '@nrwl/jest/src/utils/ast-utils';
|
||||
import { forEachExecutorOptionsInGraph } from '@nrwl/workspace/src/utilities/executor-options-utils';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
import {
|
||||
CallExpression,
|
||||
ImportDeclaration,
|
||||
VariableStatement,
|
||||
} from 'typescript';
|
||||
|
||||
// NOTE: this is a copy of the @nrwl/jest v15.8.0 migrations
|
||||
export async function updateTestsJest29(tree: Tree) {
|
||||
const graph = await createProjectGraphAsync();
|
||||
forEachExecutorOptionsInGraph<JestExecutorOptions>(
|
||||
graph,
|
||||
'@nrwl/nx-plugin:e2e',
|
||||
(options, projectName) => {
|
||||
const projectConfig = readProjectConfiguration(tree, projectName);
|
||||
visitNotIgnoredFiles(
|
||||
tree,
|
||||
projectConfig.sourceRoot || projectConfig.root,
|
||||
(file) => {
|
||||
if (!TEST_FILE_PATTERN.test(file)) {
|
||||
return;
|
||||
}
|
||||
updateJestMockTypes(tree, file);
|
||||
updateJestMocked(tree, file);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
export function updateJestMockTypes(tree: Tree, filePath: string) {
|
||||
const contents = tree.read(filePath, 'utf-8');
|
||||
const updatedContent = tsquery.replace(
|
||||
contents,
|
||||
':matches(ImportDeclaration, VariableStatement):has(Identifier[name="MaybeMockedDeep"], Identifier[name="MaybeMocked"]):has(StringLiteral[value="jest-mock"])',
|
||||
(node: ImportDeclaration | VariableStatement) => {
|
||||
const text = node.getText();
|
||||
return (
|
||||
text
|
||||
// MaybeMockedDeep and MaybeMocked now are exported as Mocked and MockedShallow
|
||||
.replace('MaybeMockedDeep', 'Mocked')
|
||||
.replace('MaybeMocked', 'MockedShallow')
|
||||
);
|
||||
}
|
||||
);
|
||||
tree.write(filePath, updatedContent);
|
||||
}
|
||||
|
||||
export function updateJestMocked(tree: Tree, filePath: string) {
|
||||
const contents = tree.read(filePath, 'utf-8');
|
||||
const jestGlobalNodes = tsquery.query(
|
||||
contents,
|
||||
':matches(ImportDeclaration, VariableStatement):has(Identifier[name="jest"]):has(StringLiteral[value="@jest/globals"])'
|
||||
);
|
||||
|
||||
// this only applies if using jest from @jest/globals
|
||||
if (jestGlobalNodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedJestMockTypes = tsquery.replace(
|
||||
contents,
|
||||
'CallExpression:has(Identifier[name="jest"]):has(Identifier[name="mocked"])',
|
||||
(node: CallExpression) => {
|
||||
if (
|
||||
node.arguments.length === 2 &&
|
||||
node.getText().startsWith('jest.mocked(')
|
||||
) {
|
||||
const text = node.getText();
|
||||
// jest.mocked(someObject, true); => jest.mocked(someObject);
|
||||
if (node.arguments[1].getText() === 'true') {
|
||||
return text.replace(/,\s*true/g, '');
|
||||
}
|
||||
// jest.mocked(someObject, false); => jest.mocked(someObject, {shallow: true});
|
||||
// opt into the new behavior unless explicitly opting out
|
||||
if (node.arguments[1].getText() === 'false') {
|
||||
return text.replace('false', '{shallow: true}');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
tree.write(filePath, updatedJestMockTypes);
|
||||
}
|
||||
|
||||
export default updateTestsJest29;
|
||||
@ -0,0 +1,464 @@
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import {
|
||||
ProjectGraph,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
updateProjectConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
import { updateConfigsJest29 } from './jest-29-configs';
|
||||
import { libraryGenerator } from '@nrwl/workspace';
|
||||
|
||||
let projectGraph: ProjectGraph;
|
||||
jest.mock('@nrwl/devkit', () => ({
|
||||
...jest.requireActual<any>('@nrwl/devkit'),
|
||||
createProjectGraphAsync: jest.fn().mockImplementation(async () => {
|
||||
return projectGraph;
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('Nx Plugin Migration - jest 29 update configs', () => {
|
||||
let tree: Tree;
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
it('should update jest.config.ts', async () => {
|
||||
await setup(tree, 'my-lib');
|
||||
|
||||
await updateConfigsJest29(tree);
|
||||
|
||||
const actualJestConfigTs = tree.read('libs/my-lib/jest.config.ts', 'utf-8');
|
||||
expect(actualJestConfigTs).toMatchSnapshot();
|
||||
const actualJestConfigJs = tree.read('libs/my-lib/jest.config.js', 'utf-8');
|
||||
expect(actualJestConfigJs).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should update root preset', async () => {
|
||||
await setup(tree, 'my-lib');
|
||||
await updateConfigsJest29(tree);
|
||||
|
||||
const actualPreset = tree.read('jest.preset.js', 'utf-8');
|
||||
expect(actualPreset).toMatchSnapshot();
|
||||
const actualJestConfigTs = tree.read('libs/my-lib/jest.config.ts', 'utf-8');
|
||||
expect(actualJestConfigTs).toMatchSnapshot();
|
||||
const actualJestConfigJs = tree.read('libs/my-lib/jest.config.js', 'utf-8');
|
||||
expect(actualJestConfigJs).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should update root preset if ts-jest is preset', async () => {
|
||||
await setup(tree, 'my-lib');
|
||||
tree.write(
|
||||
'jest.preset.js',
|
||||
`const nxPreset = require('@nrwl/jest/preset').default;
|
||||
module.exports = {
|
||||
...nxPreset,
|
||||
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
},
|
||||
something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}]
|
||||
},
|
||||
transform: {
|
||||
'^.+\\.(ts|js|html)$': 'ts-jest',
|
||||
},
|
||||
resolver: '@nrwl/jest/plugins/resolver',
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageReporters: ['html'],
|
||||
};
|
||||
`
|
||||
);
|
||||
|
||||
await updateConfigsJest29(tree);
|
||||
|
||||
const actualPreset = tree.read('jest.preset.js', 'utf-8');
|
||||
expect(actualPreset).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should NOT update ts-jest with no globals are preset', async () => {
|
||||
await setup(tree, 'my-lib');
|
||||
tree.write(
|
||||
'jest.preset.js',
|
||||
`const nxPreset = require('@nrwl/jest/preset').default;
|
||||
module.exports = {
|
||||
...nxPreset,
|
||||
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
|
||||
transform: {
|
||||
'^.+\\.(ts|js|html)$': 'ts-jest',
|
||||
},
|
||||
resolver: '@nrwl/jest/plugins/resolver',
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageReporters: ['html'],
|
||||
};
|
||||
`
|
||||
);
|
||||
|
||||
await updateConfigsJest29(tree);
|
||||
|
||||
const actualPreset = tree.read('jest.preset.js', 'utf-8');
|
||||
expect(actualPreset).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should add snapshot config with no root preset', async () => {
|
||||
await setup(tree, 'my-lib');
|
||||
|
||||
tree.delete('jest.preset.js');
|
||||
|
||||
await updateConfigsJest29(tree);
|
||||
|
||||
const actualJestConfigTs = tree.read('libs/my-lib/jest.config.ts', 'utf-8');
|
||||
expect(actualJestConfigTs).toMatchSnapshot();
|
||||
const actualJestConfigJs = tree.read('libs/my-lib/jest.config.js', 'utf-8');
|
||||
expect(actualJestConfigJs).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should work with multiple projects + configs', async () => {
|
||||
await setup(tree, 'my-lib');
|
||||
await setup(tree, 'another-lib', projectGraph);
|
||||
await updateConfigsJest29(tree);
|
||||
|
||||
const actualJestConfigTs1 = tree.read(
|
||||
'libs/my-lib/jest.config.ts',
|
||||
'utf-8'
|
||||
);
|
||||
expect(actualJestConfigTs1).toMatchSnapshot();
|
||||
const actualJestConfigJs1 = tree.read(
|
||||
'libs/my-lib/jest.config.js',
|
||||
'utf-8'
|
||||
);
|
||||
expect(actualJestConfigJs1).toMatchSnapshot();
|
||||
|
||||
const actualJestConfigTs2 = tree.read(
|
||||
'libs/another-lib/jest.config.ts',
|
||||
'utf-8'
|
||||
);
|
||||
expect(actualJestConfigTs2).toMatchSnapshot();
|
||||
const actualJestConfigJs2 = tree.read(
|
||||
'libs/another-lib/jest.config.js',
|
||||
'utf-8'
|
||||
);
|
||||
expect(actualJestConfigJs2).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should update globalThis.ngJest.teardown to testEnvironmentOptions ', async () => {
|
||||
await setup(tree, 'jest-preset-angular');
|
||||
tree.write(
|
||||
`libs/jest-preset-angular/jest.config.ts`,
|
||||
`globalThis.ngJest = {
|
||||
teardown: true
|
||||
}
|
||||
|
||||
export default {
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
}
|
||||
},
|
||||
transform: {
|
||||
'^.+.(ts|mjs|js|html)$': 'jest-preset-angular',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};`
|
||||
);
|
||||
tree.write(
|
||||
`libs/jest-preset-angular/jest.config.js`,
|
||||
`
|
||||
globalThis.ngJest = {
|
||||
ngcc: true,
|
||||
teardown: false
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
}
|
||||
},
|
||||
transform: {
|
||||
'^.+.(ts|mjs|js|html)$': 'jest-preset-angular',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
testEnvironmentOptions: {
|
||||
blah: 123,
|
||||
},
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};`
|
||||
);
|
||||
await updateConfigsJest29(tree);
|
||||
const jpaJestConfigTs = tree.read(
|
||||
`libs/jest-preset-angular/jest.config.ts`,
|
||||
'utf-8'
|
||||
);
|
||||
expect(jpaJestConfigTs).toMatchSnapshot();
|
||||
const jpaJestConfigJs = tree.read(
|
||||
`libs/jest-preset-angular/jest.config.js`,
|
||||
'utf-8'
|
||||
);
|
||||
expect(jpaJestConfigJs).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should work with jest-preset-angular', async () => {
|
||||
await setup(tree, 'jest-preset-angular');
|
||||
tree.write(
|
||||
`libs/jest-preset-angular/jest.config.ts`,
|
||||
`export default {
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
}
|
||||
},
|
||||
transform: {
|
||||
'^.+.(ts|mjs|js|html)$': 'jest-preset-angular',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};`
|
||||
);
|
||||
tree.write(
|
||||
`libs/jest-preset-angular/jest.config.js`,
|
||||
`module.exports = {
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
}
|
||||
},
|
||||
transform: {
|
||||
'^.+.(ts|mjs|js|html)$': 'jest-preset-angular',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};`
|
||||
);
|
||||
await updateConfigsJest29(tree);
|
||||
const jpaJestConfigTs = tree.read(
|
||||
`libs/jest-preset-angular/jest.config.ts`,
|
||||
'utf-8'
|
||||
);
|
||||
expect(jpaJestConfigTs).toMatchSnapshot();
|
||||
const jpaJestConfigJs = tree.read(
|
||||
`libs/jest-preset-angular/jest.config.js`,
|
||||
'utf-8'
|
||||
);
|
||||
expect(jpaJestConfigJs).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should work if not using ts-jest transformer', async () => {
|
||||
await setup(tree, 'no-ts-jest');
|
||||
tree.write(
|
||||
`libs/no-ts-jest/jest.config.ts`,
|
||||
`export default {
|
||||
transform: {
|
||||
'^.+\\\\.[tj]sx?$': 'babel-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};`
|
||||
);
|
||||
tree.write(
|
||||
`libs/no-ts-jest/jest.config.js`,
|
||||
`module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\.[tj]sx?$': 'babel-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
};`
|
||||
);
|
||||
|
||||
await updateConfigsJest29(tree);
|
||||
const noTsJestConfigTs = tree.read(
|
||||
`libs/no-ts-jest/jest.config.ts`,
|
||||
'utf-8'
|
||||
);
|
||||
expect(noTsJestConfigTs).toMatchSnapshot();
|
||||
const noTsJestConfigJs = tree.read(
|
||||
`libs/no-ts-jest/jest.config.js`,
|
||||
'utf-8'
|
||||
);
|
||||
expect(noTsJestConfigJs).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should work snapshotFormat is defined', async () => {
|
||||
await setup(tree, 'no-ts-jest');
|
||||
tree.write(
|
||||
`libs/no-ts-jest/jest.config.ts`,
|
||||
`export default {
|
||||
transform: {
|
||||
'^.+\\\\.[tj]sx?$': 'babel-jest',
|
||||
},
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
},
|
||||
something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}]
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
snapshotFormat: {escapeString: false, printBasicPrototype: true}
|
||||
};`
|
||||
);
|
||||
tree.write(
|
||||
`libs/no-ts-jest/jest.config.js`,
|
||||
`module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\.[tj]sx?$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html']
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
},
|
||||
something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}]
|
||||
},
|
||||
snapshotFormat: {escapeString: false, printBasicPrototype: true}
|
||||
};`
|
||||
);
|
||||
|
||||
await updateConfigsJest29(tree);
|
||||
const snapshotJestConfigTs = tree.read(
|
||||
'libs/no-ts-jest/jest.config.ts',
|
||||
'utf-8'
|
||||
);
|
||||
expect(snapshotJestConfigTs).toMatchSnapshot();
|
||||
const snapshotJestConfigJs = tree.read(
|
||||
`libs/no-ts-jest/jest.config.js`,
|
||||
'utf-8'
|
||||
);
|
||||
expect(snapshotJestConfigJs).toMatchSnapshot();
|
||||
});
|
||||
it('should be idempotent', async () => {
|
||||
await setup(tree, 'my-lib');
|
||||
|
||||
await updateConfigsJest29(tree);
|
||||
|
||||
const actualJestConfigTs1 = tree.read(
|
||||
'libs/my-lib/jest.config.ts',
|
||||
'utf-8'
|
||||
);
|
||||
expect(actualJestConfigTs1).toMatchSnapshot();
|
||||
const actualJestConfigJs1 = tree.read(
|
||||
'libs/my-lib/jest.config.js',
|
||||
'utf-8'
|
||||
);
|
||||
expect(actualJestConfigJs1).toMatchSnapshot();
|
||||
|
||||
await updateConfigsJest29(tree);
|
||||
|
||||
const actualJestConfigTs2 = tree.read(
|
||||
'libs/my-lib/jest.config.ts',
|
||||
'utf-8'
|
||||
);
|
||||
expect(actualJestConfigTs2).toEqual(actualJestConfigTs1);
|
||||
const actualJestConfigJs2 = tree.read(
|
||||
'libs/my-lib/jest.config.js',
|
||||
'utf-8'
|
||||
);
|
||||
expect(actualJestConfigJs2).toEqual(actualJestConfigJs1);
|
||||
});
|
||||
});
|
||||
|
||||
async function setup(tree: Tree, name: string, existingGraph?: ProjectGraph) {
|
||||
await libraryGenerator(tree, {
|
||||
name,
|
||||
});
|
||||
const projectConfig = readProjectConfiguration(tree, name);
|
||||
projectConfig.targets['test'] = {
|
||||
...projectConfig.targets['test'],
|
||||
executor: '@nrwl/nx-plugin:e2e',
|
||||
configurations: {
|
||||
ci: {
|
||||
ci: true,
|
||||
},
|
||||
other: {
|
||||
jestConfig: `libs/${name}/jest.config.js`,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
updateProjectConfiguration(tree, name, projectConfig);
|
||||
tree.write(
|
||||
`libs/${name}/jest.config.ts`,
|
||||
`/* eslint-disable */
|
||||
export default {
|
||||
displayName: '${name}',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
}
|
||||
},
|
||||
transform: {
|
||||
'^.+\\\\.[tj]sx?$': 'ts-jest'
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/libs/${name}'
|
||||
};
|
||||
`
|
||||
);
|
||||
|
||||
tree.write(
|
||||
`libs/${name}/jest.config.js`,
|
||||
`module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\.[tj]sx?$': 'ts-jest'
|
||||
},
|
||||
// I am a comment and shouldn't be removed
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
},
|
||||
something: 'else',
|
||||
abc: [1234, true, {abc: 'yes'}]
|
||||
},
|
||||
/**
|
||||
* Multi-line comment shouldn't be removed
|
||||
*/
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js'
|
||||
};
|
||||
`
|
||||
);
|
||||
|
||||
projectGraph = {
|
||||
dependencies: {
|
||||
...existingGraph?.dependencies,
|
||||
},
|
||||
nodes: {
|
||||
...existingGraph?.nodes,
|
||||
[name]: {
|
||||
name,
|
||||
type: 'lib',
|
||||
data: projectConfig,
|
||||
} as any,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,181 @@
|
||||
import {
|
||||
ProjectGraph,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
updateProjectConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import { libraryGenerator } from '@nrwl/workspace';
|
||||
import { updateTestsJest29 } from './jest-29-tests';
|
||||
|
||||
let projectGraph: ProjectGraph;
|
||||
jest.mock('@nrwl/devkit', () => ({
|
||||
...jest.requireActual<any>('@nrwl/devkit'),
|
||||
createProjectGraphAsync: jest
|
||||
.fn()
|
||||
.mockImplementation(async () => projectGraph),
|
||||
}));
|
||||
describe('Nx Plugin Migration - jest 29 mocked usage in tests', () => {
|
||||
let tree: Tree;
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
});
|
||||
|
||||
it('should not update anything if there are no tests', async () => {
|
||||
await setup(tree, 'my-lib');
|
||||
const expected = tree.read('libs/my-lib/src/lib/my-lib.spec.ts', 'utf-8');
|
||||
await updateTestsJest29(tree);
|
||||
expect(
|
||||
tree.read('libs/my-lib/src/file-one.spec.ts', 'utf-8')
|
||||
).toMatchSnapshot();
|
||||
expect(
|
||||
tree.read('libs/my-lib/src/file-two.spec.ts', 'utf-8')
|
||||
).toMatchSnapshot();
|
||||
expect(tree.read('libs/my-lib/src/lib/my-lib.spec.ts', 'utf-8')).toEqual(
|
||||
expected
|
||||
);
|
||||
});
|
||||
it('should be idempotent', async () => {
|
||||
await setup(tree, 'my-lib');
|
||||
|
||||
const expected = tree.read('libs/my-lib/src/lib/my-lib.spec.ts', 'utf-8');
|
||||
|
||||
await updateTestsJest29(tree);
|
||||
|
||||
expect(
|
||||
tree.read('libs/my-lib/src/file-one.spec.ts', 'utf-8')
|
||||
).toMatchSnapshot();
|
||||
expect(
|
||||
tree.read('libs/my-lib/src/file-two.spec.ts', 'utf-8')
|
||||
).toMatchSnapshot();
|
||||
expect(tree.read('libs/my-lib/src/lib/my-lib.spec.ts', 'utf-8')).toEqual(
|
||||
expected
|
||||
);
|
||||
|
||||
await updateTestsJest29(tree);
|
||||
|
||||
expect(
|
||||
tree.read('libs/my-lib/src/file-one.spec.ts', 'utf-8')
|
||||
).toMatchSnapshot();
|
||||
expect(
|
||||
tree.read('libs/my-lib/src/file-two.spec.ts', 'utf-8')
|
||||
).toMatchSnapshot();
|
||||
expect(tree.read('libs/my-lib/src/lib/my-lib.spec.ts', 'utf-8')).toEqual(
|
||||
expected
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
async function setup(tree: Tree, name: string) {
|
||||
await libraryGenerator(tree, {
|
||||
name,
|
||||
});
|
||||
const projectConfig = readProjectConfiguration(tree, name);
|
||||
projectConfig.targets['test'] = {
|
||||
...projectConfig.targets['test'],
|
||||
configurations: {
|
||||
ci: {
|
||||
ci: true,
|
||||
},
|
||||
other: {
|
||||
jestConfig: `libs/${name}/jest.config.js`,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
updateProjectConfiguration(tree, name, projectConfig);
|
||||
|
||||
tree.write(
|
||||
`libs/${name}/jest.config.js`,
|
||||
`module.exports = {
|
||||
transform: {
|
||||
'^.+\\\\.[tj]sx?$': 'ts-jest'
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json'
|
||||
}
|
||||
},
|
||||
displayName: 'jest',
|
||||
testEnvironment: 'node',
|
||||
preset: '../../jest.preset.js'
|
||||
};
|
||||
|
||||
`
|
||||
);
|
||||
tree.write(
|
||||
`libs/${name}/src/file-one.spec.ts`,
|
||||
`
|
||||
import{ MaybeMockedDeep, MaybeMocked } from 'jest-mock';
|
||||
import {expect, jest, test} from '@jest/globals';
|
||||
import {song} from './song';
|
||||
|
||||
jest.mock('./song');
|
||||
jest.spyOn(console, 'log');
|
||||
|
||||
const mockedSong = jest.mocked(song, true);
|
||||
// or through \`jest.Mocked<Source>\`
|
||||
// const mockedSong = song as jest.Mocked<typeof song>;
|
||||
|
||||
test('deep method is typed correctly', () => {
|
||||
mockedSong.one.more.time.mockReturnValue(12);
|
||||
|
||||
expect(mockedSong.one.more.time(10)).toBe(12);
|
||||
expect(mockedSong.one.more.time.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('direct usage', () => {
|
||||
jest.mocked(console.log).mockImplementation(() => {
|
||||
return;
|
||||
});
|
||||
|
||||
console.log('one more time');
|
||||
|
||||
expect(jest.mocked(console.log, false).mock.calls).toHaveLength(1);
|
||||
});
|
||||
`
|
||||
);
|
||||
tree.write(
|
||||
`libs/${name}/src/file-two.spec.ts`,
|
||||
`
|
||||
const { MaybeMockedDeep, MaybeMocked } = require('jest-mock');
|
||||
const {expect, jest, test} = require('@jest/globals');
|
||||
const {song} = require('./song');
|
||||
|
||||
jest.mock('./song');
|
||||
jest.spyOn(console, 'log');
|
||||
|
||||
const mockedSong = jest.mocked(song, true);
|
||||
// or through \`jest.Mocked<Source>\`
|
||||
// const mockedSong = song as jest.Mocked<typeof song>;
|
||||
|
||||
test('deep method is typed correctly', () => {
|
||||
mockedSong.one.more.time.mockReturnValue(12);
|
||||
|
||||
expect(mockedSong.one.more.time(10)).toBe(12);
|
||||
expect(mockedSong.one.more.time.mock.calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('direct usage', () => {
|
||||
jest.mocked(console.log).mockImplementation(() => {
|
||||
return;
|
||||
});
|
||||
|
||||
console.log('one more time');
|
||||
|
||||
expect(jest.mocked(console.log, false).mock.calls).toHaveLength(1);
|
||||
});
|
||||
`
|
||||
);
|
||||
projectGraph = {
|
||||
dependencies: {},
|
||||
nodes: {
|
||||
[name]: {
|
||||
name,
|
||||
type: 'lib',
|
||||
data: projectConfig,
|
||||
} as any,
|
||||
},
|
||||
};
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user