Skip to content

Commit

Permalink
chore(ci): refactor ts-node compatibility tests (jestjs#12834)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrazauskas authored May 11, 2022
1 parent 21b32ab commit e0cb576
Show file tree
Hide file tree
Showing 8 changed files with 234 additions and 57 deletions.
12 changes: 7 additions & 5 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ jobs:
YARN_ENABLE_SCRIPTS: false
run: yarn --immutable

typecheck:
name: Running TypeScript compiler
ts-compatibility:
name: TypeScript Compatibility
runs-on: ubuntu-latest
needs: prepare-yarn-cache

Expand All @@ -53,13 +53,15 @@ jobs:
run: yarn --immutable
- name: build
run: yarn build
- name: test typings
run: yarn test-types
- name: ts integration
run: yarn test-ts --selectProjects ts-integration
- name: type tests
run: yarn test-ts --selectProjects type-tests
- name: verify TypeScript@4.3 compatibility
run: yarn verify-old-ts

lint:
name: Running Lint
name: Lint
runs-on: ubuntu-latest
needs: prepare-yarn-cache

Expand Down
37 changes: 8 additions & 29 deletions e2e/__tests__/esmConfigFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/

import {resolve} from 'path';
import execa = require('execa');
import {existsSync} from 'graceful-fs';
import {onNodeVersions} from '@jest/test-utils';
import {getConfig} from '../runJest';

Expand Down Expand Up @@ -48,33 +45,15 @@ onNodeVersions('>=12.17.0', () => {
});
});

