From 277c56e764498301956f7d27810d70c94c4748ef Mon Sep 17 00:00:00 2001
From: RedYetiDev <38299977+RedYetiDev@users.noreply.github.com>
Date: Wed, 25 Sep 2024 14:53:57 -0400
Subject: [PATCH] test_runner: support typescript files in default glob

---
 doc/api/test.md                               | 23 ++++++++++++++-----
 lib/internal/test_runner/utils.js             |  7 ++++--
 .../matching-patterns/typescript-test.cts     |  4 ++++
 .../matching-patterns/typescript-test.mts     |  4 ++++
 .../matching-patterns/typescript-test.ts      |  4 ++++
 test/parallel/test-runner-cli.js              | 21 +++++++++++++++++
 6 files changed, 55 insertions(+), 8 deletions(-)
 create mode 100644 test/fixtures/test-runner/matching-patterns/typescript-test.cts
 create mode 100644 test/fixtures/test-runner/matching-patterns/typescript-test.mts
 create mode 100644 test/fixtures/test-runner/matching-patterns/typescript-test.ts

diff --git a/doc/api/test.md b/doc/api/test.md
index 99e4b452f1f561..62bdbbeaf8fff4 100644
--- a/doc/api/test.md
+++ b/doc/api/test.md
@@ -422,12 +422,22 @@ node --test
 
 By default, Node.js will run all files matching these patterns:
 
-* `**/*.test.?(c|m)js`
-* `**/*-test.?(c|m)js`
-* `**/*_test.?(c|m)js`
-* `**/test-*.?(c|m)js`
-* `**/test.?(c|m)js`
-* `**/test/**/*.?(c|m)js`
+* `**/*.test.{cjs,mjs,js}`
+* `**/*-test.{cjs,mjs,js}`
+* `**/*_test.{cjs,mjs,js}`
+* `**/test-*.{cjs,mjs,js}`
+* `**/test.{cjs,mjs,js}`
+* `**/test/**/*.{cjs,mjs,js}`
+
+When [`--experimental-strip-types`][] is supplied, the following
+additional patterns are matched:
+
+* `**/*.test.{cts,mts,ts}`
+* `**/*-test.{cts,mts,ts}`
+* `**/*_test.{cts,mts,ts}`
+* `**/test-*.{cts,mts,ts}`
+* `**/test.{cts,mts,ts}`
+* `**/test/**/*.{cts,mts,ts}`
 
 Alternatively, one or more glob patterns can be provided as the
 final argument(s) to the Node.js command, as shown below.
@@ -3562,6 +3572,7 @@ added:
 Can be used to abort test subtasks when the test has been aborted.
 
 [TAP]: https://testanything.org/
+[`--experimental-strip-types`]: cli.md#--experimental-strip-types
 [`--experimental-test-coverage`]: cli.md#--experimental-test-coverage
 [`--experimental-test-module-mocks`]: cli.md#--experimental-test-module-mocks
 [`--experimental-test-snapshots`]: cli.md#--experimental-test-snapshots
diff --git a/lib/internal/test_runner/utils.js b/lib/internal/test_runner/utils.js
index 67ce601c1dfe5f..9b8692529ed2c4 100644
--- a/lib/internal/test_runner/utils.js
+++ b/lib/internal/test_runner/utils.js
@@ -54,8 +54,11 @@ const kMultipleCallbackInvocations = 'multipleCallbackInvocations';
 const kRegExpPattern = /^\/(.*)\/([a-z]*)$/;
 
 const kPatterns = ['test', 'test/**/*', 'test-*', '*[._-]test'];
-const kDefaultPattern = `**/{${ArrayPrototypeJoin(kPatterns, ',')}}.?(c|m)js`;
-
+const kFileExtensions = ['js', 'mjs', 'cjs'];
+if (getOptionValue('--experimental-strip-types')) {
+  ArrayPrototypePush(kFileExtensions, 'ts', 'mts', 'cts');
+}
+const kDefaultPattern = `**/{${ArrayPrototypeJoin(kPatterns, ',')}}.{${ArrayPrototypeJoin(kFileExtensions, ',')}}`;
 
 function createDeferredCallback() {
   let calledCount = 0;
diff --git a/test/fixtures/test-runner/matching-patterns/typescript-test.cts b/test/fixtures/test-runner/matching-patterns/typescript-test.cts
new file mode 100644
index 00000000000000..1ba6866ffcdb56
--- /dev/null
+++ b/test/fixtures/test-runner/matching-patterns/typescript-test.cts
@@ -0,0 +1,4 @@
+const test = require('node:test');
+
+// 'as string' ensures that type stripping actually occurs
+test('this should pass' as string);
diff --git a/test/fixtures/test-runner/matching-patterns/typescript-test.mts b/test/fixtures/test-runner/matching-patterns/typescript-test.mts
new file mode 100644
index 00000000000000..52ea74c251594a
--- /dev/null
+++ b/test/fixtures/test-runner/matching-patterns/typescript-test.mts
@@ -0,0 +1,4 @@
+import { test } from 'node:test';
+
+// 'as string' ensures that type stripping actually occurs
+test('this should pass' as string);
diff --git a/test/fixtures/test-runner/matching-patterns/typescript-test.ts b/test/fixtures/test-runner/matching-patterns/typescript-test.ts
new file mode 100644
index 00000000000000..1ba6866ffcdb56
--- /dev/null
+++ b/test/fixtures/test-runner/matching-patterns/typescript-test.ts
@@ -0,0 +1,4 @@
+const test = require('node:test');
+
+// 'as string' ensures that type stripping actually occurs
+test('this should pass' as string);
diff --git a/test/parallel/test-runner-cli.js b/test/parallel/test-runner-cli.js
index 6ba4516673fb79..f80d53656d6745 100644
--- a/test/parallel/test-runner-cli.js
+++ b/test/parallel/test-runner-cli.js
@@ -57,6 +57,27 @@ for (const isolation of ['none', 'process']) {
     assert.match(stdout, /ok 1 - this should pass/);
     assert.match(stdout, /ok 2 - this should pass/);
     assert.match(stdout, /ok 3 - this should pass/);
+    // Doesn't match the TypeScript files
+    assert.doesNotMatch(stdout, /ok 4 - this should pass/);
+  }
+
+  for (const type of ['strip', 'transform']) {
+    // Should match files with "-test.(c|m)(t|j)s" suffix when typescript support is enabled
+    const args = ['--test', '--test-reporter=tap', '--no-warnings',
+                  `--experimental-${type}-types`, `--experimental-test-isolation=${isolation}`];
+    const child = spawnSync(process.execPath, args, { cwd: join(testFixtures, 'matching-patterns') });
+
+    assert.strictEqual(child.status, 0);
+    assert.strictEqual(child.signal, null);
+    assert.strictEqual(child.stderr.toString(), '');
+    const stdout = child.stdout.toString();
+
+    assert.match(stdout, /ok 1 - this should pass/);
+    assert.match(stdout, /ok 2 - this should pass/);
+    assert.match(stdout, /ok 3 - this should pass/);
+    assert.match(stdout, /ok 4 - this should pass/);
+    assert.match(stdout, /ok 5 - this should pass/);
+    assert.match(stdout, /ok 6 - this should pass/);
   }
 
   {