From b98d265c72f4c36c69177c2986d2362bd9baa5dd Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 11 Dec 2025 10:30:31 -0800 Subject: [PATCH 1/2] chore: swap from tap to built-in node:test --- .github/workflows/audit.yml | 4 +- .github/workflows/ci-release.yml | 16 +- .github/workflows/ci.yml | 16 +- .github/workflows/post-dependabot.yml | 4 +- .github/workflows/pull-request.yml | 4 +- .github/workflows/release-integration.yml | 4 +- .github/workflows/release.yml | 8 +- lib/fixer.js | 9 + package.json | 23 +- test/basic.js | 50 ++-- test/consistency.js | 7 +- test/dependencies.js | 118 +++++++- test/extract-description.js | 72 +++++ test/github-urls.js | 31 +- test/mixedcase-names.js | 55 +++- test/normalize.js | 349 +++++++++++++++++----- test/scoped.js | 52 ++-- test/scripts.js | 88 +++++- test/strict.js | 23 +- test/typo.js | 25 +- 20 files changed, 728 insertions(+), 230 deletions(-) create mode 100644 test/extract-description.js diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 85282bd..2543d79 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -30,8 +30,8 @@ jobs: uses: actions/setup-node@v4 id: node with: - node-version: 22.x - check-latest: contains('22.x', '.x') + node-version: 24.x + check-latest: contains('24.x', '.x') - name: Install Latest npm uses: ./.github/actions/install-latest-npm with: diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index e9ab5ff..94bcb30 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -51,8 +51,8 @@ jobs: uses: actions/setup-node@v4 id: node with: - node-version: 22.x - check-latest: contains('22.x', '.x') + node-version: 24.x + check-latest: contains('24.x', '.x') - name: Install Latest npm uses: ./.github/actions/install-latest-npm with: @@ -95,6 +95,7 @@ jobs: - 20.x - 22.9.0 - 22.x + - 24.x exclude: - platform: { name: macOS, os: macos-13, shell: bash } node-version: 20.17.0 @@ -104,6 +105,8 @@ jobs: node-version: 22.9.0 - platform: { name: macOS, os: macos-13, shell: bash } node-version: 22.x + - platform: { name: macOS, os: macos-13, shell: bash } + node-version: 24.x runs-on: ${{ matrix.platform.os }} defaults: run: @@ -137,9 +140,14 @@ jobs: node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" + - name: Test (with coverage on Node >= 24) + if: ${{ startsWith(matrix.node-version, '24') }} + run: npm run test:cover --ignore-scripts + - name: Test (on Node 20 with globbing workaround) + if: ${{ startsWith(matrix.node-version, '20') }} + run: npm run test:node20 --ignore-scripts - name: Test + if: ${{ !startsWith(matrix.node-version, '24') && !startsWith(matrix.node-version, '20') }} run: npm test --ignore-scripts - name: Conclude Check uses: LouisBrunner/checks-action@v1.6.0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92a33b5..ecfdefb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,8 +34,8 @@ jobs: uses: actions/setup-node@v4 id: node with: - node-version: 22.x - check-latest: contains('22.x', '.x') + node-version: 24.x + check-latest: contains('24.x', '.x') - name: Install Latest npm uses: ./.github/actions/install-latest-npm with: @@ -71,6 +71,7 @@ jobs: - 20.x - 22.9.0 - 22.x + - 24.x exclude: - platform: { name: macOS, os: macos-13, shell: bash } node-version: 20.17.0 @@ -80,6 +81,8 @@ jobs: node-version: 22.9.0 - platform: { name: macOS, os: macos-13, shell: bash } node-version: 22.x + - platform: { name: macOS, os: macos-13, shell: bash } + node-version: 24.x runs-on: ${{ matrix.platform.os }} defaults: run: @@ -103,7 +106,12 @@ jobs: node: ${{ steps.node.outputs.node-version }} - name: Install Dependencies run: npm i --ignore-scripts --no-audit --no-fund - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" + - name: Test (with coverage on Node >= 24) + if: ${{ startsWith(matrix.node-version, '24') }} + run: npm run test:cover --ignore-scripts + - name: Test (on Node 20 with globbing workaround) + if: ${{ startsWith(matrix.node-version, '20') }} + run: npm run test:node20 --ignore-scripts - name: Test + if: ${{ !startsWith(matrix.node-version, '24') && !startsWith(matrix.node-version, '20') }} run: npm test --ignore-scripts diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index 3a91911..8e80d10 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -28,8 +28,8 @@ jobs: uses: actions/setup-node@v4 id: node with: - node-version: 22.x - check-latest: contains('22.x', '.x') + node-version: 24.x + check-latest: contains('24.x', '.x') - name: Install Latest npm uses: ./.github/actions/install-latest-npm with: diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index c69932d..9ecf311 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -34,8 +34,8 @@ jobs: uses: actions/setup-node@v4 id: node with: - node-version: 22.x - check-latest: contains('22.x', '.x') + node-version: 24.x + check-latest: contains('24.x', '.x') - name: Install Latest npm uses: ./.github/actions/install-latest-npm with: diff --git a/.github/workflows/release-integration.yml b/.github/workflows/release-integration.yml index 9ca9a2b..195f50a 100644 --- a/.github/workflows/release-integration.yml +++ b/.github/workflows/release-integration.yml @@ -45,8 +45,8 @@ jobs: uses: actions/setup-node@v4 id: node with: - node-version: 22.x - check-latest: contains('22.x', '.x') + node-version: 24.x + check-latest: contains('24.x', '.x') - name: Install Latest npm uses: ./.github/actions/install-latest-npm with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 53ff3c2..863f9eb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,8 +39,8 @@ jobs: uses: actions/setup-node@v4 id: node with: - node-version: 22.x - check-latest: contains('22.x', '.x') + node-version: 24.x + check-latest: contains('24.x', '.x') - name: Install Latest npm uses: ./.github/actions/install-latest-npm with: @@ -119,8 +119,8 @@ jobs: uses: actions/setup-node@v4 id: node with: - node-version: 22.x - check-latest: contains('22.x', '.x') + node-version: 24.x + check-latest: contains('24.x', '.x') - name: Install Latest npm uses: ./.github/actions/install-latest-npm with: diff --git a/lib/fixer.js b/lib/fixer.js index 49b97f5..0b8defa 100644 --- a/lib/fixer.js +++ b/lib/fixer.js @@ -393,9 +393,12 @@ function unParsePerson (person) { } function parsePerson (person) { + /* node:coverage disable */ + // not possible in normal flow if (typeof person !== 'string') { return person } + /* node:coverage enable */ var matchedName = person.match(/^([^(<]+)/) var matchedUrl = person.match(/\(([^()]+)\)/) var matchedEmail = person.match(/<([^<>]+)>/) @@ -425,9 +428,12 @@ function addOptionalDepsToDeps (data) { } function depObjectify (deps, type, warn) { + /* node:coverage disable */ + // not possible in normal flow if (!deps) { return {} } + /* node:coverage enable */ if (typeof deps === 'string') { deps = deps.trim().split(/[\n\r\s\t ,]+/) } @@ -459,9 +465,12 @@ function objectifyDeps (data, warn) { } function bugsTypos (bugs, warn) { + /* node:coverage disable */ + // not possible in normal flow if (!bugs) { return } + /* node:coverage enable */ Object.keys(bugs).forEach(function (k) { if (typos.bugs[k]) { warn('typo', k, typos.bugs[k], 'bugs') diff --git a/package.json b/package.json index 613ccf9..957711b 100644 --- a/package.json +++ b/package.json @@ -10,16 +10,18 @@ }, "main": "lib/normalize.js", "scripts": { - "test": "tap", + "test": "node --test './test/**/*.js'", "npmclilint": "npmcli-lint", "lint": "npm run eslint", "lintfix": "npm run eslint -- --fix", "posttest": "npm run lint", "postsnap": "npm run lintfix --", "postlint": "template-oss-check", - "snap": "tap", + "snap": "node --test --test-update-snapshots './test/**/*.js'", "template-oss-apply": "template-oss-apply --force", - "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"" + "eslint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", + "test:node20": "node --test test", + "test:cover": "node --test --experimental-test-coverage --test-timeout=3000 --test-coverage-lines=97 --test-coverage-functions=97 --test-coverage-branches=97 './test/**/*.js'" }, "dependencies": { "hosted-git-info": "^9.0.0", @@ -41,16 +43,9 @@ "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.28.1", - "publish": "true" - }, - "tap": { - "branches": 86, - "functions": 92, - "lines": 86, - "statements": 86, - "nyc-arg": [ - "--exclude", - "tap-snapshots/**" - ] + "publish": "true", + "testRunner": "node:test", + "latestCiVersion": 24, + "coverageThreshold": 97 } } diff --git a/test/basic.js b/test/basic.js index 98a1865..f50babc 100644 --- a/test/basic.js +++ b/test/basic.js @@ -1,9 +1,10 @@ -var tap = require('tap') -var normalize = require('../lib/normalize') -var path = require('path') -var fs = require('fs') +const test = require('node:test') +const assert = require('node:assert') +const normalize = require('../lib/normalize') +const path = require('path') +const fs = require('fs') -tap.test('basic test', function (t) { +test('basic test', function (t, done) { var p = path.resolve(__dirname, './fixtures/read-package-json.json') fs.readFile(p, function (err, contents) { if (err) { @@ -12,28 +13,29 @@ tap.test('basic test', function (t) { var originalData = JSON.parse(contents.toString()) var data = JSON.parse(contents.toString()) normalize(data) - t.ok(data) - verifyFields(t, data, originalData) - t.end() + assert.ok(data) + verifyFields(data, originalData) + done() }) }) -function verifyFields (t, normalized, original) { - t.equal(normalized.version, original.version, 'Version field stays same') - t.equal(normalized._id, normalized.name + '@' + normalized.version, 'It gets good id.') - t.equal(normalized.name, original.name, 'Name stays the same.') - t.type(normalized.author, 'object', 'author field becomes object') - t.same(normalized.scripts, original.scripts, 'scripts field (object) stays same') - t.equal(normalized.main, original.main) +function verifyFields (normalized, original) { + assert.strictEqual(normalized.version, original.version, 'Version field stays same') + assert.strictEqual(normalized._id, normalized.name + '@' + normalized.version, 'It gets good id.') + assert.strictEqual(normalized.name, original.name, 'Name stays the same.') + assert.strictEqual(typeof normalized.author, 'object', 'author field becomes object') + assert.deepStrictEqual(normalized.scripts, original.scripts, 'scripts field (object) stays same') + assert.strictEqual(normalized.main, original.main) // optional deps are folded in. - t.same(normalized.optionalDependencies, + assert.deepStrictEqual(normalized.optionalDependencies, original.optionalDependencies) - t.has( - normalized.dependencies, - original.optionalDependencies, 'opt depedencies are copied into dependencies' - ) - t.has(normalized.dependencies, original.dependencies, 'regular depedencies stay in place') - t.same(normalized.devDependencies, original.devDependencies) - t.type(normalized.bugs, 'object', 'bugs should become object') - t.equal(normalized.bugs.url, 'https://github.com/isaacs/read-package-json/issues') + for (const key in original.optionalDependencies) { + assert.ok(key in normalized.dependencies, 'opt depedencies are copied into dependencies') + } + for (const key in original.dependencies) { + assert.ok(key in normalized.dependencies, 'regular depedencies stay in place') + } + assert.deepStrictEqual(normalized.devDependencies, original.devDependencies) + assert.strictEqual(typeof normalized.bugs, 'object', 'bugs should become object') + assert.strictEqual(normalized.bugs.url, 'https://github.com/isaacs/read-package-json/issues') } diff --git a/test/consistency.js b/test/consistency.js index e1d6527..b4f6745 100644 --- a/test/consistency.js +++ b/test/consistency.js @@ -1,4 +1,5 @@ -const t = require('tap') +const test = require('node:test') +const assert = require('node:assert') const normalize = require('../lib/normalize') const fs = require('fs') const path = require('path') @@ -6,7 +7,7 @@ const { promisify } = require('util') const readFile = promisify(fs.readFile) const readdir = promisify(fs.readdir) -t.test('consistent normalization', async t => { +test('consistent normalization', async () => { const entries = await readdir(path.join(__dirname, 'fixtures')) const verifyConsistency = async (entryName) => { const warn = () => null @@ -17,7 +18,7 @@ t.test('consistent normalization', async t => { normalize(data, warn) const clonedData = { ...data } normalize(data, warn) - t.same(clonedData, data, + assert.deepStrictEqual(clonedData, data, 'Normalization of ' + entryName + ' is consistent.') } diff --git a/test/dependencies.js b/test/dependencies.js index 1458f65..7e232d4 100644 --- a/test/dependencies.js +++ b/test/dependencies.js @@ -1,10 +1,11 @@ -var tap = require('tap') -var normalize = require('../lib/normalize') +const test = require('node:test') +const assert = require('node:assert') +const normalize = require('../lib/normalize') -var warningMessages = require('../lib/warning_messages.json') -var safeFormat = require('../lib/safe_format') +const warningMessages = require('../lib/warning_messages.json') +const safeFormat = require('../lib/safe_format') -tap.test('warn if dependency contains anything else but a string', function (t) { +test('warn if dependency contains anything else but a string', function () { var warnings = [] function warn (w) { warnings.push(w) @@ -18,13 +19,12 @@ tap.test('warn if dependency contains anything else but a string', function (t) var wanted1 = safeFormat(warningMessages.nonStringDependency, 'a', 123) var wanted2 = safeFormat(warningMessages.nonStringDependency, 'b', 456) var wanted3 = safeFormat(warningMessages.nonStringDependency, 'c', 789) - t.ok(~warnings.indexOf(wanted1), wanted1) - t.ok(~warnings.indexOf(wanted2), wanted2) - t.ok(~warnings.indexOf(wanted3), wanted3) - t.end() + assert.ok(warnings.includes(wanted1), wanted1) + assert.ok(warnings.includes(wanted2), wanted2) + assert.ok(warnings.includes(wanted3), wanted3) }) -tap.test('warn if bundleDependencies array contains anything else but strings', function (t) { +test('warn if bundleDependencies array contains anything else but strings', function () { var warnings = [] function warn (w) { warnings.push(w) @@ -43,10 +43,96 @@ tap.test('warn if bundleDependencies array contains anything else but strings', var wanted1 = safeFormat(warningMessages.nonStringBundleDependency, 123) var wanted2 = safeFormat(warningMessages.nonStringBundleDependency, { foo: 'bar' }) var wanted3 = safeFormat(warningMessages.nonDependencyBundleDependency, 'abc') - t.ok(~warnings.indexOf(wanted1), wanted1) - t.ok(~warnings.indexOf(wanted2), wanted2) - t.ok(~warnings.indexOf(wanted3), wanted3) - t.equal(pkg.dependencies.abc, '*', 'added bundled dep to dependencies with *') - t.equal(pkg.dependencies.def, '^1.0.0', 'left def dependency alone') - t.end() + assert.ok(warnings.includes(wanted1), wanted1) + assert.ok(warnings.includes(wanted2), wanted2) + assert.ok(warnings.includes(wanted3), wanted3) + assert.strictEqual(pkg.dependencies.abc, '*', 'added bundled dep to dependencies with *') + assert.strictEqual(pkg.dependencies.def, '^1.0.0', 'left def dependency alone') +}) + +test('warn if bundleDependencies is not an array', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + bundleDependencies: 'not-an-array', + } + normalize(data, warn) + assert.strictEqual(data.bundleDependencies, undefined, 'non-array bundleDependencies should be removed') + assert.ok( + warnings.some(w => w.includes("Invalid 'bundleDependencies' list")), + 'should warn about non-array bundleDependencies' + ) +}) + +test('warn if bundleDependencies is an object', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + bundleDependencies: { foo: 'bar' }, + } + normalize(data, warn) + assert.strictEqual(data.bundleDependencies, undefined, 'object bundleDependencies should be removed') + assert.ok( + warnings.some(w => w.includes("Invalid 'bundleDependencies' list")), + 'should warn about non-array bundleDependencies' + ) +}) + +test('warn if dependencies is not an object', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + dependencies: null, + devDependencies: 123, + } + normalize(data, warn) + assert.strictEqual(data.dependencies, undefined, 'null dependencies should be removed') + assert.strictEqual(data.devDependencies, undefined, 'number devDependencies should be removed') + assert.ok( + warnings.some(w => w.includes('dependencies') && w.includes('field must be an object')), + 'should warn about non-object dependencies' + ) + assert.ok( + warnings.some(w => w.includes('devDependencies') && w.includes('field must be an object')), + 'should warn about non-object devDependencies' + ) +}) + +test('safeFormat throws TypeError on falsy argument', function () { + assert.throws( + () => safeFormat(null), + { name: 'TypeError', message: 'Bad arguments.' } + ) + assert.throws( + () => safeFormat(undefined), + { name: 'TypeError', message: 'Bad arguments.' } + ) + assert.throws( + () => safeFormat(''), + { name: 'TypeError', message: 'Bad arguments.' } + ) + assert.throws( + () => safeFormat(0), + { name: 'TypeError', message: 'Bad arguments.' } + ) + assert.throws( + () => safeFormat(false), + { name: 'TypeError', message: 'Bad arguments.' } + ) + assert.throws( + () => safeFormat('valid', null), + { name: 'TypeError', message: 'Bad arguments.' } + ) }) diff --git a/test/extract-description.js b/test/extract-description.js new file mode 100644 index 0000000..4ed8d81 --- /dev/null +++ b/test/extract-description.js @@ -0,0 +1,72 @@ +const { test } = require('node:test') +const assert = require('node:assert') +const extractDescription = require('../lib/extract_description.js') + +test('returns undefined for falsy input (!d)', function () { + assert.strictEqual(extractDescription(null), undefined) + assert.strictEqual(extractDescription(undefined), undefined) + assert.strictEqual(extractDescription(''), undefined) + assert.strictEqual(extractDescription(0), undefined) + assert.strictEqual(extractDescription(false), undefined) +}) + +test('returns undefined for ERROR message', function () { + assert.strictEqual(extractDescription('ERROR: No README data found!'), undefined) +}) + +test('skips heading lines to reach s++ (lines starting with # or empty)', function () { + const readme = `# Title + +## Subtitle + +This is the description.` + assert.strictEqual(extractDescription(readme), 'This is the description.') +}) + +test('skips multiple headings and empty lines', function () { + const readme = '# Main Title\n\nThis is the actual description text.\nAnd more description.' + assert.strictEqual(extractDescription(readme), 'This is the actual description text. And more description.') +}) + +test('iterates through description lines to reach e++ (multi-line description)', function () { + const readme = `# Title + +This is line one of the description. +This is line two of the description. +This is line three of the description. + +Another paragraph here.` + assert.strictEqual( + extractDescription(readme), + 'This is line one of the description. This is line two of the description. This is line three of the description.' + ) +}) + +test('stops at first empty line after description', function () { + const readme = `Description line 1 +Description line 2 + +This should not be included` + assert.strictEqual(extractDescription(readme), 'Description line 1 Description line 2') +}) + +test('handles single line description', function () { + const readme = 'Just a simple description' + assert.strictEqual(extractDescription(readme), 'Just a simple description') +}) + +test('trims whitespace from description', function () { + const readme = ` + + Description with leading spaces + +More content` + assert.strictEqual(extractDescription(readme), 'Description with leading spaces') +}) + +test('handles description starting immediately after heading', function () { + const readme = `# Heading +Description starts here +And continues here` + assert.strictEqual(extractDescription(readme), 'Description starts here And continues here') +}) diff --git a/test/github-urls.js b/test/github-urls.js index 47a5de4..d06fc7d 100644 --- a/test/github-urls.js +++ b/test/github-urls.js @@ -1,11 +1,12 @@ -const t = require('tap') +const test = require('node:test') +const assert = require('node:assert') const normalize = require('../lib/normalize') const fs = require('fs') const path = require('path') const { promisify } = require('util') const readFile = promisify(fs.readFile) -t.test('consistent normalization', async t => { +test('consistent normalization', async () => { const entries = [ 'read-package-json.json', 'http-server.json', @@ -19,17 +20,35 @@ t.test('consistent normalization', async t => { const data = JSON.parse(contents.toString()) normalize(data, warn) if (data.name === 'node-module_exist') { - t.same(data.bugs.url, 'https://gist.github.com/3135914') + assert.deepStrictEqual(data.bugs.url, 'https://gist.github.com/3135914') } if (data.name === 'read-package-json') { - t.same(data.bugs.url, 'https://github.com/isaacs/read-package-json/issues') + assert.deepStrictEqual(data.bugs.url, 'https://github.com/isaacs/read-package-json/issues') } if (data.name === 'http-server') { - t.same(data.bugs.url, 'https://github.com/nodejitsu/http-server/issues') + assert.deepStrictEqual(data.bugs.url, 'https://github.com/nodejitsu/http-server/issues') } if (data.name === 'movefile') { - t.same(data.bugs.url, 'https://github.com/yazgazan/movefile/issues') + assert.deepStrictEqual(data.bugs.url, 'https://github.com/yazgazan/movefile/issues') } } return Promise.all(entries.map(i => verifyConsistency(i))) }) + +test('warns about broken git URL with double .git.git', function () { + const warnings = [] + const warn = (w) => warnings.push(w) + const data = { + name: 'test-package', + version: '1.0.0', + repository: { + type: 'git', + url: 'https://github.com/user/repo.git.git', + }, + } + normalize(data, warn) + assert.ok( + warnings.some(w => w.includes('Probably broken git url')), + 'should warn about broken git URL' + ) +}) diff --git a/test/mixedcase-names.js b/test/mixedcase-names.js index a44bed8..ded5d8c 100644 --- a/test/mixedcase-names.js +++ b/test/mixedcase-names.js @@ -1,32 +1,65 @@ -var test = require('tap').test +const test = require('node:test') +const assert = require('node:assert') -var normalize = require('../') -var fixer = normalize.fixer +const normalize = require('../') +const fixer = normalize.fixer -test('mixedcase', function (t) { - t.doesNotThrow(function () { +test('mixedcase', function () { + assert.doesNotThrow(function () { fixer.fixNameField({ name: 'foo' }, true) }) - t.doesNotThrow(function () { + assert.doesNotThrow(function () { fixer.fixNameField({ name: 'foo' }, false) }) - t.doesNotThrow(function () { + assert.doesNotThrow(function () { fixer.fixNameField({ name: 'foo' }) }) - t.throws(function () { + assert.throws(function () { fixer.fixNameField({ name: 'Foo' }, true) }, new Error('Invalid name: "Foo"'), 'should throw an error') - t.throws(function () { + assert.throws(function () { fixer.fixNameField({ name: 'Foo' }, { strict: true }) }, new Error('Invalid name: "Foo"'), 'should throw an error') - t.doesNotThrow(function () { + assert.doesNotThrow(function () { fixer.fixNameField({ name: 'Foo' }, { strict: true, allowLegacyCase: true }) }) +}) + +test('non-string name throws error', function () { + assert.throws( + function () { + fixer.fixNameField({ name: 123 }, true) + }, + { name: 'Error', message: 'name field must be a string.' }, + 'should throw error for number name' + ) + + assert.throws( + function () { + fixer.fixNameField({ name: { foo: 'bar' } }, true) + }, + { name: 'Error', message: 'name field must be a string.' }, + 'should throw error for object name' + ) + + assert.throws( + function () { + fixer.fixNameField({ name: ['array'] }, true) + }, + { name: 'Error', message: 'name field must be a string.' }, + 'should throw error for array name' + ) - t.end() + assert.throws( + function () { + fixer.fixNameField({ name: null }, true) + }, + { name: 'Error', message: 'name field must be a string.' }, + 'should throw error for null name' + ) }) diff --git a/test/normalize.js b/test/normalize.js index 65c38bf..37bcbea 100644 --- a/test/normalize.js +++ b/test/normalize.js @@ -1,43 +1,45 @@ -var tap = require('tap') -var fs = require('fs') -var path = require('path') +const test = require('node:test') +const assert = require('node:assert') +const fs = require('fs') +const path = require('path') -var normalize = require('../lib/normalize') -var warningMessages = require('../lib/warning_messages.json') -var safeFormat = require('../lib/safe_format') +const normalize = require('../lib/normalize') +const warningMessages = require('../lib/warning_messages.json') +const safeFormat = require('../lib/safe_format') +const makeWarning = require('../lib/make_warning') -var rpjPath = path.resolve(__dirname, './fixtures/read-package-json.json') +const rpjPath = path.resolve(__dirname, './fixtures/read-package-json.json') -tap.test('normalize some package data', function (t) { +test('normalize some package data', function (t, done) { var packageData = require(rpjPath) var warnings = [] normalize(packageData, function (warning) { warnings.push(warning) }) // there's no readme data in this particular object - t.equal(warnings.length, 1, "There's exactly one warning.") + assert.strictEqual(warnings.length, 1, "There's exactly one warning.") fs.readFile(rpjPath, function (err, data) { if (err) { throw err } // Various changes have been made - t.not(packageData, JSON.parse(data), 'Output is different from input.') - t.end() + assert.notDeepStrictEqual(packageData, JSON.parse(data), 'Output is different from input.') + done() }) }) -tap.test('runs without passing warning function', function (t) { +test('runs without passing warning function', function (t, done) { fs.readFile(rpjPath, function (err, data) { if (err) { throw err } normalize(JSON.parse(data)) - t.ok(true, "If you read this, this means I'm still alive.") - t.end() + assert.ok(true, "If you read this, this means I'm still alive.") + done() }) }) -tap.test('empty object', function (t) { +test('empty object', function () { var packageData = {} var expect = { name: '', @@ -50,17 +52,16 @@ tap.test('empty object', function (t) { warnings.push(m) } normalize(packageData, warn) - t.same(packageData, expect) - t.same(warnings, [ + assert.deepStrictEqual(packageData, expect) + assert.deepStrictEqual(warnings, [ warningMessages.missingDescription, warningMessages.missingRepository, warningMessages.missingReadme, warningMessages.missingLicense, ]) - t.end() }) -tap.test('core module name', function (t) { +test('core module name', function () { var warnings = [] function warn (m) { warnings.push(m) @@ -84,11 +85,10 @@ tap.test('core module name', function (t) { warningMessages.missingLicense, ]) } - t.same(warnings, expect) - t.end() + assert.deepStrictEqual(warnings, expect) }) -tap.test('urls required', function (t) { +test('urls required', function () { var warnings = [] function warn (w) { warnings.push(w) @@ -118,11 +118,10 @@ tap.test('urls required', function (t) { warningMessages.emptyNormalizedBugs, warningMessages.nonUrlHomepage, warningMessages.missingLicense] - t.same(warnings, expect) - t.end() + assert.deepStrictEqual(warnings, expect) }) -tap.test('homepage field must start with a protocol.', function (t) { +test('homepage field must start with a protocol.', function () { var warnings = [] function warn (w) { warnings.push(w) @@ -137,12 +136,11 @@ tap.test('homepage field must start with a protocol.', function (t) { warningMessages.missingRepository, warningMessages.missingReadme, warningMessages.missingLicense] - t.same(warnings, expect) - t.same(a.homepage, 'http://example.org') - t.end() + assert.deepStrictEqual(warnings, expect) + assert.deepStrictEqual(a.homepage, 'http://example.org') }) -tap.test('license field should be a valid SPDX expression', function (t) { +test('license field should be a valid SPDX expression', function () { var warnings = [] function warn (w) { warnings.push(w) @@ -156,11 +154,10 @@ tap.test('license field should be a valid SPDX expression', function (t) { warningMessages.missingRepository, warningMessages.missingReadme, warningMessages.invalidLicense] - t.same(warnings, expect) - t.end() + assert.deepStrictEqual(warnings, expect) }) -tap.test("don't fail when license is just a space", function (t) { +test("don't fail when license is just a space", function () { var warnings = [] function warn (w) { warnings.push(w) @@ -174,11 +171,10 @@ tap.test("don't fail when license is just a space", function (t) { warningMessages.missingRepository, warningMessages.missingReadme, warningMessages.invalidLicense] - t.same(warnings, expect) - t.end() + assert.deepStrictEqual(warnings, expect) }) -tap.test("don't fail when license is licence", function (t) { +test("don't fail when license is licence", function () { var warnings = [] function warn (w) { warnings.push(w) @@ -190,77 +186,88 @@ tap.test("don't fail when license is licence", function (t) { licence: 'MIT', }, warn) - t.same(warnings, []) - t.end() + assert.deepStrictEqual(warnings, []) }) -tap.test('gist bugs url', function (t) { +test('gist bugs url', function () { var d = { repository: 'git@gist.github.com:1234567.git', } normalize(d) - t.same(d.repository, { type: 'git', url: 'git+ssh://git@gist.github.com/1234567.git' }) - t.same(d.bugs, { url: 'https://gist.github.com/1234567' }) - t.end() + assert.deepStrictEqual(d.repository, { type: 'git', url: 'git+ssh://git@gist.github.com/1234567.git' }) + assert.deepStrictEqual(d.bugs, { url: 'https://gist.github.com/1234567' }) }) -tap.test('singularize repositories', function (t) { +test('singularize repositories', function () { var d = { repositories: ['git@gist.github.com:1234567.git'] } normalize(d) - t.same(d.repository, { type: 'git', url: 'git+ssh://git@gist.github.com/1234567.git' }) - t.end() + assert.deepStrictEqual(d.repository, { type: 'git', url: 'git+ssh://git@gist.github.com/1234567.git' }) }) -tap.test('treat visionmedia/express as github repo', function (t) { +test('treat visionmedia/express as github repo', function () { var d = { repository: { type: 'git', url: 'visionmedia/express' } } normalize(d) - t.same(d.repository, { type: 'git', url: 'git+https://github.com/visionmedia/express.git' }) - t.end() + assert.deepStrictEqual(d.repository, { type: 'git', url: 'git+https://github.com/visionmedia/express.git' }) }) -tap.test('treat isaacs/node-graceful-fs as github repo', function (t) { +test('treat isaacs/node-graceful-fs as github repo', function () { var d = { repository: { type: 'git', url: 'isaacs/node-graceful-fs' } } normalize(d) - t.same(d.repository, { type: 'git', url: 'git+https://github.com/isaacs/node-graceful-fs.git' }) - t.end() + assert.deepStrictEqual(d.repository, { type: 'git', url: 'git+https://github.com/isaacs/node-graceful-fs.git' }) }) -tap.test('homepage field will set to github url if repository is a github repo', function (t) { +test('homepage field will set to github url if repository is a github repo', function () { var a normalize(a = { repository: { type: 'git', url: 'https://github.com/isaacs/node-graceful-fs' }, }) - t.same(a.homepage, 'https://github.com/isaacs/node-graceful-fs#readme') - t.end() + assert.deepStrictEqual(a.homepage, 'https://github.com/isaacs/node-graceful-fs#readme') }) -tap.test('homepage field will set to github gist url if repository is a gist', function (t) { +test('homepage field will set to github gist url if repository is a gist', function () { var a normalize(a = { repository: { type: 'git', url: 'git@gist.github.com:1234567.git' }, }) - t.same(a.homepage, 'https://gist.github.com/1234567') - t.end() + assert.deepStrictEqual(a.homepage, 'https://gist.github.com/1234567') }) /* eslint-disable-next-line max-len */ -tap.test('homepage field will set to github gist url if repository is a shorthand reference', function (t) { +test('homepage field will set to github gist url if repository is a shorthand reference', function () { var a normalize(a = { repository: { type: 'git', url: 'sindresorhus/chalk' }, }) - t.same(a.homepage, 'https://github.com/sindresorhus/chalk#readme') - t.end() + assert.deepStrictEqual(a.homepage, 'https://github.com/sindresorhus/chalk#readme') }) -tap.test("don't mangle github shortcuts in dependencies", function (t) { +test("don't mangle github shortcuts in dependencies", function () { var d = { dependencies: { 'node-graceful-fs': 'isaacs/node-graceful-fs' } } normalize(d) - t.same(d.dependencies, { 'node-graceful-fs': 'github:isaacs/node-graceful-fs' }) - t.end() + assert.deepStrictEqual(d.dependencies, { 'node-graceful-fs': 'github:isaacs/node-graceful-fs' }) }) -tap.test('deprecation warning for array in dependencies fields', function (t) { +test('deprecation warning for string in dependencies fields', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + dependencies: 'express@4.0.0, lodash@3.0.0', + } + normalize(data, warn) + assert.ok(typeof data.dependencies === 'object', 'string dependencies converted to object') + assert.ok(data.dependencies.express, 'express dependency parsed') + assert.ok(data.dependencies.lodash, 'lodash dependency parsed') + assert.ok( + warnings.includes(safeFormat(warningMessages.deprecatedArrayDependencies, 'dependencies')), + 'deprecation warning for string dependencies' + ) +}) + +test('deprecation warning for array in dependencies fields', function () { var warnings = [] function warn (w) { warnings.push(w) @@ -270,19 +277,221 @@ tap.test('deprecation warning for array in dependencies fields', function (t) { devDependencies: [], optionalDependencies: [], }, warn) - t.ok( - ~warnings.indexOf(safeFormat(warningMessages.deprecatedArrayDependencies, 'dependencies')), + assert.ok( + warnings.includes(safeFormat(warningMessages.deprecatedArrayDependencies, 'dependencies')), 'deprecation warning' ) - t.ok( - ~warnings.indexOf(safeFormat(warningMessages.deprecatedArrayDependencies, 'devDependencies')), + assert.ok( + warnings.includes(safeFormat(warningMessages.deprecatedArrayDependencies, 'devDependencies')), 'deprecation warning' ) - t.ok( - ~warnings.indexOf( + assert.ok( + warnings.includes( safeFormat(warningMessages.deprecatedArrayDependencies, 'optionalDependencies') ), 'deprecation warning' ) - t.end() +}) + +test('removes non-array files field', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + files: 'not an array', + } + normalize(data, warn) + assert.strictEqual(data.files, undefined, 'non-array files field should be removed') + assert.ok( + warnings.some(w => w.includes("Invalid 'files' member")), + 'should warn about non-array files field' + ) +}) + +test('filters out invalid filenames from files array', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + files: [ + 'valid-file.js', + 'src/another-valid.js', + null, + '', + 123, + { file: 'object.js' }, + 'README.md', + ], + } + normalize(data, warn) + assert.deepStrictEqual( + data.files, + ['valid-file.js', 'src/another-valid.js', 'README.md'], + 'only valid string filenames should remain' + ) + assert.ok( + warnings.some(w => w.includes("Invalid filename in 'files' list")), + 'should warn about invalid filenames' + ) +}) + +test('converts string man field to array', function () { + var data = { + name: 'test-package', + version: '1.0.0', + man: './man/doc.1', + } + normalize(data) + assert.ok(Array.isArray(data.man), 'man field should be converted to array') + assert.deepStrictEqual(data.man, ['./man/doc.1'], 'man field should contain the original string') +}) + +test('leaves array man field unchanged', function () { + var data = { + name: 'test-package', + version: '1.0.0', + man: ['./man/doc.1', './man/doc.2'], + } + normalize(data) + assert.ok(Array.isArray(data.man), 'man field should remain an array') + assert.deepStrictEqual( + data.man, + ['./man/doc.1', './man/doc.2'], + 'man field should remain unchanged' + ) +}) + +test('warns about deprecated modules field', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + modules: ['some', 'modules'], + } + normalize(data, warn) + assert.strictEqual(data.modules, undefined, 'modules field should be removed') + assert.ok( + warnings.some(w => w.includes('modules field is deprecated')), + 'should warn about deprecated modules field' + ) +}) + +test('converts string keywords to array', function () { + var data = { + name: 'test-package', + version: '1.0.0', + keywords: 'javascript, node, testing, awesome', + } + normalize(data) + assert.ok(Array.isArray(data.keywords), 'keywords should be converted to array') + assert.deepStrictEqual( + data.keywords, + ['javascript', 'node', 'testing', 'awesome'], + 'keywords should be split by comma and space' + ) +}) + +test('leaves array keywords unchanged', function () { + var data = { + name: 'test-package', + version: '1.0.0', + keywords: ['javascript', 'node', 'testing'], + } + normalize(data) + assert.ok(Array.isArray(data.keywords), 'keywords should remain an array') + assert.deepStrictEqual( + data.keywords, + ['javascript', 'node', 'testing'], + 'keywords should remain unchanged' + ) +}) + +test('removes non-array keywords and warns', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + keywords: { key: 'value' }, + } + normalize(data, warn) + assert.strictEqual(data.keywords, undefined, 'non-array keywords should be removed') + assert.ok( + warnings.some(w => w.includes('keywords should be an array of strings')), + 'should warn about non-array keywords' + ) +}) + +test('filters out non-string keywords from array', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + keywords: ['valid', 123, null, '', { key: 'value' }, 'another-valid'], + } + normalize(data, warn) + assert.deepStrictEqual( + data.keywords, + ['valid', 'another-valid'], + 'only valid string keywords should remain' + ) + assert.ok( + warnings.some(w => w.includes('keywords should be an array of strings')), + 'should warn about non-string keywords' + ) +}) + +test('removes non-string description and warns', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + description: { text: 'should be a string' }, + } + normalize(data, warn) + assert.strictEqual(data.description, undefined, 'non-string description should be removed') + assert.ok( + warnings.some(w => w.includes("'description' field should be a string")), + 'should warn about non-string description' + ) +}) + +test('makeWarning handles unknown warning types with fallback format', function () { + var result = makeWarning('unknownWarningType', 'someValue') + assert.strictEqual(result, "unknownWarningType: 'someValue'", 'should use fallback format for unknown warnings') +}) + +test('passing true as warn parameter enables strict mode', function () { + assert.throws( + () => normalize({ name: 'UpperCase', version: '1.0.0' }, true), + { message: /Invalid name/ }, + 'strict mode should reject uppercase names' + ) +}) + +test('normalizes shortcut repository format to https', function () { + var data = { + name: 'test-package', + version: '1.0.0', + repository: 'github:user/repo', + } + normalize(data) + assert.strictEqual(data.repository.type, 'git', 'type should be git') }) diff --git a/test/scoped.js b/test/scoped.js index b8c1dcc..f12b8d1 100644 --- a/test/scoped.js +++ b/test/scoped.js @@ -1,59 +1,53 @@ -var test = require('tap').test +const test = require('node:test') +const assert = require('node:assert') -var fixNameField = require('../lib/fixer.js').fixNameField -var fixBinField = require('../lib/fixer.js').fixBinField +const fixNameField = require('../lib/fixer.js').fixNameField +const fixBinField = require('../lib/fixer.js').fixBinField -test('a simple scoped module has a valid name', function (t) { +test('a simple scoped module has a valid name', function () { var data = { name: '@org/package' } fixNameField(data, false) - t.equal(data.name, '@org/package', 'name was unchanged') - - t.end() + assert.strictEqual(data.name, '@org/package', 'name was unchanged') }) -test("'org@package' is not a valid name", function (t) { - t.throws(function () { +test("'org@package' is not a valid name", function () { + assert.throws(function () { fixNameField({ name: 'org@package' }, false) }, 'blows up as expected') - - t.end() }) -test("'org=package' is not a valid name", function (t) { - t.throws(function () { +test("'org=package' is not a valid name", function () { + assert.throws(function () { fixNameField({ name: 'org=package' }, false) }, 'blows up as expected') - - t.end() }) -test("'@org=sub/package' is not a valid name", function (t) { - t.throws(function () { +test("'@org=sub/package' is not a valid name", function () { + assert.throws(function () { fixNameField({ name: '@org=sub/package' }, false) }, 'blows up as expected') - - t.end() }) -test("'@org/' is not a valid name", function (t) { - t.throws(function () { +test("'@org/' is not a valid name", function () { + assert.throws(function () { fixNameField({ name: '@org/' }, false) }, 'blows up as expected') - - t.end() }) -test("'@/package' is not a valid name", function (t) { - t.throws(function () { +test("'@/package' is not a valid name", function () { + assert.throws(function () { fixNameField({ name: '@/package' }, false) }, 'blows up as expected') +}) - t.end() +test("'@org/sub/package' is not a valid name (too many slashes)", function () { + assert.throws(function () { + fixNameField({ name: '@org/sub/package' }, false) + }, { message: /Invalid name/ }, 'blows up when scoped name has more than one slash') }) -test("name='@org/package', bin='bin.js' is bin={package:'bin.js'}", function (t) { +test("name='@org/package', bin='bin.js' is bin={package:'bin.js'}", function () { var obj = { name: '@org/package', bin: 'bin.js' } fixBinField(obj) - t.strictSame(obj.bin, { package: 'bin.js' }) - t.end() + assert.deepStrictEqual(obj.bin, { package: 'bin.js' }) }) diff --git a/test/scripts.js b/test/scripts.js index c2cf040..d2a00e0 100644 --- a/test/scripts.js +++ b/test/scripts.js @@ -1,9 +1,10 @@ -var tap = require('tap') -var normalize = require('../lib/normalize') -var path = require('path') -var fs = require('fs') +const test = require('node:test') +const assert = require('node:assert') +const normalize = require('../lib/normalize') +const path = require('path') +const fs = require('fs') -tap.test('bad scripts', function (t) { +test('bad scripts', function (t, done) { var p = path.resolve(__dirname, './fixtures/badscripts.json') fs.readFile(p, function (err, contents) { if (err) { @@ -12,15 +13,78 @@ tap.test('bad scripts', function (t) { var originalData = JSON.parse(contents.toString()) var data = JSON.parse(contents.toString()) normalize(data) - t.ok(data) - verifyFields(t, data, originalData) - t.end() + assert.ok(data) + verifyFields(data, originalData) + done() }) }) -function verifyFields (t, normalized, original) { - t.equal(normalized.version, original.version, 'Version field stays same') - t.equal(normalized.name, original.name, 'Name stays the same.') +function verifyFields (normalized, original) { + assert.strictEqual(normalized.version, original.version, 'Version field stays same') + assert.strictEqual(normalized.name, original.name, 'Name stays the same.') // scripts is not an object, so it should be deleted - t.notOk(normalized.scripts) + assert.ok(!normalized.scripts) } + +test('sets gypfile to true when install script is node-gyp rebuild', function () { + var data = { + name: 'test-package', + version: '1.0.0', + scripts: { + install: 'node-gyp rebuild', + }, + } + normalize(data) + assert.strictEqual(data.gypfile, true, 'gypfile should be set to true') +}) + +test('does not set gypfile when install script is different', function () { + var data = { + name: 'test-package', + version: '1.0.0', + scripts: { + install: 'some other command', + }, + } + normalize(data) + assert.strictEqual(data.gypfile, undefined, 'gypfile should not be set') +}) + +test('does not set gypfile when preinstall script exists', function () { + var data = { + name: 'test-package', + version: '1.0.0', + scripts: { + install: 'node-gyp rebuild', + preinstall: 'echo preinstall', + }, + } + normalize(data) + assert.strictEqual(data.gypfile, undefined, 'gypfile should not be set when preinstall exists') +}) + +test('removes non-string script values', function () { + var warnings = [] + function warn (w) { + warnings.push(w) + } + var data = { + name: 'test-package', + version: '1.0.0', + scripts: { + test: 'echo test', + build: 123, + start: { command: 'node server.js' }, + deploy: null, + }, + } + normalize(data, warn) + assert.strictEqual(data.scripts.test, 'echo test', 'valid string script should remain') + assert.strictEqual(data.scripts.build, undefined, 'number script should be removed') + assert.strictEqual(data.scripts.start, undefined, 'object script should be removed') + assert.strictEqual(data.scripts.deploy, undefined, 'null script should be removed') + assert.ok( + warnings.some(w => w.includes('script values must be string commands')), + 'should warn about non-string scripts' + ) +}) diff --git a/test/strict.js b/test/strict.js index 78dd229..f45c7d7 100644 --- a/test/strict.js +++ b/test/strict.js @@ -1,8 +1,9 @@ -var test = require('tap').test +const test = require('node:test') +const assert = require('node:assert') -var normalize = require('../') +const normalize = require('../') -test('strict', function (t) { +test('strict', function () { var threw try { @@ -10,9 +11,9 @@ test('strict', function (t) { normalize({ name: 'X' }, true) } catch (er) { threw = true - t.equal(er.message, 'Invalid name: "X"') + assert.strictEqual(er.message, 'Invalid name: "X"') } finally { - t.equal(threw, true) + assert.strictEqual(threw, true) } try { @@ -20,9 +21,9 @@ test('strict', function (t) { normalize({ name: ' x ' }, true) } catch (er) { threw = true - t.equal(er.message, 'Invalid name: " x "') + assert.strictEqual(er.message, 'Invalid name: " x "') } finally { - t.equal(threw, true) + assert.strictEqual(threw, true) } try { @@ -30,9 +31,9 @@ test('strict', function (t) { normalize({ name: 'x', version: '01.02.03' }, true) } catch (er) { threw = true - t.equal(er.message, 'Invalid version: "01.02.03"') + assert.strictEqual(er.message, 'Invalid version: "01.02.03"') } finally { - t.equal(threw, true) + assert.strictEqual(threw, true) } // these should not throw @@ -43,7 +44,7 @@ test('strict', function (t) { z: '! 99 $$ASFJ(Aawenf90awenf as;naw.3j3qnraw || an elephant', } } normalize(slob, false) - t.same(slob, + assert.deepStrictEqual(slob, { name: 'X', version: '1.2.3', dependencies: @@ -51,6 +52,4 @@ test('strict', function (t) { z: '! 99 $$ASFJ(Aawenf90awenf as;naw.3j3qnraw || an elephant' }, readme: 'ERROR: No README data found!', _id: 'X@1.2.3' }) - - t.end() }) diff --git a/test/typo.js b/test/typo.js index 7110565..8039d8f 100644 --- a/test/typo.js +++ b/test/typo.js @@ -1,10 +1,11 @@ -var test = require('tap').test +const test = require('node:test') +const assert = require('node:assert') -var normalize = require('../') -var warningMessages = require('../lib/warning_messages.json') -var safeFormat = require('../lib/safe_format') +const normalize = require('../') +const warningMessages = require('../lib/warning_messages.json') +const safeFormat = require('../lib/safe_format') -test('typos', function (t) { +test('typos', function () { var warnings = [] function warn (m) { warnings.push(m) @@ -56,7 +57,7 @@ test('typos', function (t) { name: 'name', version: '1.2.5' }, warn) - t.same(warnings, expect) + assert.deepStrictEqual(warnings, expect) warnings.length = 0 expect = @@ -73,7 +74,7 @@ test('typos', function (t) { version: '1.2.5', bugs: { web: 'url', name: 'url' } }, warn) - t.same(warnings, expect) + assert.deepStrictEqual(warnings, expect) warnings.length = 0 expect = @@ -87,7 +88,7 @@ test('typos', function (t) { version: '1.2.5', script: { server: 'start', tests: 'test' } }, warn) - t.same(warnings, expect) + assert.deepStrictEqual(warnings, expect) warnings.length = 0 expect = @@ -102,7 +103,7 @@ test('typos', function (t) { version: '1.2.5', scripts: { server: 'start', tests: 'test' } }, warn) - t.same(warnings, expect) + assert.deepStrictEqual(warnings, expect) warnings.length = 0 expect = @@ -118,7 +119,7 @@ test('typos', function (t) { start: 'start', test: 'test' } }, warn) - t.same(warnings, expect) + assert.deepStrictEqual(warnings, expect) warnings.length = 0 expect = [] @@ -128,7 +129,5 @@ test('typos', function (t) { version: '1.2.5', scripts: { server: 'start', tests: 'test' } }, warn) - t.same(warnings, expect) - - t.end() + assert.deepStrictEqual(warnings, expect) }) From de44bf72787a404fb3e7b609d68be46799e12273 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 11 Dec 2025 10:31:09 -0800 Subject: [PATCH 2/2] chore: remove tap --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 957711b..b296b38 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^6.0.0", - "@npmcli/template-oss": "4.28.1", - "tap": "^16.0.1" + "@npmcli/template-oss": "4.28.1" }, "files": [ "bin/",