Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ci): refactor ts-node compatibility tests #12834

Merged
merged 4 commits into from
May 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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