Skip to content

Commit 0caa049

Browse files
authored
[UIE-136] Build test utils package (#4294)
1 parent 2b24c84 commit 0caa049

22 files changed

+256
-100
lines changed

.pnp.cjs

+89-18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.

jest.config.mjs

+14-9
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1-
import { baseConfig } from '@terra-ui-packages/test-utils';
1+
import { getJestConfig } from '@terra-ui-packages/test-utils';
2+
3+
const baseConfig = getJestConfig();
24

35
export default {
46
...baseConfig,
5-
'reporters': [
7+
reporters: [
68
'default',
7-
['jest-html-reporter', {
8-
'pageTitle': 'Test Report',
9-
'sort': 'status',
10-
'includeFailureMsg': true,
11-
'includeSuiteFailure': true,
12-
"outputPath": "test-report/index.html",
13-
}]
9+
[
10+
'jest-html-reporter',
11+
{
12+
pageTitle: 'Test Report',
13+
sort: 'status',
14+
includeFailureMsg: true,
15+
includeSuiteFailure: true,
16+
outputPath: 'test-report/index.html',
17+
},
18+
],
1419
],
1520
setupFilesAfterEnv: [...baseConfig.setupFilesAfterEnv, '<rootDir>/src/setupTests.ts'],
1621
};

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"analyze": "yarn build && source-map-explorer 'build/static/js/*.js' --gzip",
6868
"build": "yarn build-packages && yarn build-app",
6969
"build-app": "tsc && yarn save-build-info && vite build && rm build/config.json",
70-
"build-packages": "yarn workspaces foreach --include '@terra-ui-packages/*' --parallel run build",
70+
"build-packages": "yarn workspaces foreach --include '@terra-ui-packages/*' --parallel --topological-dev run build",
7171
"lint": "eslint --fix --max-warnings=0 .",
7272
"optimize-image-svgs": "svgo --enable=inlineStyles,prefixIds --config '{ \"plugins\": [ { \"inlineStyles\": { \"onlyMatchedOnce\": false } }] }' --pretty -f src/images -r -p 1 --multipass",
7373
"preinstall": "node .hooks/check-engine-light.js",

packages/components/jest.config.mjs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// ESLint thinks @terra-ui-packages/test-utils should be listed in dependencies instead of devDependencies.
22
// TODO: Fix this in ESLint configuration.
33
// eslint-disable-next-line import/no-extraneous-dependencies
4-
import { baseConfig } from '@terra-ui-packages/test-utils';
4+
import { getJestConfig } from '@terra-ui-packages/test-utils';
55

6-
export default baseConfig;
6+
export default getJestConfig();

packages/components/src/TooltipTrigger.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import { withFakeTimers } from '@terra-ui-packages/test-utils';
12
import { act, screen, within } from '@testing-library/react';
23
import userEvent from '@testing-library/user-event';
34
import { button, h } from 'react-hyperscript-helpers';
45

56
import { icon } from './icon';
67
import { getPopupRoot } from './internal/PopupPortal';
7-
import { renderWithTheme, withFakeTimers } from './internal/test-utils';
8+
import { renderWithTheme } from './internal/test-utils';
89
import { TooltipTrigger, TooltipTriggerProps } from './TooltipTrigger';
910

1011
describe('TooltipTrigger', () => {

packages/components/src/internal/test-utils.ts

-18
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,3 @@ export const TestThemeProvider = (props) => {
3131
export const renderWithTheme = (ui: ReactElement) => {
3232
return render(ui, { wrapper: TestThemeProvider });
3333
};
34-
35-
/**
36-
* Wrap a test function in useFakeTimers/useRealTimers.
37-
*/
38-
export const withFakeTimers =
39-
<F extends (...args: any[]) => any>(fn: F) =>
40-
(...args: Parameters<F>): ReturnType<F> => {
41-
try {
42-
jest.useFakeTimers();
43-
return fn(...args);
44-
} finally {
45-
// "It's important to also call runOnlyPendingTimers before switching to real timers.
46-
// This will ensure you flush all the pending timers before you switch to real timers."
47-
// -- https://testing-library.com/docs/using-fake-timers/
48-
jest.runOnlyPendingTimers();
49-
jest.useRealTimers();
50-
}
51-
};

packages/core-utils/jest.config.mjs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// ESLint thinks @terra-ui-packages/test-utils should be listed in dependencies instead of devDependencies.
22
// TODO: Fix this in ESLint configuration.
33
// eslint-disable-next-line import/no-extraneous-dependencies
4-
import { baseConfig } from '@terra-ui-packages/test-utils';
4+
import { getJestConfig } from '@terra-ui-packages/test-utils';
55

66
export default {
7-
...baseConfig,
7+
...getJestConfig(),
88
// Ignore type tests when calculating coverage.
99
coveragePathIgnorePatterns: ['\\.types\\.ts$', '\\.errors\\.ts$'],
1010
};

packages/test-utils/README.md

+1-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
11
# test-utils
22

3-
Shared configuration for testing packages with Jest.
4-
5-
Note that, unlike most packages, this package does not have a build process.
6-
Because the source files are directly exported, ES Modules are named with a
7-
`.mjs` extension to enforce fully specified imports within this package.
8-
9-
The files in src/transforms were originally generated by Create React App.
10-
Since they are CommonJS, they are named with a `.cjs` extension.
3+
Shared configuration and helpers for testing packages with Jest.

packages/test-utils/package.json

+26-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
11
{
22
"name": "@terra-ui-packages/test-utils",
3-
"version": "0.0.2",
3+
"version": "0.0.3",
4+
"scripts": {
5+
"build": "vite build --emptyOutDir",
6+
"dev": "vite build --mode=development --watch",
7+
"test": "yarn run build >/dev/null && jest"
8+
},
49
"type": "module",
5-
"module": "./src/index.mjs",
10+
"module": "./lib/es/index.js",
11+
"main": "./lib/cjs/index.cjs",
12+
"types": "./lib/types/index.d.ts",
613
"exports": {
714
".": {
8-
"import": "./src/index.mjs"
15+
"import": "./lib/es/index.js",
16+
"require": "./lib/cjs/index.cjs",
17+
"types": "./lib/types/index.d.ts"
918
}
1019
},
11-
"scripts": {
12-
"build": "true"
13-
},
20+
"files": [
21+
"lib/cjs/**",
22+
"lib/es/**",
23+
"lib/types/**",
24+
"transforms/**"
25+
],
1426
"dependencies": {
1527
"@babel/core": "^7.16.0",
1628
"@testing-library/jest-dom": "^5.17.0",
@@ -25,5 +37,13 @@
2537
"jest-fail-on-console": "^3.1.1",
2638
"jest-watch-typeahead": "^1.0.0",
2739
"whatwg-fetch": "^3.6.2"
40+
},
41+
"devDependencies": {
42+
"@jest/types": "^27.5.1",
43+
"@terra-ui-packages/build-utils": "^1.0.0",
44+
"@types/jest": "^28.1.8",
45+
"@types/node": "^20.6.2",
46+
"typescript": "^4.9.5",
47+
"vite": "^4.3.9"
2848
}
2949
}

packages/test-utils/src/index.mjs

-1
This file was deleted.

packages/test-utils/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './jestConfig';
2+
export * from './withFakeTimers';

packages/test-utils/src/jest.config.mjs

-33
This file was deleted.

packages/test-utils/src/jestConfig.ts

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { Config } from '@jest/types';
2+
import fs from 'fs';
3+
import { createRequire } from 'module';
4+
import path from 'path';
5+
import process from 'process';
6+
import { fileURLToPath } from 'url';
7+
8+
export const getJestConfig = (): Config.InitialOptions => {
9+
// Use consistent time zone when testing locally and in CI.
10+
process.env.TZ = 'UTC';
11+
12+
const require = createRequire(import.meta.url);
13+
const testUtilsPath = path.dirname(fileURLToPath(import.meta.url));
14+
15+
// setupTests has a different file extension depending on whether it's built
16+
// as an ES module (the default, .js) or as a CommonJS module (.cjs).
17+
// This returns the path to the setupTests file that is a sibling of this
18+
// file (jest.config) in the build output.
19+
const getSetupTestsPath = (): string => {
20+
const extensions = ['js', 'cjs'];
21+
for (const ext of extensions) {
22+
const setupTestsPath = path.resolve(testUtilsPath, `setupTests.${ext}`);
23+
if (fs.existsSync(setupTestsPath)) {
24+
return setupTestsPath;
25+
}
26+
}
27+
28+
throw new Error('Unable to locate setupTests');
29+
};
30+
31+
const jestConfig: Config.InitialOptions = {
32+
rootDir: process.cwd(),
33+
roots: ['<rootDir>/src'],
34+
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.d.ts'],
35+
setupFilesAfterEnv: [getSetupTestsPath()],
36+
testMatch: ['<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}', '<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}'],
37+
testEnvironment: 'jsdom',
38+
transform: {
39+
'^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': path.resolve(testUtilsPath, '../../transforms/babelTransform.cjs'),
40+
'^.+\\.css$': path.resolve(testUtilsPath, '../../transforms/cssTransform.cjs'),
41+
'^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': path.resolve(testUtilsPath, '../../transforms/fileTransform.cjs'),
42+
},
43+
transformIgnorePatterns: [],
44+
modulePaths: [],
45+
moduleNameMapper: {
46+
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
47+
'^src/(.*)$': '<rootDir>/src/$1',
48+
},
49+
watchPlugins: [require.resolve('jest-watch-typeahead/filename'), require.resolve('jest-watch-typeahead/testname')],
50+
resetMocks: false,
51+
clearMocks: true,
52+
};
53+
54+
return jestConfig;
55+
};

packages/test-utils/src/setupTests.mjs packages/test-utils/src/setupTests.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
/* eslint-env jest */
21
import '@testing-library/jest-dom';
32
import 'blob-polyfill';
43
import 'whatwg-fetch';
54

5+
// @ts-expect-error Types for the current version of jest-axe are not available.
66
import { toHaveNoViolations } from 'jest-axe';
77
import failOnConsole from 'jest-fail-on-console';
88

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* Wrap a test function in useFakeTimers/useRealTimers.
3+
*/
4+
export const withFakeTimers =
5+
<F extends (...args: any[]) => any>(fn: F) =>
6+
(...args: Parameters<F>): ReturnType<F> => {
7+
try {
8+
jest.useFakeTimers();
9+
return fn(...args);
10+
} finally {
11+
// "It's important to also call runOnlyPendingTimers before switching to real timers.
12+
// This will ensure you flush all the pending timers before you switch to real timers."
13+
// -- https://testing-library.com/docs/using-fake-timers/
14+
jest.runOnlyPendingTimers();
15+
jest.useRealTimers();
16+
}
17+
};

packages/test-utils/tsconfig.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "lib/types",
5+
"rootDir": "src"
6+
},
7+
"include": ["src"],
8+
"exclude": ["src/**/*.types.ts", "src/**/*.errors.ts"]
9+
}

packages/test-utils/vite.config.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { viteConfig as defineBaseConfig } from '@terra-ui-packages/build-utils';
2+
import { defineConfig } from 'vite';
3+
4+
export default defineConfig((args) => {
5+
const baseConfig = defineBaseConfig(args)
6+
return {
7+
...baseConfig,
8+
build: {
9+
...baseConfig.build,
10+
lib: {
11+
...baseConfig.build.lib,
12+
entry: [
13+
'src/index.ts',
14+
// Since jest.config references setupTests but does not import it,
15+
// setupTests has to be added as a separate entry point in order
16+
// for it to be bundled.
17+
'src/setupTests.ts',
18+
]
19+
},
20+
}
21+
}
22+
});

yarn.lock

+13
Original file line numberDiff line numberDiff line change
@@ -3020,7 +3020,11 @@ __metadata:
30203020
resolution: "@terra-ui-packages/test-utils@workspace:packages/test-utils"
30213021
dependencies:
30223022
"@babel/core": ^7.16.0
3023+
"@jest/types": ^27.5.1
3024+
"@terra-ui-packages/build-utils": ^1.0.0
30233025
"@testing-library/jest-dom": ^5.17.0
3026+
"@types/jest": ^28.1.8
3027+
"@types/node": ^20.6.2
30243028
babel-jest: ^27.4.2
30253029
babel-preset-react-app: ^10.0.1
30263030
blob-polyfill: ^7.0.20220408
@@ -3031,6 +3035,8 @@ __metadata:
30313035
jest-axe: ^6.0.0
30323036
jest-fail-on-console: ^3.1.1
30333037
jest-watch-typeahead: ^1.0.0
3038+
typescript: ^4.9.5
3039+
vite: ^4.3.9
30343040
whatwg-fetch: ^3.6.2
30353041
languageName: unknown
30363042
linkType: soft
@@ -3376,6 +3382,13 @@ __metadata:
33763382
languageName: node
33773383
linkType: hard
33783384

3385+
"@types/node@npm:^20.6.2":
3386+
version: 20.6.2
3387+
resolution: "@types/node@npm:20.6.2"
3388+
checksum: 96fe5303872640a173f3fd43e289a451776ed5b8f0090094447c6790b43f23fb607eea8268af0829cef4d132e5afa0bfa4cd871aa7412e9042a414a698e9e971
3389+
languageName: node
3390+
linkType: hard
3391+
33793392
"@types/parse-json@npm:^4.0.0":
33803393
version: 4.0.0
33813394
resolution: "@types/parse-json@npm:4.0.0"

0 commit comments

Comments
 (0)