Skip to content

Commit

Permalink
feat(testing): support jest 28
Browse files Browse the repository at this point in the history
WIP jest migration
  • Loading branch information
barbados-clemens committed Jun 22, 2022
1 parent 40f8363 commit 8ff4fb6
Show file tree
Hide file tree
Showing 12 changed files with 21,938 additions and 14 deletions.
9 changes: 9 additions & 0 deletions packages/angular/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,15 @@
"alwaysAddToPackageJson": false
}
}
},
"14.4.0": {
"version": "14.4.0-beta.0",
"packages": {
"jest-preset-angular": {
"version": "~12.1.0",
"alwaysAddToPackageJson": false
}
}
}
}
}
33 changes: 33 additions & 0 deletions packages/jest/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@
"cli": "nx",
"description": "Update to export default in jest config and revert jest.preset.ts to jest.preset.js",
"factory": "./src/migrations/update-14-1-5/update-exports-jest-config"
},
"update-configs-jest-28": {
"version": "14.4.0-beta.0",
"cli": "nx",
"description": "Update jest configs to support jest 28 changes (https://jestjs.io/docs/upgrading-to-jest28#configuration-options)",
"factory": "./src/migrations/update-14-4-0/update-configs-jest-28"
},
"update-tests-jest-28": {
"version": "14.4.0-beta.0",
"cli": "nx",
"description": "Update jest test files to support jest 28 changes (https://jestjs.io/docs/upgrading-to-jest28)",
"factory": "./src/migrations/update-14-4-0/update-tests-jest-28"
}
},
"packageJsonUpdates": {
Expand Down Expand Up @@ -136,6 +148,27 @@
"alwaysAddToPackageJson": false
}
}
},
"14.4.0": {
"version": "14.4.0-beta.0",
"packages": {
"jest": {
"version": "~28.1.1",
"alwaysAddToPackageJson": false
},
"@types/jest": {
"version": "~28.1.1",
"alwaysAddToPackageJson": false
},
"ts-jest": {
"version": "~28.0.5",
"alwaysAddToPackageJson": false
},
"babel-jest": {
"version": "~28.1.1",
"alwaysAddToPackageJson": false
}
}
}
}
}
10 changes: 5 additions & 5 deletions packages/jest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@
"migrations": "./migrations.json"
},
"dependencies": {
"@jest/reporters": "27.5.1",
"@jest/test-result": "27.5.1",
"@jest/reporters": "28.1.1",
"@jest/test-result": "28.1.1",
"@nrwl/devkit": "file:../devkit",
"@phenomnomnominal/tsquery": "4.1.1",
"chalk": "4.1.0",
"identity-obj-proxy": "3.0.0",
"jest-config": "27.5.1",
"jest-resolve": "27.5.1",
"jest-util": "27.5.1",
"jest-config": "28.1.1",
"jest-resolve": "28.1.1",
"jest-util": "28.1.1",
"resolve.exports": "1.1.0",
"rxjs": "^6.5.4",
"tslib": "^2.3.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { readJson } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { libraryGenerator as workspaceLib } from '@nrwl/workspace';
import {
checkDeps,
updateConfigsJest28,
updateJestConfig,
} from './update-configs-jest-28';

const mockJestConfig = `
import { nxPreset } from '@nrwl/jest/preset'
const myGlobals = ['Math', 'Promise'];
export default {
...nxPreset,
displayName: 'test-ng-app',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
extraGlobals: ['Math', 'Something'],
extraGlobals: [],
extraGlobals: myGlobals,
timers: 'fake',
timers: 'modern',
timers: 'legacy',
timers: 'real',
testURL: 'http://localhost',
testURL: "123abc",
testURL: \`BLAH\`,
testEnvironment: 'jsdom',
testRunner: 'jest-jasmine2',
}
`;
describe('Jest Migration - jest 28 config support', () => {
it('should update "extraGlobals" config option', () => {
const actual = updateJestConfig(mockJestConfig);
expect(actual).not.toContain(`extraGlobals`);
expect(actual).toContain(`sandboxInjectedGlobals: ['Math', 'Something'],`);
expect(actual).toContain(`sandboxInjectedGlobals: [],`);
expect(actual).toContain(`sandboxInjectedGlobals: myGlobals,`);
});

it('should update "testURL" config option', () => {
const actual = updateJestConfig(mockJestConfig);
expect(actual).not.toContain(`testURL`);
expect(actual).toContain(
`testEnvironmentOptions: {url: 'http://localhost'},`
);
expect(actual).toContain(`testEnvironmentOptions: {url: "123abc"},`);
expect(actual).toContain(`testEnvironmentOptions: {url: \`BLAH\`},`);
});

it('should update "timers" config option', () => {
const actual = updateJestConfig(mockJestConfig);
expect(actual).not.toContain(`timers`);
expect(actual).toContain(`fakeTimers: { enableGlobally: false },`);
expect(actual).toContain(`fakeTimers: { enableGlobally: true },`);
expect(actual).toContain(`fakeTimers: { enableGlobally: true },`);
expect(actual).toContain(
`fakeTimers: { enableGlobally: true, legacyFakeTimers: true },`
);
});

it('should update jest-environment-jsdom if being used', async () => {
let tree = createTreeWithEmptyWorkspace(2);
tree.write(
`package.json`,
`{
"name": "jest-28-test",
"version": "0.0.0",
"license": "MIT",
"devDependencies": {
"jest": "^28.1.1",
"jest-environment-jsdom": "^27.1.0",
"jest-preset-angular": "^11.0.0",
"nx": "14.1.6",
"ts-jest": "^27.0.2",
"ts-node": "9.1.1",
"typescript": "~4.6.2"
},
"dependencies": {
}
}
`
);

const actual = checkDeps(tree);
expect(actual).toEqual({
'jest-environment-jsdom': '28.1.1',
});
});

it('should update jest-jasmine2 if being used as a test runner', () => {
let tree = createTreeWithEmptyWorkspace(2);
tree.write(
`package.json`,
`{
"name": "jest-28-test",
"version": "0.0.0",
"license": "MIT",
"devDependencies": {
"jest": "^27.1.1",
"jest-jasmine2": "^27.1.0",
"nx": "14.1.6",
"ts-jest": "^27.0.2",
"ts-node": "9.1.1",
"typescript": "~4.6.2"
},
"dependencies": {
}
}
`
);

const actual = checkDeps(tree);
expect(actual).toEqual({
'jest-jasmine2': '28.1.1',
});
});

it('should not install deps if they are not used', () => {
let tree = createTreeWithEmptyWorkspace(2);
tree.write(
`package.json`,
`{
"name": "jest-28-test",
"version": "0.0.0",
"license": "MIT",
"devDependencies": {
"jest": "^27.1.0",
"nx": "14.1.6",
"ts-jest": "^27.0.2",
"ts-node": "9.1.1",
"typescript": "~4.6.2"
},
"dependencies": {
}
}
`
);

const actual = checkDeps(tree);
expect(actual).toEqual({});
});

it('should update deps from jest.config.ts', async () => {
let tree = createTreeWithEmptyWorkspace(2);
await workspaceLib(tree, { name: 'my-lib', unitTestRunner: 'jest' });
tree.write(
'libs/my-lib/jest.config.ts',
`
export default {
displayName: 'test-ng-app',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {
'ts-jest': {
useESM: true,
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\\\.(html|svg)$',
},
},
testEnvironment: 'jsdom',
testRunner: 'jest-jasmine2',
coverageDirectory: '../../coverage/apps/test-ng-app',
transform: {
'^.+\\\\.(ts|mjs|js|html)$': 'jest-preset-angular',
},
transformIgnorePatterns: [
'node_modules/(?!.*\\\\.mjs$|rxjs)',
// 'node_modules/(?!rxjs)'
],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
}`
);
updateConfigsJest28(tree);

const packageJson = readJson(tree, 'package.json');
expect(packageJson.devDependencies).toEqual(
expect.objectContaining({
'jest-environment-jsdom': '28.1.1',
'jest-jasmine2': '28.1.1',
})
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { addDependenciesToPackageJson, readJson, Tree } from '@nrwl/devkit';
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
import { JestExecutorOptions } from '../../executors/jest/schema';
import {
findRootJestConfig,
findRootJestPreset,
} from '../../utils/config/find-root-jest-files';
import { jestVersion } from '../../utils/versions';

const JASMINE_TEST_RUNNER = /(testRunner:\s*['"`])(jest-jasmine2)(['"`])/g;

const JSDOM_TEST_ENV = /(testEnvironment:\s*['"`])(jsdom)(['"`])/g;

export function updateConfigsJest28(tree: Tree) {
let devDeps = checkDeps(tree);
forEachExecutorOptions<JestExecutorOptions>(
tree,
'@nrwl/jest:jest',
(options) => {
if (options.jestConfig && tree.exists(options.jestConfig)) {
const updatedConfig = updateJestConfig(
tree.read(options.jestConfig, 'utf-8')
);
tree.write(options.jestConfig, updatedConfig);

const projectConfigCheck = testFileForDep(updatedConfig);
devDeps = { ...devDeps, ...projectConfigCheck };
}
}
);

return addDependenciesToPackageJson(tree, {}, devDeps);
}

export function updateJestConfig(config: string): string {
return config
.replace(
/(testURL:\s*['"`])(.*)(['"`])/g,
'testEnvironmentOptions: {url: $3$2$3}'
)
.replace(/(extraGlobals)/g, `sandboxInjectedGlobals`)
.replace(
/(timers:\s*['"`])(real)(['"`])/g,
'fakeTimers: { enableGlobally: false }'
)
.replace(
/(timers:\s*['"`])(fake|modern)(['"`])/g,
'fakeTimers: { enableGlobally: true }'
)
.replace(
/(timers:\s*['"`])(legacy)(['"`])/g,
'fakeTimers: { enableGlobally: true, legacyFakeTimers: true }'
);
}

export function checkDeps(tree: Tree): Record<string, string> {
const packageJson = readJson(tree, 'package.json');
let devDeps = {};

if (packageJson.devDependencies['jest-jasmine2']) {
devDeps['jest-jasmine2'] = jestVersion;
}
if (
packageJson.devDependencies['jest-environment-jsdom'] ||
packageJson.devDependencies['jest-preset-angular']
) {
devDeps['jest-environment-jsdom'] = jestVersion;
}

const rootJestConfig = findRootJestConfig(tree);
if (rootJestConfig) {
const rootConfigCheck = testFileForDep(tree.read(rootJestConfig, 'utf-8'));
devDeps = { ...devDeps, ...rootConfigCheck };
}

const rootJestPreset = findRootJestPreset(tree);
if (rootJestPreset) {
const rootPresetCheck = testFileForDep(tree.read(rootJestPreset, 'utf-8'));
devDeps = { ...devDeps, ...rootPresetCheck };
}

return devDeps;
}

function testFileForDep(config: string): Record<string, string> {
const deps = {};
if (JASMINE_TEST_RUNNER.test(config)) {
deps['jest-jasmine2'] = jestVersion;
}
if (JSDOM_TEST_ENV.test(config)) {
deps['jest-environment-jsdom'] = jestVersion;
}
return deps;
}

export default updateConfigsJest28;

0 comments on commit 8ff4fb6

Please sign in to comment.