diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 0dc0445..c440dca 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -13,6 +13,10 @@ on: jobs: validate: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [20, 22] steps: - name: Checkout repository @@ -21,13 +25,20 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 20 + node-version: ${{ matrix.node-version }} + cache: npm - name: Install dependencies - run: npm install + run: npm ci - - name: Validate schemas - run: npm run validate:schemas + - name: Validate package + run: npm run validate - - name: Validate examples - run: npm run validate:examples + - name: Verify checksums + run: npm run checksums:verify + + - name: Smoke test entrypoint import + run: npm run test:smoke:import + + - name: Smoke test npm pack + run: npm run test:smoke:pack diff --git a/package.json b/package.json index 5681aae..f1c8102 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,9 @@ "checksums:verify": "bash scripts/verify-checksums.sh", "checksums:dirty": "git diff --exit-code -- checksums.txt", "prepack": "npm run checksums:gen", - "prepublishOnly": "npm run checksums:gen && npm run checksums:dirty && npm run validate" + "prepublishOnly": "npm run checksums:gen && npm run checksums:dirty && npm run validate", + "test:smoke:import": "node scripts/smoke-import.mjs", + "test:smoke:pack": "node scripts/smoke-pack.mjs" }, "main": "./index.js", "exports": { diff --git a/scripts/smoke-import.mjs b/scripts/smoke-import.mjs new file mode 100644 index 0000000..1955808 --- /dev/null +++ b/scripts/smoke-import.mjs @@ -0,0 +1,11 @@ +import assert from 'node:assert/strict'; +import * as commons from '../index.js'; + +const exportNames = Object.keys(commons); +assert.ok(exportNames.length > 0, 'Expected package entrypoint to export schema bindings.'); + +for (const exportName of exportNames) { + assert.ok(commons[exportName], `Expected export ${exportName} to be defined.`); +} + +console.log(`✅ Imported package entrypoint successfully with ${exportNames.length} exports.`); diff --git a/scripts/smoke-pack.mjs b/scripts/smoke-pack.mjs new file mode 100644 index 0000000..763ed66 --- /dev/null +++ b/scripts/smoke-pack.mjs @@ -0,0 +1,44 @@ +import assert from 'node:assert/strict'; +import { mkdtemp, rm, stat } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { execFile } from 'node:child_process'; +import { promisify } from 'node:util'; + +const execFileAsync = promisify(execFile); +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const ROOT = path.join(__dirname, '..'); + +const tempDir = await mkdtemp(path.join(os.tmpdir(), 'protocol-commons-pack-')); + +try { + const { stdout, stderr } = await execFileAsync( + 'npm', + ['pack', '--json', '--pack-destination', tempDir], + { cwd: ROOT } + ); + + if (stderr.trim()) { + process.stderr.write(stderr); + } + + const jsonStart = stdout.indexOf('['); + const jsonEnd = stdout.lastIndexOf(']'); + + assert.ok(jsonStart >= 0 && jsonEnd >= jsonStart, 'Expected npm pack --json to emit a JSON payload.'); + + const packs = JSON.parse(stdout.slice(jsonStart, jsonEnd + 1)); + + assert.equal(packs.length, 1, 'Expected npm pack to emit exactly one tarball.'); + + const tarballPath = path.join(tempDir, packs[0].filename); + const tarballStat = await stat(tarballPath); + assert.ok(tarballStat.isFile(), `Expected tarball at ${tarballPath}.`); + assert.ok(tarballStat.size > 0, 'Expected packed tarball to be non-empty.'); + + console.log(`✅ npm pack succeeded: ${packs[0].filename}`); +} finally { + await rm(tempDir, { recursive: true, force: true }); +}