describe('typescript', () => {
beforeAll(async () => {
// the typescript config test needs `@jest/types` to be built
const cwd = resolve(__dirname, '../../');
const typesPackageDirectory = 'packages/jest-types';

const indexDTsFile = resolve(
cwd,
typesPackageDirectory,
'build/index.d.ts',
);

if (!existsSync(indexDTsFile)) {
await execa('tsc', ['-b', typesPackageDirectory], {cwd});
}
}, 360_000);

test('reads config from ts file when package.json#type=module', () => {
const {configs} = getConfig('esm-config/ts', [], {
skipPkgJsonCheck: true,
});
test('reads config from ts file when package.json#type=module', () => {
const {configs} = getConfig('esm-config/ts', [], {
skipPkgJsonCheck: true,
});

expect(configs).toHaveLength(1);
expect(configs[0].displayName).toEqual({
color: 'white',
name: 'Config from ts file',
});
expect(configs).toHaveLength(1);
expect(configs[0].displayName).toEqual({
color: 'white',
name: 'Config from ts file',
});
});
});
176 changes: 176 additions & 0 deletions e2e/__tests__/tsIntegration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import * as path from 'path';
import {onNodeVersions} from '@jest/test-utils';
import {cleanup, writeFiles} from '../Utils';
import runJest, {getConfig} from '../runJest';

const DIR = path.resolve(__dirname, '../ts-node-integration');

beforeEach(() => cleanup(DIR));
afterAll(() => cleanup(DIR));

describe('when `Config` type is imported from "@jest/types"', () => {
test('with object config exported from TS file', () => {
writeFiles(DIR, {
'__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));",
'jest.config.ts': `
import type {Config} from '@jest/types';
const config: Config.InitialOptions = {displayName: 'ts-object-config', verbose: true};
export default config;
`,
'package.json': '{}',
});

const {configs, globalConfig} = getConfig(path.join(DIR));

expect(configs).toHaveLength(1);
expect(configs[0].displayName?.name).toBe('ts-object-config');
expect(globalConfig.verbose).toBe(true);
});

test('with function config exported from TS file', () => {
writeFiles(DIR, {
'__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));",
'jest.config.ts': `
import type {Config} from '@jest/types';
async function getVerbose() {return true;}
export default async (): Promise<Config.InitialOptions> => {
const verbose: Config.InitialOptions['verbose'] = await getVerbose();
return {displayName: 'ts-async-function-config', verbose};
};
`,
'package.json': '{}',
});

const {configs, globalConfig} = getConfig(path.join(DIR));

expect(configs).toHaveLength(1);
expect(configs[0].displayName?.name).toBe('ts-async-function-config');
expect(globalConfig.verbose).toBe(true);
});

test('throws if type errors are encountered', () => {
writeFiles(DIR, {
'__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));",
'jest.config.ts': `
import type {Config} from '@jest/types';
const config: Config.InitialOptions = {testTimeout: '10000'};
export default config;
`,
'package.json': '{}',
});

const {stderr, exitCode} = runJest(DIR);

expect(stderr).toMatch(
"jest.config.ts(2,40): error TS2322: Type 'string' is not assignable to type 'number'.",
);
expect(exitCode).toBe(1);
});

test('throws if syntax errors are encountered', () => {
writeFiles(DIR, {
'__tests__/dummy.test.js': "test('dummy', () => expect(123).toBe(123));",
'jest.config.ts': `
import type {Config} from '@jest/types';
const config: Config.InitialOptions = {verbose: true};
export default get config;
`,
'package.json': '{}',
});

const {stderr, exitCode} = runJest(DIR);

expect(stderr).toMatch(
"jest.config.ts(3,16): error TS2304: Cannot find name 'get'.",
);
expect(exitCode).toBe(1);
});

// The versions where vm.Module exists and commonjs with "exports" is not broken
onNodeVersions('>=12.16.0', () => {
test('works with object config exported from TS file when package.json#type=module', () => {
writeFiles(DIR, {
'__tests__/dummy.test.js': "test('dummy', () => expect(12).toBe(12));",
'jest.config.ts': `
import type {Config} from '@jest/types';
const config: Config.InitialOptions = {displayName: 'ts-esm-object-config', verbose: true};
export default config;
`,
'package.json': '{"type": "module"}',
});

const {configs, globalConfig} = getConfig(path.join(DIR));

expect(configs).toHaveLength(1);
expect(configs[0].displayName?.name).toBe('ts-esm-object-config');
expect(globalConfig.verbose).toBe(true);
});

test('works with function config exported from TS file when package.json#type=module', () => {
writeFiles(DIR, {
'__tests__/dummy.test.js': "test('dummy', () => expect(12).toBe(12));",
'jest.config.ts': `
import type {Config} from '@jest/types';
async function getVerbose() {return true;}
export default async (): Promise<Config.InitialOptions> => {
const verbose: Config.InitialOptions['verbose'] = await getVerbose();
return {displayName: 'ts-esm-async-function-config', verbose};
};
`,
'package.json': '{"type": "module"}',
});

const {configs, globalConfig} = getConfig(path.join(DIR));

expect(configs).toHaveLength(1);
expect(configs[0].displayName?.name).toBe('ts-esm-async-function-config');
expect(globalConfig.verbose).toBe(true);
});

test('throws if type errors are encountered when package.json#type=module', () => {
writeFiles(DIR, {
'__tests__/dummy.test.js': "test('dummy', () => expect(12).toBe(12));",
'jest.config.ts': `
import type {Config} from '@jest/types';
const config: Config.InitialOptions = {testTimeout: '10000'};
export default config;
`,
'package.json': '{"type": "module"}',
});

const {stderr, exitCode} = runJest(DIR);

expect(stderr).toMatch(
"jest.config.ts(2,40): error TS2322: Type 'string' is not assignable to type 'number'.",
);
expect(exitCode).toBe(1);
});

test('throws if syntax errors are encountered when package.json#type=module', () => {
writeFiles(DIR, {
'__tests__/dummy.test.js':
"test('dummy', () => expect(123).toBe(123));",
'jest.config.ts': `
import type {Config} from '@jest/types';
const config: Config.InitialOptions = {verbose: true};
export default get config;
`,
'package.json': '{}',
});

const {stderr, exitCode} = runJest(DIR);

expect(stderr).toMatch(
"jest.config.ts(3,16): error TS2304: Cannot find name 'get'.",
);
expect(exitCode).toBe(1);
});
});
});
9 changes: 7 additions & 2 deletions e2e/esm-config/ts/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@
* LICENSE file in the root directory of this source tree.
*/

import type {Config} from '@jest/types';
// allows to make sure that `ts-node` compiles the config file without a need to build Jest types
// integration tests of Jest types run in a separate CI job through `jest.config.ts.mjs`
type DummyConfig = {
displayName: string;
testEnvironment: string;
};

const config: Config.InitialOptions = {
const config: DummyConfig = {
displayName: 'Config from ts file',
testEnvironment: 'node',
};
Expand Down
1 change: 1 addition & 0 deletions jest.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export default {
'/packages/jest-snapshot/src/__tests__/fixtures/',
'/packages/jest-validate/src/__tests__/fixtures/',
'/e2e/__tests__/iterator-to-null-test.ts',
'/e2e/__tests__/tsIntegration.test.ts', // this test needs types to be build, it runs in a separate CI job through `jest.config.ts.mjs`
],
testTimeout: 70000,
transform: {
Expand Down
33 changes: 33 additions & 0 deletions jest.config.ts.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import jestConfigBase from './jest.config.mjs';

export default {
projects: [
{
displayName: {
color: 'blue',
name: 'ts-integration',
},
modulePathIgnorePatterns: jestConfigBase.modulePathIgnorePatterns,
roots: ['<rootDir>/e2e/__tests__'],
testMatch: ['<rootDir>/e2e/__tests__/ts*'],
},
{
displayName: {
color: 'blue',
name: 'type-tests',
},
modulePathIgnorePatterns: jestConfigBase.modulePathIgnorePatterns,
roots: ['<rootDir>/packages'],
runner: 'jest-runner-tsd',
testMatch: ['**/__typetests__/**/*.ts'],
},
],
reporters: ['default', 'github-actions'],
};
20 changes: 0 additions & 20 deletions jest.config.tsd.mjs

This file was deleted.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@
"lint:prettier": "prettier . \"!**/*.{js,jsx,cjs,mjs,ts,tsx}\" --write",
"lint:prettier:ci": "prettier . \"!**/*.{js,jsx,cjs,mjs,ts,tsx}\" --check",
"remove-examples": "node ./scripts/remove-examples.mjs",
"test-types": "yarn jest --config jest.config.tsd.mjs",
"test-ci-partial": "yarn test-ci-partial:parallel -i",
"test-ci-partial:parallel": "yarn jest --color --config jest.config.ci.mjs",
"test-leak": "yarn jest -i --detectLeaks --color jest-mock jest-diff jest-repl pretty-format",
"test-ts": "yarn jest --config jest.config.ts.mjs",
"test-types": "yarn test-ts --selectProjects type-tests",
"test": "yarn lint && yarn jest",
"verify-old-ts": "node ./scripts/verifyOldTs.mjs",
"verify-pnp": "node ./scripts/verifyPnP.mjs",
Expand Down

0 comments on commit e0cb576

Please sign in to comment.