Skip to content

Commit 17751bb

Browse files
authored
Switch from Babel to SWC in Jest (#6205)
1 parent 9cbe7d4 commit 17751bb

File tree

11 files changed

+1094
-1799
lines changed

11 files changed

+1094
-1799
lines changed

jest.config.js

+21-2
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ module.exports = {
169169
testPathIgnorePatterns: [
170170
'/node_modules/',
171171
'\\.ssr\\.test\\.[tj]sx?$'
172-
]
172+
],
173173

174174
// The regexp pattern or array of patterns that Jest uses to detect test files
175175
// testRegex: [],
@@ -187,7 +187,26 @@ module.exports = {
187187
// timers: "real",
188188

189189
// A map from regular expressions to paths to transformers
190-
// transform: null,
190+
transform: {
191+
'^.+\\.(t|j)sx?$': [
192+
'@swc/jest',
193+
{
194+
jsc: {
195+
parser: {
196+
syntax: 'typescript',
197+
tsx: true,
198+
importAssertions: true
199+
},
200+
201+
transform: {
202+
react: {
203+
runtime: 'automatic'
204+
}
205+
}
206+
}
207+
}
208+
]
209+
},
191210

192211
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
193212
// transformIgnorePatterns: [

jest.ssr.config.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,26 @@ module.exports = {
4747
// The glob patterns Jest uses to detect test files
4848
testMatch: [
4949
'**/packages/**/*.ssr.test.[tj]s?(x)'
50-
]
50+
],
51+
52+
transform: {
53+
'^.+\\.(t|j)sx?$': [
54+
'@swc/jest',
55+
{
56+
jsc: {
57+
parser: {
58+
syntax: 'typescript',
59+
tsx: true,
60+
importAssertions: true
61+
},
62+
63+
transform: {
64+
react: {
65+
runtime: 'automatic'
66+
}
67+
}
68+
}
69+
}
70+
]
71+
},
5172
};

lib/jestResolver.js

+32-13
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,31 @@ const path = require('path');
1515
const crypto = require('crypto');
1616
const fs = require('fs');
1717
const {threadId} = require('worker_threads');
18+
const glob = require('glob');
1819

19-
const cacheDir = path.join(__dirname, '..', 'node_modules', '.cache', 'intl');
20+
const intlCacheDir = path.join(__dirname, '..', 'node_modules', '.cache', 'intl');
21+
const globCacheDir = path.join(__dirname, '..', 'node_modules', '.cache', 'glob');
2022
try {
21-
fs.mkdirSync(cacheDir, {recursive: true});
23+
fs.mkdirSync(intlCacheDir, {recursive: true});
24+
fs.mkdirSync(globCacheDir, {recursive: true});
2225
} catch (err) {
2326
// ignore
2427
}
2528

2629
module.exports = (request, options) => {
30+
// Handle glob imports.
31+
if (request.endsWith('*.json')) {
32+
let files = glob.sync(request, {cwd: options.basedir});
33+
let source = '';
34+
for (let file of files) {
35+
source += `exports['${path.basename(file, '.json')}'] = require('${path.join(options.basedir, file)}');\n`;
36+
}
37+
let hash = crypto.createHash('md5');
38+
hash.update(source);
39+
let cacheFile = path.join(globCacheDir, hash.digest('hex'));
40+
return writeCacheFile(cacheFile, source);
41+
}
42+
2743
let resolved = options.defaultResolver(request, {
2844
...options,
2945
// https://github.com/microsoft/accessibility-insights-web/pull/5421#issuecomment-1109168149
@@ -40,19 +56,22 @@ module.exports = (request, options) => {
4056

4157
let hash = crypto.createHash('md5');
4258
hash.update(res);
43-
let cacheFile = path.join(cacheDir, hash.digest('hex') + '.js');
59+
let cacheFile = path.join(intlCacheDir, hash.digest('hex') + '.js');
60+
return writeCacheFile(cacheFile, res);
61+
}
4462

45-
// If cache file already exists, return it.
46-
if (fs.existsSync(cacheFile)) {
47-
return cacheFile;
48-
}
63+
return resolved;
64+
};
4965

50-
// Otherwise, write it atomically to avoid race conditions between threads/processes.
51-
let tmpFile = cacheFile + '.' + process.pid + (threadId != null ? '.' + threadId : '');
52-
fs.writeFileSync(tmpFile, res);
53-
fs.renameSync(tmpFile, cacheFile);
66+
function writeCacheFile(cacheFile, res) {
67+
// If cache file already exists, return it.
68+
if (fs.existsSync(cacheFile)) {
5469
return cacheFile;
5570
}
5671

57-
return resolved;
58-
};
72+
// Otherwise, write it atomically to avoid race conditions between threads/processes.
73+
let tmpFile = cacheFile + '.' + process.pid + (threadId != null ? '.' + threadId : '');
74+
fs.writeFileSync(tmpFile, res);
75+
fs.renameSync(tmpFile, cacheFile);
76+
return cacheFile;
77+
}

package.json

+13-12
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,17 @@
6161
"devDependencies": {
6262
"@actions/core": "^1.1.0",
6363
"@actions/github": "^1.1.0",
64-
"@babel/cli": "^7.12.10",
65-
"@babel/core": "^7.12.10",
66-
"@babel/eslint-parser": "^7.19.1",
67-
"@babel/node": "^7.12.10",
68-
"@babel/plugin-proposal-decorators": "^7.12.1",
69-
"@babel/plugin-syntax-decorators": "^7.12.1",
70-
"@babel/plugin-transform-runtime": "^7.12.10",
71-
"@babel/preset-env": "^7.12.11",
72-
"@babel/preset-react": "^7.12.10",
73-
"@babel/preset-typescript": "^7.12.7",
74-
"@babel/register": "^7.12.10",
64+
"@babel/cli": "^7.24.1",
65+
"@babel/core": "^7.24.3",
66+
"@babel/eslint-parser": "^7.24.1",
67+
"@babel/node": "^7.23.9",
68+
"@babel/plugin-proposal-decorators": "^7.24.1",
69+
"@babel/plugin-syntax-decorators": "7.24.1",
70+
"@babel/plugin-transform-runtime": "^7.24.3",
71+
"@babel/preset-env": "^7.24.3",
72+
"@babel/preset-react": "^7.24.1",
73+
"@babel/preset-typescript": "^7.24.1",
74+
"@babel/register": "^7.23.7",
7575
"@octokit/rest": "*",
7676
"@parcel/optimizer-data-url": "^2.12.0",
7777
"@parcel/optimizer-terser": "^2.12.0",
@@ -95,6 +95,7 @@
9595
"@storybook/test-runner": "^0.9.0",
9696
"@storybook/testing-library": "^0.0.13",
9797
"@storybook/testing-react": "^1.3.0",
98+
"@swc/jest": "^0.2.36",
9899
"@testing-library/dom": "^9.2.0",
99100
"@testing-library/jest-dom": "^5.16.5",
100101
"@testing-library/react": "^14.0.0",
@@ -181,7 +182,7 @@
181182
"yargs": "^17.2.1"
182183
},
183184
"resolutions": {
184-
"@babel/core": "7.12.10",
185+
"@babel/core": "7.24.3",
185186
"@types/react": "18.2.28",
186187
"postcss": "8.4.24",
187188
"postcss-custom-properties": "13.2.0",

packages/@internationalized/number/test/NumberParser.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
*/
1212

1313
import fc from 'fast-check';
14-
import messages from '../../../@react-aria/numberfield/intl/*';
14+
import messages from '../../../@react-aria/numberfield/intl/*.json';
1515
import {NumberParser} from '../src/NumberParser';
1616

1717
// for some reason hu-HU isn't supported in jsdom/node
18-
let locales = Object.keys(messages).map(locale => locale.replace('.json', '')).filter(locale => locale !== 'hu-HU');
18+
let locales = Object.keys(messages).filter(locale => locale !== 'hu-HU');
1919

2020
describe('NumberParser', function () {
2121
describe('parse', function () {

packages/@react-aria/focus/test/focusSafely.test.js

+11-5
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,20 @@
1414
import {act, render} from '@react-spectrum/test-utils';
1515
import {focusSafely} from '../';
1616
import React from 'react';
17-
import * as ReactAriaUtils from '../../utils/index';
17+
import * as ReactAriaUtils from '@react-aria/utils';
1818
import {setInteractionModality} from '@react-aria/interactions';
1919

20+
jest.mock('@react-aria/utils', () => {
21+
let original = jest.requireActual('@react-aria/utils');
22+
return {
23+
...original,
24+
focusWithoutScrolling: jest.fn()
25+
};
26+
});
27+
2028
jest.useFakeTimers();
2129

2230
describe('focusSafely', () => {
23-
const focusWithoutScrollingSpy = jest.spyOn(ReactAriaUtils, 'focusWithoutScrolling').mockImplementation(() => {});
24-
2531
it("should not focus on the element if it's no longer connected", async function () {
2632
setInteractionModality('virtual');
2733

@@ -40,7 +46,7 @@ describe('focusSafely', () => {
4046
jest.runAllTimers();
4147
});
4248

43-
expect(focusWithoutScrollingSpy).toBeCalledTimes(0);
49+
expect(ReactAriaUtils.focusWithoutScrolling).toBeCalledTimes(0);
4450
});
4551

4652
it("should focus on the element if it's connected", async function () {
@@ -58,6 +64,6 @@ describe('focusSafely', () => {
5864
jest.runAllTimers();
5965
});
6066

61-
expect(focusWithoutScrollingSpy).toBeCalledTimes(1);
67+
expect(ReactAriaUtils.focusWithoutScrolling).toBeCalledTimes(1);
6268
});
6369
});

packages/@react-spectrum/avatar/test/Avatar.test.js

-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {Avatar} from '../';
22
import React from 'react';
33
import {render, screen} from '@react-spectrum/test-utils';
4-
import * as Utils from '@react-spectrum/utils';
54

65
describe('Avatar', () => {
76
it('renders an avatar image', () => {
@@ -31,26 +30,6 @@ describe('Avatar', () => {
3130
width: '80px'
3231
});
3332
});
34-
35-
// Spying on dimensionValue since we're unable to use toHaveStyle effectively with CSS vars
36-
// See https://github.com/testing-library/jest-dom/issues/322
37-
it('supports predefined avatar sizes', () => {
38-
const dimensionValueSpy = jest.spyOn(Utils, 'dimensionValue');
39-
render(<Avatar src="http://localhost/some_image.png" size="avatar-size-700" />);
40-
expect(dimensionValueSpy).not.toHaveBeenCalledWith('avatar-size-100');
41-
});
42-
43-
it('defaults to default size when size is size-XXXX', () => {
44-
const dimensionValueSpy = jest.spyOn(Utils, 'dimensionValue');
45-
render(<Avatar src="http://localhost/some_image.png" size="size-100" />);
46-
expect(dimensionValueSpy).toHaveBeenCalledWith('avatar-size-100');
47-
});
48-
49-
it('defaults to default size when size is a string number', () => {
50-
const dimensionValueSpy = jest.spyOn(Utils, 'dimensionValue');
51-
render(<Avatar src="http://localhost/some_image.png" size="100" />);
52-
expect(dimensionValueSpy).toHaveBeenCalledWith('avatar-size-100');
53-
});
5433
});
5534

5635
it('supports custom class names', () => {

packages/@react-spectrum/numberfield/test/NumberField.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ import {announce} from '@react-aria/live-announcer';
1616
import {Button} from '@react-spectrum/button';
1717
import {chain} from '@react-aria/utils';
1818
import {Form} from '@react-spectrum/form';
19-
import messages from '../../../@react-aria/numberfield/intl/*';
19+
import messages from '../../../@react-aria/numberfield/intl/*.json';
2020
import {NumberField} from '../';
2121
import {Provider} from '@react-spectrum/provider';
2222
import React, {useState} from 'react';
2323
import {theme} from '@react-spectrum/theme-default';
2424
import userEvent from '@testing-library/user-event';
2525

2626
// for some reason hu-HU isn't supported in jsdom/node
27-
let locales = Object.keys(messages).map(locale => locale.replace('.json', '')).filter(locale => locale !== 'hu-HU');
27+
let locales = Object.keys(messages).filter(locale => locale !== 'hu-HU');
2828

2929
// a note for these tests, text selection is not working in jsdom, so on focus will not select the value already
3030
// in the numberfield

patches/@babel+types+7.17.10.patch patches/@babel+types+7.24.0.patch

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
diff --git a/node_modules/@babel/types/lib/retrievers/getBindingIdentifiers.js b/node_modules/@babel/types/lib/retrievers/getBindingIdentifiers.js
2-
index 4daaf8b..f22bb5a 100644
2+
index 86b4d1d..8dc0869 100644
33
--- a/node_modules/@babel/types/lib/retrievers/getBindingIdentifiers.js
44
+++ b/node_modules/@babel/types/lib/retrievers/getBindingIdentifiers.js
5-
@@ -72,6 +72,13 @@ getBindingIdentifiers.keys = {
5+
@@ -62,6 +62,13 @@ getBindingIdentifiers.keys = {
66
InterfaceDeclaration: ["id"],
77
TypeAlias: ["id"],
88
OpaqueType: ["id"],

scripts/buildI18n.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function build(scope, dist = scope.slice(1)) {
4040
serialized += '};\n';
4141

4242
fs.writeFileSync(`packages/${dist}/i18n/${lang}.js`, minifySync(`module.exports = ${serialized}`).code);
43-
fs.writeFileSync(`packages/${dist}/i18n/${lang}.mjs`, minifySync(`export default ${serialized}`).code);
43+
fs.writeFileSync(`packages/${dist}/i18n/${lang}.mjs`, minifySync(`export default ${serialized}`, {module: true}).code);
4444
}
4545

4646
fs.writeFileSync(`packages/${dist}/i18n/lang.d.ts`, `import type {LocalizedString} from '@internationalized/string';

0 commit comments

Comments
 (0)