Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0832a90
feat(`tape-to-node-test`): first draft
AugustinMauroy Dec 10, 2025
527acf4
fix: use `workflow` convention
AugustinMauroy Dec 10, 2025
c5ca0a5
fix: use `EOL`
AugustinMauroy Dec 10, 2025
59cf844
chore: update readme
AugustinMauroy Dec 10, 2025
af14a96
feat(tape-to-node-test): support dynamic import
AugustinMauroy Dec 11, 2025
f665ea8
feat(`tape-to-node-test`): support more cases
AugustinMauroy Dec 11, 2025
08e74b0
fix: code format
AugustinMauroy Dec 11, 2025
e51e443
feat(tape-to-node-test): support timeout
AugustinMauroy Dec 11, 2025
7cd866b
feat(tape-to-node-test): improve
AugustinMauroy Dec 11, 2025
506db48
fix: linting/issue
AugustinMauroy Dec 12, 2025
256c540
test,fix: handling of timeout
AugustinMauroy Dec 12, 2025
a6caff6
Delete index.ts
AugustinMauroy Dec 12, 2025
15c63ec
Merge branch 'main' into tape-to-node-test
AugustinMauroy Dec 15, 2025
c0037e1
remove dep
AugustinMauroy Dec 15, 2025
5b9ce43
Apply suggestions from code review
AugustinMauroy Dec 18, 2025
5e5d232
fix: code style
AugustinMauroy Dec 18, 2025
8e0e92c
Update recipes/tape-to-node-test/src/workflow.ts
AugustinMauroy Jan 17, 2026
630c116
better async cb handling
AugustinMauroy Jan 17, 2026
654294a
wip
AugustinMauroy Jan 17, 2026
ddf833a
handle `test` and `plan`
AugustinMauroy Jan 17, 2026
bfcb5eb
update
AugustinMauroy Jan 17, 2026
a44f92e
WIP
AugustinMauroy Jan 21, 2026
fc28208
improve async/sync handling
AugustinMauroy Jan 21, 2026
2630241
update
AugustinMauroy Jan 21, 2026
f13199b
apply review
AugustinMauroy Apr 6, 2026
39d0797
better t.pass
AugustinMauroy Apr 6, 2026
21a2d7c
Update workflow.ts
AugustinMauroy Apr 9, 2026
beb9739
apply suggestion
AugustinMauroy Apr 25, 2026
6da0864
timeout support
AugustinMauroy Apr 25, 2026
2769176
add remove line
AugustinMauroy Apr 25, 2026
a7c16f4
Merge branch 'main' into tape-to-node-test
AugustinMauroy Apr 25, 2026
a12f72e
Update package-lock.json
AugustinMauroy Apr 25, 2026
56a15b4
fix
AugustinMauroy Apr 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
"**",
"!**/*.snap.cjs",
"!**/fixtures",
"!**/expected",
"!**/input"
"!**/tests"
]
},
"assist": { "actions": { "source": { "organizeImports": "off" } } },
Expand Down
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 118 additions & 0 deletions recipes/tape-to-node-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Tape to Node.js Test Runner Codemod

