Repository: electron/electron
Pull request: test: fix esm issue in node-spec-runner

#### Description of Change

Chromium added a top-level package.json in CL:7485999 that sets the type to module and breaks commonjs tests run via node-spec-runner.js. This commit temporarily changes the type to commonjs while running the tests, then changes it back to module when done.

Errors would occur on every test like the following:

```
electron on git:main ❯ node script/node-spec-runner.js parallel/test-crypto
=== release test-crypto ===
Path: parallel/test-crypto
file:///Users/codebytere/Developer/electron-gn/src/third_party/electron_node/test/parallel/test-crypto.js:23
const common = require('../common');
               ^

ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and '/Users/codebytere/Developer/electron-gn/src/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at file:///Users/codebytere/Developer/electron-gn/src/third_party/electron_node/test/parallel/test-crypto.js:23:16
    at ModuleJob.run (node:internal/modules/esm/module_job:430:25)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:661:26)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:116:5)

Node.js v24.14.0
Command: /Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/MacOS/Electron /Users/codebytere/Developer/electron-gn/src/third_party/electron_node/test/parallel/test-crypto.js


[00:00|% 100|+   0|-   1]: Done

Failed tests:
/Users/codebytere/Developer/electron-gn/src/out/Testing/Electron.app/Contents/MacOS/Electron /Users/codebytere/Developer/electron-gn/src/third_party/electron_node/test/parallel/test-crypto.js
```

#### Checklist
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

- [x] PR description included
- [x] `npm test` passes
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: none

Changed files:
filename: script/node-spec-runner.js
patch: @@ -14,6 +14,7 @@ const args = minimist(process.argv.slice(2), {
 
 const BASE = path.resolve(__dirname, '../..');
 
+const ROOT_PACKAGE_JSON = path.resolve(BASE, 'package.json');
 const NODE_DIR = path.resolve(BASE, 'third_party', 'electron_node');
 const JUNIT_DIR = args.jUnitDir ? path.resolve(args.jUnitDir) : null;
 const TAP_FILE_NAME = 'test.tap';
@@ -38,6 +39,18 @@ const defaultOptions = [
   '-J'
 ];
 
+// The root package.json is ESM, which breaks the test runner.
+// Temporarily change it to CommonJS while running the tests, then
+// change it back when done.
+const resetPackageJson = ({ useESM }) => {
+  // This won't always exist in CI.
+  if (!fs.existsSync(ROOT_PACKAGE_JSON)) { return; }
+
+  const packageJson = JSON.parse(fs.readFileSync(ROOT_PACKAGE_JSON, 'utf-8'));
+  packageJson.type = useESM ? 'module' : 'commonjs';
+  fs.writeFileSync(ROOT_PACKAGE_JSON, JSON.stringify(packageJson, null, 2) + '\n');
+};
+
 const getCustomOptions = () => {
   let customOptions = ['tools/test.py'];
 
@@ -79,6 +92,8 @@ async function main () {
 
   const options = args.default ? defaultOptions : getCustomOptions();
 
+  resetPackageJson({ useESM: false });
+
   const testChild = cp.spawn('python3', options, {
     env: {
       ...process.env,
@@ -88,7 +103,10 @@ async function main () {
     cwd: NODE_DIR,
     stdio: 'inherit'
   });
+
   testChild.on('exit', (testCode) => {
+    resetPackageJson({ useESM: true });
+
     if (JUNIT_DIR) {
       fs.mkdirSync(JUNIT_DIR);
       const converterStream = require('tap-xunit')();