diff --git a/assets/js/components/adminbar/__snapshots__/AdminBarWidgets.test.js.snap b/assets/js/components/adminbar/__snapshots__/AdminBarWidgets.test.js.snap index 9507afe3fba..d154fc5b8d3 100644 --- a/assets/js/components/adminbar/__snapshots__/AdminBarWidgets.test.js.snap +++ b/assets/js/components/adminbar/__snapshots__/AdminBarWidgets.test.js.snap @@ -16,7 +16,7 @@ exports[`AdminBarWidgets should not render the Activate Analytics CTA when the A class="googlesitekit-data-block__title-datapoint-wrapper" >

=24.0.0" @@ -6495,6 +6493,334 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@swc/core": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.21.tgz", + "integrity": "sha512-fkk7NJcBscrR3/F8jiqlMptRHP650NxqDnspBMrRe5d8xOoCy9MLL5kOBLFXjFLfMo3KQQHhk+/jUULOMlR1uQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.21", + "@swc/core-darwin-x64": "1.15.21", + "@swc/core-linux-arm-gnueabihf": "1.15.21", + "@swc/core-linux-arm64-gnu": "1.15.21", + "@swc/core-linux-arm64-musl": "1.15.21", + "@swc/core-linux-ppc64-gnu": "1.15.21", + "@swc/core-linux-s390x-gnu": "1.15.21", + "@swc/core-linux-x64-gnu": "1.15.21", + "@swc/core-linux-x64-musl": "1.15.21", + "@swc/core-win32-arm64-msvc": "1.15.21", + "@swc/core-win32-ia32-msvc": "1.15.21", + "@swc/core-win32-x64-msvc": "1.15.21" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.21.tgz", + "integrity": "sha512-SA8SFg9dp0qKRH8goWsax6bptFE2EdmPf2YRAQW9WoHGf3XKM1bX0nd5UdwxmC5hXsBUZAYf7xSciCler6/oyA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.21.tgz", + "integrity": "sha512-//fOVntgowz9+V90lVsNCtyyrtbHp3jWH6Rch7MXHXbcvbLmbCTmssl5DeedUWLLGiAAW1wksBdqdGYOTjaNLw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.21.tgz", + "integrity": "sha512-meNI4Sh6h9h8DvIfEc0l5URabYMSuNvyisLmG6vnoYAS43s8ON3NJR8sDHvdP7NJTrLe0q/x2XCn6yL/BeHcZg==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.21.tgz", + "integrity": "sha512-QrXlNQnHeXqU2EzLlnsPoWEh8/GtNJLvfMiPsDhk+ht6Xv8+vhvZ5YZ/BokNWSIZiWPKLAqR0M7T92YF5tmD3g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.21.tgz", + "integrity": "sha512-8/yGCMO333ultDaMQivE5CjO6oXDPeeg1IV4sphojPkb0Pv0i6zvcRIkgp60xDB+UxLr6VgHgt+BBgqS959E9g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-ppc64-gnu": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.21.tgz", + "integrity": "sha512-ucW0HzPx0s1dgRvcvuLSPSA/2Kk/VYTv9st8qe1Kc22Gu0Q0rH9+6TcBTmMuNIp0Xs4BPr1uBttmbO1wEGI49Q==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-s390x-gnu": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.21.tgz", + "integrity": "sha512-ulTnOGc5I7YRObE/9NreAhQg94QkiR5qNhhcUZ1iFAYjzg/JGAi1ch+s/Ixe61pMIr8bfVrF0NOaB0f8wjaAfA==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.21.tgz", + "integrity": "sha512-D0RokxtM+cPvSqJIKR6uja4hbD+scI9ezo95mBhfSyLUs9wnPPl26sLp1ZPR/EXRdYm3F3S6RUtVi+8QXhT24Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.21.tgz", + "integrity": "sha512-nER8u7VeRfmU6fMDzl1NQAbbB/G7O2avmvCOwIul1uGkZ2/acbPH+DCL9h5+0yd/coNcxMBTL6NGepIew+7C2w==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.21.tgz", + "integrity": "sha512-+/AgNBnjYugUA8C0Do4YzymgvnGbztv7j8HKSQLvR/DQgZPoXQ2B3PqB2mTtGh/X5DhlJWiqnunN35JUgWcAeQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.21.tgz", + "integrity": "sha512-IkSZj8PX/N4HcaFhMQtzmkV8YSnuNoJ0E6OvMwFiOfejPhiKXvl7CdDsn1f4/emYEIDO3fpgZW9DTaCRMDxaDA==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.21", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.21.tgz", + "integrity": "sha512-zUyWso7OOENB6e1N1hNuNn8vbvLsTdKQ5WKLgt/JcBNfJhKy/6jmBmqI3GXk/MyvQKd5SLvP7A0F36p7TeDqvw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/jest": { + "version": "0.2.39", + "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.39.tgz", + "integrity": "sha512-eyokjOwYd0Q8RnMHri+8/FS1HIrIUKK/sRrFp8c1dThUOfNeCWbLmBP1P5VsKdvmkd25JaH+OKYwEYiAYg9YAA==", + "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^30.0.0", + "@swc/counter": "^0.1.3", + "jsonc-parser": "^3.2.0" + }, + "engines": { + "npm": ">= 7.0.0" + }, + "peerDependencies": { + "@swc/core": "*" + } + }, + "node_modules/@swc/jest/node_modules/@jest/create-cache-key-function": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-30.3.0.tgz", + "integrity": "sha512-hTupmOWylzeyqbMNeSNi7ZDprpjrcroAOOG+qCEW66st3+Z5RnYHVYkUt+zjIcLmrTUi2lPY79hJz8mB3L2oXQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@swc/jest/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@swc/jest/node_modules/@jest/types": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz", + "integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==", + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@swc/jest/node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "license": "MIT" + }, + "node_modules/@swc/jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@swc/types": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.26.tgz", + "integrity": "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, "node_modules/@tannin/compile": { "version": "1.1.0", "license": "MIT", @@ -17758,6 +18084,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, "node_modules/jsonfile": { "version": "6.1.0", "dev": true, @@ -26976,20 +27308,19 @@ }, "tests/js": { "dependencies": { + "@swc/core": "^1.15.21", + "@swc/jest": "^0.2.39", "@wordpress/element": "^2.20.3", "intl": "^1.2.5", "intl-locales-supported": "^1.8.12" }, "devDependencies": { - "@babel/preset-env": "^7.27.2", "@jackfranklin/test-data-bot": "^2.0.0", "@shopify/jest-dom-mocks": "^4.0.2", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^10.4.9", "@testing-library/react-hooks": "^3.7.0", - "@wordpress/babel-preset-default": "^8.23.0", "@wordpress/jest-preset-default": "^12.23.0", - "babel-jest": "^29.7.0", "cross-env": "^7.0.3", "fetch-mock": "^9.10.3", "fetch-mock-jest": "^1.3.0", diff --git a/tests/js/babel-transform.js b/tests/js/babel-transform.js deleted file mode 100644 index eedaa1c93e2..00000000000 --- a/tests/js/babel-transform.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Site Kit by Google, Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * External dependencies - */ -const babelJest = require( 'babel-jest' ); - -module.exports = babelJest.createTransformer( { - presets: [ '@wordpress/babel-preset-default' ], -} ); diff --git a/tests/js/jest.config.js b/tests/js/jest.config.js index 77d8443988c..71f3b302220 100644 --- a/tests/js/jest.config.js +++ b/tests/js/jest.config.js @@ -16,6 +16,8 @@ const path = require( 'path' ); +const swcTransform = path.resolve( __dirname, 'swc-jest-compat.js' ); + function getModuleAbsolutePath( packageName ) { return path.dirname( require.resolve( path.join( packageName, 'package.json' ) ) @@ -30,8 +32,31 @@ module.exports = { rootDir: '../../', preset: getModuleAbsolutePath( '@wordpress/jest-preset-default' ), transform: { - '^.+\\.(js|jsx|ts|tsx)$': - '/tests/js/babel-transform.js', + '^.+\\.(js|jsx)$': [ + swcTransform, + { + jsc: { + parser: { jsx: true }, + transform: { react: { runtime: 'automatic' } }, + loose: true, + }, + module: { type: 'commonjs' }, + }, + ], + '^.+\\.(ts|tsx)$': [ + swcTransform, + { + jsc: { + parser: { + syntax: 'typescript', + tsx: true, + }, + transform: { react: { runtime: 'automatic' } }, + loose: true, + }, + module: { type: 'commonjs' }, + }, + ], }, setupFiles: [ '/tests/js/setup-globals', @@ -83,8 +108,31 @@ module.exports = { rootDir: '../../', testEnvironment: 'node', transform: { - '^.+\\.(js|jsx|ts|tsx)$': - '/tests/js/babel-transform.js', + '^.+\\.(js|jsx)$': [ + swcTransform, + { + jsc: { + parser: { jsx: true }, + transform: { react: { runtime: 'automatic' } }, + loose: true, + }, + module: { type: 'commonjs' }, + }, + ], + '^.+\\.(ts|tsx)$': [ + swcTransform, + { + jsc: { + parser: { + syntax: 'typescript', + tsx: true, + }, + transform: { react: { runtime: 'automatic' } }, + loose: true, + }, + module: { type: 'commonjs' }, + }, + ], }, testMatch: [ '/packages/eslint-plugin/**/?(*.)test.{js,jsx,ts,tsx}', diff --git a/tests/js/package.json b/tests/js/package.json index 0e2ac41275a..4fd5df2517e 100644 --- a/tests/js/package.json +++ b/tests/js/package.json @@ -5,20 +5,19 @@ "test:js:watch": "npm run test:js -- --watch" }, "dependencies": { + "@swc/core": "^1.15.21", + "@swc/jest": "^0.2.39", "@wordpress/element": "^2.20.3", "intl": "^1.2.5", "intl-locales-supported": "^1.8.12" }, "devDependencies": { - "@babel/preset-env": "^7.27.2", "@jackfranklin/test-data-bot": "^2.0.0", "@shopify/jest-dom-mocks": "^4.0.2", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^10.4.9", "@testing-library/react-hooks": "^3.7.0", - "@wordpress/babel-preset-default": "^8.23.0", "@wordpress/jest-preset-default": "^12.23.0", - "babel-jest": "^29.7.0", "cross-env": "^7.0.3", "fetch-mock": "^9.10.3", "fetch-mock-jest": "^1.3.0", diff --git a/tests/js/swc-jest-compat.js b/tests/js/swc-jest-compat.js new file mode 100644 index 00000000000..87abf90d5e3 --- /dev/null +++ b/tests/js/swc-jest-compat.js @@ -0,0 +1,71 @@ +/** + * Site Kit by Google, Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * SWC compiles named ES module exports as Object.defineProperty() getter calls + * with no `configurable` flag (so it defaults to false). Jest's spyOn() and + * jest.mock() require configurable: true to be able to replace those properties. + * + * This wrapper calls @swc/jest and then patches every export getter definition + * to add `configurable: true`, matching what Babel's CJS transform produces. + */ + +const { createTransformer: swcCreateTransformer } = require( '@swc/jest' ); + +function makeExportsConfigurable( code ) { + // Matches the SWC-emitted pattern: + // enumerable: true, + // get: function() { ... } + // and inserts configurable: true between them. + return code.replace( + /(enumerable:\s*true,\n)(\s*)(get:)/g, + '$1$2configurable: true,\n$2$3' + ); +} + +// Jest calls createTransformer( config ) when the transform is specified as +// [ 'path/to/transformer', config ]. We must forward `options` to @swc/jest so +// it computes the correct SWC options (parser syntax, JSX, TypeScript, etc.). +function createTransformer( options ) { + const transformer = swcCreateTransformer( options ); + return { + ...transformer, + process( sourceText, sourcePath, jestOptions ) { + const result = transformer.process( + sourceText, + sourcePath, + jestOptions + ); + return { + ...result, + code: makeExportsConfigurable( result.code ), + }; + }, + async processAsync( sourceText, sourcePath, jestOptions ) { + const result = await transformer.processAsync( + sourceText, + sourcePath, + jestOptions + ); + return { + ...result, + code: makeExportsConfigurable( result.code ), + }; + }, + }; +} + +module.exports = { createTransformer };