Commit e2eb47b

Anton Golub <antongolub@antongolub.com>
2025-08-17 19:44:01
test: refactor npm artifact checks (#1319)
* test: gather npm artifact checks * chore: tweak ups
1 parent 4844b49
.github/workflows/dev-publish.yml
@@ -84,8 +84,8 @@ jobs:
       - name: pushing lite snapshot to ${{ env.GOOGLE_NPM_REGISTRY }}
         run: |
           cat <<< $(jq '.name="zx"' package.json) > package.json
-          cat <<< $(jq '.version="${{ env.ZX_LITE_DEV_VERSION }}"' package.json) > package.json
           node scripts/prepublish-lite.mjs
+          cat <<< $(jq '.version="${{ env.ZX_LITE_DEV_VERSION }}"' package.json) > package.json
           npm publish --provenance --access=public --no-git-tag-version --tag dev --registry https://${{ env.GOOGLE_NPM_REGISTRY }}
 
       - name: pushing to jsr.io
build/index.cjs
@@ -53,7 +53,7 @@ var import_vendor = require("./vendor.cjs");
 
 // src/versions.ts
 var versions = {
-  zx: "8.8.0",
+  zx: "8.8.1",
   chalk: "5.5.0",
   depseek: "0.4.3",
   dotenv: "0.2.3",
src/versions.ts
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 export const versions: Record<string, string> = {
-  zx: '8.8.0',
+  zx: '8.8.1',
   chalk: '5.5.0',
   depseek: '0.4.3',
   dotenv: '0.2.3',
test/it/build-npm.test.js
@@ -12,81 +12,255 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import { tempdir, $, path, fs, version } from '../../build/index.js'
 import assert from 'node:assert'
-import { describe, before, after, it } from 'node:test'
+import { describe, test } from 'node:test'
+import {
+  $,
+  within,
+  path,
+  glob,
+  tempdir,
+  fs,
+  version,
+} from '../../build/index.js'
 
-const __dirname = path.dirname(new URL(import.meta.url).pathname)
-const root = path.resolve(__dirname, '../../')
+const __dirname = new URL('.', import.meta.url).pathname
+const root = path.resolve(__dirname, '../..')
+const sync = async (from, to, entries) => {
+  for (const entry of entries)
+    await fs.copy(path.resolve(from, entry), path.join(to, entry))
+}
 
 describe('npm artifact', () => {
-  let tmp
-  let zxdir
-  let t$
-
-  const pkgJson = {
-    name: 'zx-test',
-    dependencies: {
-      typescript: '^5',
-      esbuild: '^0.25.8',
-      '@types/node': '*',
-      '@types/fs-extra': '*',
-    },
-  }
-
-  before(async () => {
-    tmp = tempdir()
-    t$ = $({ cwd: tmp, quiet: true })
-    zxdir = path.resolve(tmp, 'node_modules/zx')
-
-    await fs.outputJSON(path.resolve(tmp, 'package.json'), pkgJson)
-    await t$`npm i`
-    // `file:<path>` dep mounts `node_modules` too, so we use cloning here
-    await fs.copy(
-      path.resolve(root, 'package.json'),
-      path.resolve(zxdir, 'package.json')
-    )
-    await fs.copy(path.resolve(root, 'build'), path.resolve(zxdir, 'build'))
+  describe('contents', () => {
+    test('zx full', async () =>
+      within(async () => {
+        const tmp = tempdir()
+        $.cwd = tmp
+        $.quiet = true
+
+        // link
+        await $`ln -s ${path.resolve(root, 'node_modules')} ${path.resolve(tmp, 'node_modules')}`
+        await sync(root, tmp, [
+          'scripts',
+          'build',
+          'man',
+          'package.json',
+          'README.md',
+          'LICENSE',
+        ])
+
+        // pack / unpack
+        await $`node scripts/prepublish-clean.mjs`
+        const pack = await $`npm pack`
+        await $`tar xf ${pack}`
+        await $`rm ${pack}`.nothrow()
+
+        // run
+        const { stderr } =
+          await $`node -e 'import {$} from "./package/build/core.js"; $.verbose = true; await $\`echo hello\`'`
+        assert.match(stderr, /hello/)
+
+        // contents
+        const files = await glob('**/*', {
+          cwd: path.resolve(tmp, 'package'),
+          absolute: false,
+          onlyFiles: true,
+        })
+        assert.deepEqual(
+          files.sort(),
+          [
+            'LICENSE',
+            'README.md',
+            'package.json',
+            'man/zx.1',
+            'build/cli.cjs',
+            'build/cli.d.ts',
+            'build/cli.js',
+            'build/core.cjs',
+            'build/core.d.ts',
+            'build/core.js',
+            'build/deno.js',
+            'build/deps.cjs',
+            'build/deps.d.ts',
+            'build/error.d.ts',
+            'build/esblib.cjs',
+            'build/globals.cjs',
+            'build/globals.d.ts',
+            'build/globals.js',
+            'build/goods.d.ts',
+            'build/index.cjs',
+            'build/index.d.ts',
+            'build/index.js',
+            'build/internals.cjs',
+            'build/log.d.ts',
+            'build/md.d.ts',
+            'build/util.cjs',
+            'build/util.d.ts',
+            'build/versions.d.ts',
+            'build/vendor-core.cjs',
+            'build/vendor-core.d.ts',
+            'build/vendor-extra.cjs',
+            'build/vendor-extra.d.ts',
+            'build/vendor.cjs',
+            'build/vendor.d.ts',
+            'build/3rd-party-licenses',
+          ].sort()
+        )
+      }))
+
+    test('zx@lite', async () =>
+      within(async () => {
+        const tmp = tempdir()
+        $.cwd = tmp
+        $.quiet = true
+
+        // link
+        await $`ln -s ${path.resolve(root, 'node_modules')} ${path.resolve(tmp, 'node_modules')}`
+        await sync(root, tmp, [
+          'build',
+          'package.json',
+          'README.md',
+          'LICENSE',
+          'scripts',
+        ])
+
+        // prepare package.json for lite
+        await $`node scripts/prepublish-lite.mjs`
+        await $`node scripts/prepublish-clean.mjs`
+
+        // pack / unpack
+        const pack = await $`npm pack`
+        await $`tar xf ${pack}`
+        await $`rm ${pack}`.nothrow()
+
+        // run
+        const { stderr } =
+          await $`node -e 'import {$} from "./package/build/core.js"; $.verbose = true; await $\`echo hello\`'`
+        assert.match(stderr, /hello/)
+
+        // contents
+        const files = await glob('**/*', {
+          cwd: path.resolve(tmp, 'package'),
+          absolute: false,
+          onlyFiles: true,
+        })
+        assert.deepEqual(
+          files.sort(),
+          [
+            'LICENSE',
+            'README.md',
+            'build/3rd-party-licenses',
+            'build/cli.js',
+            'build/core.cjs',
+            'build/core.d.ts',
+            'build/core.js',
+            'build/deno.js',
+            'build/error.d.ts',
+            'build/esblib.cjs',
+            'build/internals.cjs',
+            'build/log.d.ts',
+            'build/util.cjs',
+            'build/util.d.ts',
+            'build/vendor-core.cjs',
+            'build/vendor-core.d.ts',
+            'package.json',
+          ].sort()
+        )
+      }))
   })
 
-  after(() => fs.remove(tmp))
-
-  it('buildable with tsc', async () => {
-    const tsconfig = {
-      compilerOptions: {
-        module: 'commonjs',
-        target: 'esnext',
-        outDir: 'bundle',
-        rootDir: 'src',
-        declaration: true,
-        declarationMap: false,
-        esModuleInterop: true,
-      },
-      include: ['src'],
-    }
-    const indexTs = `import {$} from 'zx'
+  describe('compatibility', () => {
+    test('js', async () => {
+      const out = await within(async () => {
+        $.cwd = path.resolve(root, 'test/fixtures/js-project')
+        await $`npm i --no-package-lock`
+        return $`node node_modules/zx/build/cli.js --verbose script.js`
+      })
+      assert.match(out.stderr, /js-script/)
+    })
+
+    test('tsc', async () => {
+      const out = await within(async () => {
+        $.cwd = path.resolve(root, 'test/fixtures/ts-project')
+        await $`npm i --no-package-lock`
+        try {
+          await $`npx tsc`
+        } catch (err) {
+          throw new Error(err.stdout)
+        }
+        return $`node build/script.js`
+      })
+      assert.match(out.stderr, /ts-script/)
+    })
+
+    test('tsc (isolated)', async () => {
+      const tmp = tempdir()
+      const t$ = $({ cwd: tmp, quiet: true })
+      const zxdir = path.resolve(tmp, 'node_modules/zx')
+      const pkgJson = {
+        name: 'zx-test',
+        dependencies: {
+          typescript: '^5',
+          '@types/node': '*',
+          '@types/fs-extra': '*',
+        },
+      }
+
+      await fs.outputJSON(path.resolve(tmp, 'package.json'), pkgJson)
+      await t$`npm i`
+      await sync(root, zxdir, ['package.json', 'build']) // `file:<path>` dep mounts `node_modules` too, so we use cloning here
+
+      const tsconfig = {
+        compilerOptions: {
+          module: 'commonjs',
+          target: 'esnext',
+          outDir: 'bundle',
+          rootDir: 'src',
+          declaration: true,
+          declarationMap: false,
+          esModuleInterop: true,
+        },
+        include: ['src'],
+      }
+      const indexTs = `import {$} from 'zx'
 (async () => {
   await $({verbose: true})\`echo hello\`
 })()
 `
-    await fs.outputJSON(path.resolve(tmp, 'tsconfig.json'), tsconfig)
-    await fs.outputFile(path.resolve(tmp, 'src/index.ts'), indexTs)
+      await fs.outputJSON(path.resolve(tmp, 'tsconfig.json'), tsconfig)
+      await fs.outputFile(path.resolve(tmp, 'src/index.ts'), indexTs)
 
-    await t$`tsc`
-    const out = await t$`node bundle/index.js`.text()
-    assert.strictEqual(out, '$ echo hello\nhello\n')
-  })
+      await t$`tsc`
+      const out = await t$`node bundle/index.js`.text()
+      assert.strictEqual(out, '$ echo hello\nhello\n')
+    })
+
+    test('esbuild (iife)', async () => {
+      const tmp = tempdir()
+      const t$ = $({ cwd: tmp, quiet: true })
+      const zxdir = path.resolve(tmp, 'node_modules/zx')
+      const pkgJson = {
+        name: 'zx-test',
+        dependencies: {
+          esbuild: '^0.25.8',
+        },
+      }
+
+      await sync(root, zxdir, ['package.json', 'build'])
+      await fs.outputJSON(path.resolve(tmp, 'package.json'), pkgJson)
 
-  it('compilable with esbuild (iife)', async () => {
-    const verJs = `import {version, $} from 'zx'
+      const verJs = `import {version, $} from 'zx'
 (async () => {
   await $({verbose: true})\`echo \${version}\`
 })()
 `
-    await fs.outputFile(path.resolve(tmp, 'src/ver.js'), verJs)
+      await fs.outputFile(path.resolve(tmp, 'src/ver.js'), verJs)
+      await fs.mkdir(path.resolve(tmp, 'bundle'))
 
-    await t$`npx esbuild src/ver.js --bundle --format=iife --platform=node > bundle/ver.js`
-    const out = await t$`node bundle/ver.js`.text()
-    assert.strictEqual(out, `$ echo ${version}\n${version}\n`)
+      await t$`npx esbuild src/ver.js --bundle --format=iife --platform=node > bundle/ver.js`
+      const out = await t$`node bundle/ver.js`.text()
+      assert.strictEqual(out, `$ echo ${version}\n${version}\n`)
+    })
   })
 })
test/all.test.js
@@ -22,6 +22,5 @@ import './goods.test.ts'
 import './index.test.js'
 import './log.test.ts'
 import './md.test.ts'
-import './package.test.js'
 import './util.test.js'
 import './vendor.test.js'
test/package.test.js
@@ -1,189 +0,0 @@
-// Copyright 2022 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.
-
-import assert from 'node:assert'
-import { test, describe } from 'node:test'
-import { $, within, path, glob, tempdir, fs } from '../build/index.js'
-
-const __dirname = new URL('.', import.meta.url).pathname
-const root = path.resolve(__dirname, '..')
-
-describe('package', () => {
-  describe('work mode', () => {
-    test('ts', async () => {
-      const out = await within(async () => {
-        $.cwd = path.resolve(root, 'test/fixtures/ts-project')
-        await $`npm i --no-package-lock`
-        try {
-          await $`npx tsc`
-        } catch (err) {
-          throw new Error(err.stdout)
-        }
-        return $`node build/script.js`
-      })
-      assert.match(out.stderr, /ts-script/)
-    })
-
-    test('js', async () => {
-      const out = await within(async () => {
-        $.cwd = path.resolve(root, 'test/fixtures/js-project')
-        await $`npm i --no-package-lock`
-        return $`node node_modules/zx/build/cli.js --verbose script.js`
-      })
-      assert.match(out.stderr, /js-script/)
-    })
-  })
-
-  describe('contents', () => {
-    test('zx full', async () =>
-      within(async () => {
-        const tmp = tempdir()
-        $.cwd = tmp
-        $.quiet = true
-
-        // link
-        await $`ln -s ${path.resolve(root, 'node_modules')} ${path.resolve(tmp, 'node_modules')}`
-        for (const entry of [
-          'scripts',
-          'build',
-          'man',
-          'package.json',
-          'README.md',
-          'LICENSE',
-        ]) {
-          await fs.copy(path.resolve(root, entry), path.join(tmp, entry))
-        }
-
-        // pack / unpack
-        await $`node scripts/prepublish-clean.mjs`
-        const pack = await $`npm pack`
-        await $`tar xf ${pack}`
-        await $`rm ${pack}`.nothrow()
-
-        // run
-        const { stderr } =
-          await $`node -e 'import {$} from "./package/build/core.js"; $.verbose = true; await $\`echo hello\`'`
-        assert.match(stderr, /hello/)
-
-        // contents
-        const files = await glob('**/*', {
-          cwd: path.resolve(tmp, 'package'),
-          absolute: false,
-          onlyFiles: true,
-        })
-        assert.deepEqual(
-          files.sort(),
-          [
-            'LICENSE',
-            'README.md',
-            'package.json',
-            'man/zx.1',
-            'build/cli.cjs',
-            'build/cli.d.ts',
-            'build/cli.js',
-            'build/core.cjs',
-            'build/core.d.ts',
-            'build/core.js',
-            'build/deno.js',
-            'build/deps.cjs',
-            'build/deps.d.ts',
-            'build/error.d.ts',
-            'build/esblib.cjs',
-            'build/globals.cjs',
-            'build/globals.d.ts',
-            'build/globals.js',
-            'build/goods.d.ts',
-            'build/index.cjs',
-            'build/index.d.ts',
-            'build/index.js',
-            'build/internals.cjs',
-            'build/log.d.ts',
-            'build/md.d.ts',
-            'build/util.cjs',
-            'build/util.d.ts',
-            'build/versions.d.ts',
-            'build/vendor-core.cjs',
-            'build/vendor-core.d.ts',
-            'build/vendor-extra.cjs',
-            'build/vendor-extra.d.ts',
-            'build/vendor.cjs',
-            'build/vendor.d.ts',
-            'build/3rd-party-licenses',
-          ].sort()
-        )
-      }))
-
-    test('zx@lite', async () =>
-      within(async () => {
-        const tmp = tempdir()
-        $.cwd = tmp
-        $.quiet = true
-
-        // link
-        await $`ln -s ${path.resolve(root, 'node_modules')} ${path.resolve(tmp, 'node_modules')}`
-        for (const entry of [
-          'build',
-          'package.json',
-          'README.md',
-          'LICENSE',
-          'scripts',
-        ]) {
-          await fs.copy(path.resolve(root, entry), path.join(tmp, entry))
-        }
-
-        // prepare package.json for lite
-        await $`node scripts/prepublish-lite.mjs`
-        await $`node scripts/prepublish-clean.mjs`
-
-        // pack / unpack
-        const pack = await $`npm pack`
-        await $`tar xf ${pack}`
-        await $`rm ${pack}`.nothrow()
-
-        // run
-        const { stderr } =
-          await $`node -e 'import {$} from "./package/build/core.js"; $.verbose = true; await $\`echo hello\`'`
-        assert.match(stderr, /hello/)
-
-        // contents
-        const files = await glob('**/*', {
-          cwd: path.resolve(tmp, 'package'),
-          absolute: false,
-          onlyFiles: true,
-        })
-        assert.deepEqual(
-          files.sort(),
-          [
-            'LICENSE',
-            'README.md',
-            'build/3rd-party-licenses',
-            'build/cli.js',
-            'build/core.cjs',
-            'build/core.d.ts',
-            'build/core.js',
-            'build/deno.js',
-            'build/error.d.ts',
-            'build/esblib.cjs',
-            'build/internals.cjs',
-            'build/log.d.ts',
-            'build/util.cjs',
-            'build/util.d.ts',
-            'build/vendor-core.cjs',
-            'build/vendor-core.d.ts',
-            'package.json',
-          ].sort()
-        )
-      }))
-  })
-})