This codemod migrates tests written using [`tape`](https://github.com/tape-testing/tape) v5 to the native Node.js test runner ([`node:test`](https://nodejs.org/api/test.html)).

## Features

- Replaces `tape` imports with `node:test` and `node:assert`.
- Converts `test(name, (t) => ...)` to `test(name, async (t) => ...)`.
- Maps `tape` assertions to `node:assert` equivalents, including many aliases (e.g., `t.is`, `t.equals`, `t.deepEquals`).
- Handles `t.plan` (by commenting it out).
- Handles `t.end` (removes it for async tests, converts to `done` callback for callback-style tests).
- Handles `t.test` subtests (adds `await`).
- Converts `t.teardown` to `t.after`.
- Converts `t.comment` to `t.diagnostic`.
- Migrates `t.timeoutAfter(ms)` to `{ timeout: ms }` test option.
- Supports `test.skip` and `test.only`.
- Handles `test.onFinish` and `test.onFailure` (by commenting them out with a TODO).
- Supports loose equality assertions (e.g., `t.looseEqual` -> `assert.equal`).

## Example

### Basic Equality

```diff
- import test from "tape";
+ import { test } from 'node:test';
+ import assert from 'node:assert';

- test("basic equality", (t) => {
+ test("basic equality", async (t) => {
- t.plan(4);
+ // t.plan(4);
- t.equal(1, 1, "equal numbers");
+ assert.strictEqual(1, 1, "equal numbers");
- t.notEqual(1, 2, "not equal numbers");
+ assert.notStrictEqual(1, 2, "not equal numbers");
- t.strictEqual(true, true, "strict equality");
+ assert.strictEqual(true, true, "strict equality");
- t.notStrictEqual("1", 1, "not strict equality");
+ assert.notStrictEqual("1", 1, "not strict equality");
- t.end();
+ // t.end();
});
```

### Async Tests

```diff
- import test from "tape";
+ import { test } from 'node:test';
+ import assert from 'node:assert';

function someAsyncThing() {
return new Promise((resolve) => setTimeout(() => resolve(true), 50));
}

- test("async test with promises", async (t) => {
+ test("async test with promises", async (t) => {
- t.plan(1);
+ // t.plan(1);
const result = await someAsyncThing();
- t.ok(result, "async result is truthy");
+ assert.ok(result, "async result is truthy");
});
```

### Callback Style

```diff
- import test from "tape";
+ import { test } from 'node:test';
+ import assert from 'node:assert/strict';

- test("callback style", (t) => {
+ test("callback style", (t, done) => {
setTimeout(() => {
- t.ok(true);
+ assert.ok(true);
- t.end();
+ done();
}, 100);
});
```

### Timeout Handling

```diff
- import test from "tape";
+ import { test } from 'node:test';
+ import assert from 'node:assert/strict';

- test("timeout test", (t) => {
+ test("timeout test", { timeout: 100 }, async (t) => {
- t.timeoutAfter(100);
- t.ok(true);
+ assert.ok(true);
- t.end();
+ // t.end();
Comment thread
AugustinMauroy marked this conversation as resolved.
Outdated
});
```

### Dynamic Import

```diff
async function run() {
- const test = await import("tape");
+ const { test } = await import('node:test');
+ const { default: assert } = await import('node:assert/strict');

- test("dynamic import", (t) => {
+ test("dynamic import", async (t) => {
- t.ok(true);
+ assert.ok(true);
- t.end();
+ // t.end();
Comment thread
AugustinMauroy marked this conversation as resolved.
});
}
```
23 changes: 23 additions & 0 deletions recipes/tape-to-node-test/codemod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
schema_version: "1.0"
name: "@nodejs/tape-to-node-test"
version: "1.0.0"
description: Migrates Tape tests to Node.js native test runner
author: Node.js
license: MIT
workflow: workflow.yaml
category: migration

targets:
languages:
- javascript
- typescript

keywords:
- transformation
- migration
- tape
- node:test

capabilities:
- fs
- child_process
20 changes: 20 additions & 0 deletions recipes/tape-to-node-test/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@nodejs/tape-to-node-test",
"version": "1.0.0",
"description": "Migrates Tape tests to Node.js native test runner",
"type": "module",
"scripts": {
"test": "npx codemod jssg test -l typescript ./src/workflow.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/nodejs/userland-migrations.git",
"directory": "recipes/tape-to-node-test",
"bugs": "https://github.com/nodejs/userland-migrations/issues"
},
"author": "Node.js",
"license": "MIT",
"dependencies": {
"@nodejs/codemod-utils": "*"
}
}
8 changes: 8 additions & 0 deletions recipes/tape-to-node-test/src/remove-dependencies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import removeDependencies from '@nodejs/codemod-utils/remove-dependencies';

/**
* Remove tape and @types/tape dependencies from package.json
*/
export default function removeTapeDependencies(): string | null {
return removeDependencies(['tape', '@types/tape']);
}
Loading
Loading