diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bb666ec..f516684 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,17 +40,11 @@ jobs: - name: Install run: npm install - - name: Test (Node.js <= 16.x) - if: matrix.node-version <= '16.x' - run: npm run test:nolint - env: - CI: true - - name: Test - if: matrix.node-version > '16.x' run: npm test env: CI: true + NODE_OPTIONS: --no-warnings - name: Notify uses: sarisia/actions-status-discord@v1 diff --git a/changelog.md b/changelog.md index 9fedd15..2af78e7 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,18 @@ --- +## [7.0.1] 2025-11-28 + +- Removed almost all devdeps in favour of node internal test runner/coverage + +--- + +### [7.0.0] 2025-11-27 + +- Updated to >= node 22 + +--- + ## [6.0.0] 2024-09-24 ### Changed diff --git a/package.json b/package.json index 0714b70..75536d5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@architect/create", - "version": "7.0.0", + "version": "7.0.1", "description": "Idempotently initialize Architect projects", "main": "src/index.js", "bin": { @@ -13,9 +13,9 @@ "scripts": { "test": "npm run lint && npm run test:integration && npm run coverage", "test:nolint": "npm run test:integration && npm run coverage", - "test:unit": "cross-env PORT=6666 tape 'test/unit/**/*-test.js' | tap-arc", - "test:integration": "cross-env tape 'test/integration/**/*-test.js' | tap-arc", - "coverage": "nyc --reporter=lcov --reporter=text npm run test:unit", + "test:unit": "node --test 'test/unit/**/*-test.js'", + "test:integration": "node test/integration/run.js", + "coverage": "node --test --experimental-test-coverage 'test/unit/**/*-test.js'", "lint": "eslint . --fix", "rc": "npm version prerelease --preid RC" }, @@ -29,12 +29,6 @@ }, "devDependencies": { "@architect/eslint-config": "~3.0.0", - "cross-env": "~10.0.0", - "eslint": "~9.36.0", - "fs-extra": "~11.3.2", - "nyc": "~17.1.0", - "proxyquire": "^2.1.3", - "tap-arc": "^1.2.2", - "tape": "~5.9.0" + "eslint": "~9.39.1" } } diff --git a/test/integration/cli-test.js b/test/integration/cli-test.js index f384e88..25f7a9e 100644 --- a/test/integration/cli-test.js +++ b/test/integration/cli-test.js @@ -1,59 +1,75 @@ -let test = require('tape') -let cli = require('../../src/cli') -let { join } = require('path') -let fs = require('fs-extra') -let { readFileSync, existsSync } = require('fs') -let tmp = join(__dirname, '..', 'tmp') -let origCwd = process.cwd() -let argv = process.argv -let args = s => process.argv = [ 'fake-env', 'fake-file', ...s.split(' ') ] +let { describe, it, before, beforeEach } = require('node:test') +let assert = require('node:assert/strict') +let create = require('../../src/index') +let { join, resolve } = require('path') +let { readFileSync, existsSync, rmSync, mkdirSync } = require('fs') +let { updater } = require('@architect/utils') +let tmp = resolve(__dirname, '..', 'tmp') -test('integration test setup', async t => { - t.plan(1) - fs.emptyDirSync(tmp) - process.chdir(tmp) - t.pass('integration test environment setup complete') -}) +// Helper to empty a directory (replaces fs-extra's emptyDirSync) +function emptyDirSync (dir) { + if (existsSync(dir)) { + rmSync(dir, { recursive: true, force: true }) + } + mkdirSync(dir, { recursive: true }) +} -test('should build the basic templated node runtime project', async t => { - t.plan(2) - fs.emptyDirSync(tmp) - args('--no-install --runtime node.js') - await cli() - t.ok(existsSync(join(tmp, 'src', 'http', 'get-index', 'index.mjs')), 'src/http/get-index/index.mjs created') - t.ok(readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime node/), '"runtime node" present somewhere in manifest') -}) +describe('CLI Integration Tests', () => { + before(() => { + // Ensure tmp directory exists + emptyDirSync(tmp) + }) -test('should build the basic templated deno runtime project', async t => { - t.plan(2) - fs.emptyDirSync(tmp) - args('--no-install --runtime deno') - await cli() - t.ok(existsSync(join(tmp, 'src', 'http', 'get-index', 'mod.ts')), 'src/http/get-index/mod.ts created') - t.ok(readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime deno/), '"runtime deno" present somewhere in manifest') -}) + beforeEach(() => { + // Clean tmp directory before each test + emptyDirSync(tmp) + }) -test('should build the basic templated python runtime project', async t => { - t.plan(2) - fs.emptyDirSync(tmp) - args('--no-install --runtime python') - await cli() - t.ok(existsSync(join(tmp, 'src', 'http', 'get-index', 'lambda.py')), 'src/http/get-index/lambda.py created') - t.ok(readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime python/), '"runtime python" present somewhere in manifest') -}) + it('should build the basic templated node runtime project', async () => { + let update = updater('Create') + await create({ + folder: tmp, + install: false, + runtime: 'node.js', + update, + }) + assert.ok(existsSync(join(tmp, 'src', 'http', 'get-index', 'index.mjs')), 'src/http/get-index/index.mjs created') + assert.ok(readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime node/), '"runtime node" present somewhere in manifest') + }) -test('should build the basic templated ruby runtime project', async t => { - t.plan(2) - fs.emptyDirSync(tmp) - args('--no-install --runtime ruby') - await cli() - t.ok(existsSync(join(tmp, 'src', 'http', 'get-index', 'lambda.rb')), 'src/http/get-index/lambda.rb created') - t.ok(readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime ruby/), '"runtime ruby" present somewhere in manifest') -}) + it('should build the basic templated deno runtime project', async () => { + let update = updater('Create') + await create({ + folder: tmp, + install: false, + runtime: 'deno', + update, + }) + assert.ok(existsSync(join(tmp, 'src', 'http', 'get-index', 'mod.ts')), 'src/http/get-index/mod.ts created') + assert.ok(readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime deno/), '"runtime deno" present somewhere in manifest') + }) + + it('should build the basic templated python runtime project', async () => { + let update = updater('Create') + await create({ + folder: tmp, + install: false, + runtime: 'python', + update, + }) + assert.ok(existsSync(join(tmp, 'src', 'http', 'get-index', 'lambda.py')), 'src/http/get-index/lambda.py created') + assert.ok(readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime python/), '"runtime python" present somewhere in manifest') + }) -test('integration test teardown', t => { - t.plan(1) - process.argv = argv - process.chdir(origCwd) - t.pass('integration test environment setup removed') + it('should build the basic templated ruby runtime project', async () => { + let update = updater('Create') + await create({ + folder: tmp, + install: false, + runtime: 'ruby', + update, + }) + assert.ok(existsSync(join(tmp, 'src', 'http', 'get-index', 'lambda.rb')), 'src/http/get-index/lambda.rb created') + assert.ok(readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime ruby/), '"runtime ruby" present somewhere in manifest') + }) }) diff --git a/test/integration/run.js b/test/integration/run.js new file mode 100644 index 0000000..3557718 --- /dev/null +++ b/test/integration/run.js @@ -0,0 +1,84 @@ +#!/usr/bin/env node +// Simple test runner that avoids Node.js test runner serialization issues +let create = require('../../src/index') +let { join, resolve } = require('path') +let { readFileSync, existsSync, rmSync, mkdirSync } = require('fs') +let { updater } = require('@architect/utils') + +let tmp = resolve(__dirname, '..', 'tmp') +let passed = 0 +let failed = 0 + +function emptyDirSync (dir) { + if (existsSync(dir)) { + rmSync(dir, { recursive: true, force: true }) + } + mkdirSync(dir, { recursive: true }) +} + +async function test (name, fn) { + try { + emptyDirSync(tmp) + await fn() + console.log(`✓ ${name}`) + passed++ + } + catch (err) { + console.error(`✗ ${name}`) + console.error(err) + failed++ + } +} + +async function main () { + console.log('Running CLI Integration Tests...\n') + + await test('should build the basic templated node runtime project', async () => { + let update = updater('Create') + await create({ folder: tmp, install: false, runtime: 'node.js', update }) + if (!existsSync(join(tmp, 'src', 'http', 'get-index', 'index.mjs'))) { + throw new Error('index.mjs not created') + } + if (!readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime node/)) { + throw new Error('runtime node not in manifest') + } + }) + + await test('should build the basic templated deno runtime project', async () => { + let update = updater('Create') + await create({ folder: tmp, install: false, runtime: 'deno', update }) + if (!existsSync(join(tmp, 'src', 'http', 'get-index', 'mod.ts'))) { + throw new Error('mod.ts not created') + } + if (!readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime deno/)) { + throw new Error('runtime deno not in manifest') + } + }) + + await test('should build the basic templated python runtime project', async () => { + let update = updater('Create') + await create({ folder: tmp, install: false, runtime: 'python', update }) + if (!existsSync(join(tmp, 'src', 'http', 'get-index', 'lambda.py'))) { + throw new Error('lambda.py not created') + } + if (!readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime python/)) { + throw new Error('runtime python not in manifest') + } + }) + + await test('should build the basic templated ruby runtime project', async () => { + let update = updater('Create') + await create({ folder: tmp, install: false, runtime: 'ruby', update }) + if (!existsSync(join(tmp, 'src', 'http', 'get-index', 'lambda.rb'))) { + throw new Error('lambda.rb not created') + } + if (!readFileSync(join(tmp, 'app.arc'), 'utf-8').match(/runtime ruby/)) { + throw new Error('runtime ruby not in manifest') + } + }) + + console.log(`\n${passed} passed, ${failed} failed`) + process.exit(failed > 0 ? 1 : 0) +} + +main() diff --git a/test/unit/cli-test.js b/test/unit/cli-test.js index e3b90b7..f97a068 100644 --- a/test/unit/cli-test.js +++ b/test/unit/cli-test.js @@ -1,102 +1,117 @@ -let proxyquire = require('proxyquire') -let test = require('tape') +const { test } = require('node:test') +const assert = require('node:assert') +const Module = require('module') + let createParams -let create = p => createParams = p +const argv = process.argv +const args = s => process.argv = [ 'fake-env', 'fake-file', ...s.split(' ').filter(Boolean) ] let reset = () => { process.argv = argv createParams = undefined } -let cli = proxyquire('../../src/cli', { - '.': create, -}) -let argv = process.argv -let args = s => process.argv = [ 'fake-env', 'fake-file', ...s.split(' ').filter(Boolean) ] -test('CLI flags and params', async t => { - t.plan(15) +// Mock the create module by intercepting require +const originalRequire = Module.prototype.require +let cli + +test('CLI flags and params', async () => { + // Setup: Mock the create module + Module.prototype.require = function (id) { + if (id === '.' || id === './index.js') { + return (p) => { createParams = p } + } + return originalRequire.apply(this, arguments) + } + + // Clear require cache and reload cli + delete require.cache[require.resolve('../../src/cli')] + cli = require('../../src/cli') + + // Restore require after loading + Module.prototype.require = originalRequire + args('') await cli() Object.entries(createParams).forEach(([ k, v ]) => { if (k === 'update' || k === 'standalone') return - if (v !== undefined) t.fail(`${k} should be undefined`) + if (v !== undefined) assert.fail(`${k} should be undefined`) }) - t.pass('By default the CLI passes no controlling params') reset() // Name let name = 'hi' args(`--name ${name}`) await cli() - t.equal(createParams.name, name, 'Got name from CLI --name') + assert.equal(createParams.name, name, 'Got name from CLI --name') reset() args(`-n ${name}`) await cli() - t.equal(createParams.name, name, 'Got name from CLI -n') + assert.equal(createParams.name, name, 'Got name from CLI -n') reset() // Install / no-install await cli({ install: true }) - t.not(createParams.install, 'Got install: true from module params') + assert.ok(createParams.install, 'Got install: true from module params') reset() await cli({ install: false }) - t.notOk(createParams.install, 'Got install: false from module params') + assert.ok(!createParams.install, 'Got install: false from module params') reset() args(`--noinstall`) await cli() - t.notOk(createParams.install, 'Got install: false from CLI --noinstall') + assert.ok(!createParams.install, 'Got install: false from CLI --noinstall') reset() args(`--no-install`) await cli() - t.notOk(createParams.install, 'Got install: false from CLI --no-install') + assert.ok(!createParams.install, 'Got install: false from CLI --no-install') reset() // Runtime let runtime = 'python' args(`--runtime ${runtime}`) await cli() - t.equal(createParams.runtime, runtime, 'Got runtime from CLI --runtime') + assert.equal(createParams.runtime, runtime, 'Got runtime from CLI --runtime') reset() args(`-r ${runtime}`) await cli() - t.equal(createParams.runtime, runtime, 'Got runtime from CLI -r') + assert.equal(createParams.runtime, runtime, 'Got runtime from CLI -r') reset() // Standalone await cli({ standalone: true }) - t.ok(createParams.standalone, 'Got standalone from module params') + assert.ok(createParams.standalone, 'Got standalone from module params') reset() // Plugin args('--plugin') await cli() - t.ok(createParams.plugin, 'Got plugin from CLI') + assert.ok(createParams.plugin, 'Got plugin from CLI') reset() // Verbose args('--verbose') await cli() - t.ok(createParams.verbose, 'Got verbose from CLI') + assert.ok(createParams.verbose, 'Got verbose from CLI') reset() args('-v') await cli() - t.ok(createParams.verbose, 'Got verbose from CLI') + assert.ok(createParams.verbose, 'Got verbose from CLI') reset() // Folder let folder = './foo' args(folder) await cli() - t.equal(createParams.folder, folder, 'Got folder from CLI') + assert.equal(createParams.folder, folder, 'Got folder from CLI') reset() args(`create ${folder}`) // Ignore create await cli() - t.equal(createParams.folder, folder, `Got folder from CLI, ignored 'create'`) + assert.equal(createParams.folder, folder, `Got folder from CLI, ignored 'create'`) reset() }) diff --git a/test/unit/src/_get-name-test.js b/test/unit/src/_get-name-test.js index a4591e6..50fe6b5 100644 --- a/test/unit/src/_get-name-test.js +++ b/test/unit/src/_get-name-test.js @@ -1,4 +1,5 @@ -let test = require('tape') +let { test } = require('node:test') +let assert = require('node:assert/strict') let { join, sep } = require('path') let os = require('os') let cwd = process.cwd() @@ -7,78 +8,74 @@ let getName = require(sut) let defaultName = 'create' let s = str => str[0].replace(/\//g, sep) -test('Set up env', t => { - t.plan(1) - t.ok(getName, 'Loaded getName') +test('Set up env', () => { + assert.ok(getName, 'Loaded getName') }) -test('No name/folder specified', t => { - t.plan(2) +test('No name/folder specified', () => { let result = getName({ cwd }) - t.equal(result.name, defaultName, 'Got default name of current directory') - t.equal(result.folder, cwd, 'Got default folder of current directory') + assert.equal(result.name, defaultName, 'Got default name of current directory') + assert.equal(result.folder, cwd, 'Got default folder of current directory') }) -test('Name specified', t => { - t.plan(2) +test('Name specified', () => { let name = 'hi' let result = getName({ cwd, name }) - t.equal(result.name, name, 'Name passed through') - t.equal(result.folder, cwd, 'Got default folder of current directory') + assert.equal(result.name, name, 'Name passed through') + assert.equal(result.folder, cwd, 'Got default folder of current directory') }) -test('Folder specified', t => { - t.plan(18) +test('Folder specified', () => { let folder let result folder = cwd result = getName({ cwd, folder }) - t.equal(result.name, defaultName, 'Got default name of current directory') - t.equal(result.folder, folder, `Got specified folder: ${folder}`) + assert.equal(result.name, defaultName, 'Got default name of current directory') + assert.equal(result.folder, folder, `Got specified folder: ${folder}`) folder = s`foo` result = getName({ cwd, folder }) - t.equal(result.name, 'foo', 'Got default name of current directory') - t.equal(result.folder, join(cwd, 'foo'), `Got specified folder: ${folder}`) + assert.equal(result.name, 'foo', 'Got default name of current directory') + assert.equal(result.folder, join(cwd, 'foo'), `Got specified folder: ${folder}`) folder = s`./foo` result = getName({ cwd, folder }) - t.equal(result.name, 'foo', 'Got default name of current directory') - t.equal(result.folder, join(cwd, 'foo'), `Got specified folder: ${folder}`) + assert.equal(result.name, 'foo', 'Got default name of current directory') + assert.equal(result.folder, join(cwd, 'foo'), `Got specified folder: ${folder}`) folder = s`../foo` result = getName({ cwd, folder }) - t.equal(result.name, 'foo', 'Got default name of current directory') - t.equal(result.folder, join(cwd, '..', 'foo'), `Got specified folder: ${folder}`) + assert.equal(result.name, 'foo', 'Got default name of current directory') + assert.equal(result.folder, join(cwd, '..', 'foo'), `Got specified folder: ${folder}`) folder = s`../../foo` result = getName({ cwd, folder }) - t.equal(result.name, 'foo', 'Got default name of current directory') - t.equal(result.folder, join(cwd, '..', '..', 'foo'), `Got specified folder: ${folder}`) + assert.equal(result.name, 'foo', 'Got default name of current directory') + assert.equal(result.folder, join(cwd, '..', '..', 'foo'), `Got specified folder: ${folder}`) folder = s`/foo` result = getName({ cwd, folder }) let root = os.platform == 'win32' ? process.cwd().split(sep)[0] : sep - t.equal(result.name, 'foo', 'Got default name of current directory') - t.equal(result.folder, join(root, 'foo'), `Got specified folder: ${folder}`) + assert.equal(result.name, 'foo', 'Got default name of current directory') + assert.equal(result.folder, join(root, 'foo'), `Got specified folder: ${folder}`) folder = s`./` result = getName({ cwd, folder }) - t.equal(result.name, defaultName, 'Got default name of current directory') - t.equal(result.folder, cwd, `Got specified folder: ${folder}`) + assert.equal(result.name, defaultName, 'Got default name of current directory') + assert.equal(result.folder, cwd, `Got specified folder: ${folder}`) let path let pop = p => p.split(sep).reverse().shift() folder = s`../` path = join(cwd, '..') result = getName({ cwd, folder }) - t.equal(result.name, pop(path), `Got name from directory: ${result.name}`) - t.equal(result.folder, path, `Got specified folder: ${folder}`) + assert.equal(result.name, pop(path), `Got name from directory: ${result.name}`) + assert.equal(result.folder, path, `Got specified folder: ${folder}`) folder = s`../../` path = join(cwd, '..', '..') result = getName({ cwd, folder }) - t.equal(result.name, pop(path), `Got name from directory: ${result.name}`) - t.equal(result.folder, path, `Got specified folder: ${folder}`) + assert.equal(result.name, pop(path), `Got name from directory: ${result.name}`) + assert.equal(result.folder, path, `Got specified folder: ${folder}`) }) diff --git a/test/unit/src/bootstrap/_arc-package-test.js b/test/unit/src/bootstrap/_arc-package-test.js index abb01d1..a612435 100644 --- a/test/unit/src/bootstrap/_arc-package-test.js +++ b/test/unit/src/bootstrap/_arc-package-test.js @@ -1,6 +1,7 @@ -let test = require('tape') +let { describe, it, beforeEach, afterEach } = require('node:test') +let assert = require('node:assert/strict') let { join } = require('path') -let proxyquire = require('proxyquire') +let Module = require('module') let exists = false let destination @@ -9,71 +10,89 @@ let arcAsDep = { dependencies: { '@architect/architect': 'latest' } } let arcAsDevDep = { devDependencies: { '@architect/architect': 'latest' } } let pkg = arcAsDep -let fsStub = { - existsSync: () => exists, - readFileSync: () => JSON.stringify(pkg), - writeFileSync: (dest, data) => { - destination = dest - written = data - }, - '@noCallThru': false, -} -let arcPackage = proxyquire('../../../../src/bootstrap/_arc-package', { - fs: fsStub, -}) let foo = 'foo' let name = foo let folder = __dirname let argv = process.argv -let reset = () => { - destination = '' - written = '' - process.argv = argv -} - -test('Set up env', t => { - t.plan(1) - t.ok(arcPackage, 'Loaded getName') -}) -test('Package writer bails when Architect is called from a global install', t => { - t.plan(2) - process.argv = [ '/usr/local/bin/node', '/usr/local/bin/arc', 'create' ] - let result = arcPackage({}) - t.notOk(result, 'Invocation from global install should opt out of Arc installation') - reset() - - process.argv = [ '/usr/local/bin/node', '/usr/local/bin/arc', 'init' ] - result = arcPackage({}) - t.notOk(result, 'Invocation from global install should opt out of Arc installation') - reset() -}) +// Store original require +let originalRequire = Module.prototype.require -test('Package writer writes a package file when none exists', t => { - t.plan(3) - process.argv = [] - let result = arcPackage({ name, folder }) - t.ok(result, 'Missing package file found should opt into Arc installation') - t.equal(destination, join(__dirname, 'package.json'), 'Wrote package.json to specified folder') - t.equal(JSON.parse(written)['name'], foo, 'package.json uses specified app name') - reset() -}) +describe('_arc-package', () => { + let arcPackage + + beforeEach(() => { + // Reset state + destination = '' + written = '' + exists = false + pkg = arcAsDep + process.argv = argv + + // Mock fs module + Module.prototype.require = function (id) { + if (id === 'fs') { + return { + existsSync: () => exists, + readFileSync: () => Buffer.from(JSON.stringify(pkg)), + writeFileSync: (dest, data) => { + destination = dest + written = data + }, + } + } + return originalRequire.apply(this, arguments) + } + + // Clear module cache and require the module + delete require.cache[require.resolve('../../../../src/bootstrap/_arc-package')] + arcPackage = require('../../../../src/bootstrap/_arc-package') + }) + + afterEach(() => { + // Restore original require + Module.prototype.require = originalRequire + + // Reset state + exists = false + pkg = arcAsDep + process.argv = argv + }) + + it('should load the module', () => { + assert.ok(arcPackage, 'Loaded arcPackage') + }) + + it('should bail when Architect is called from a global install', () => { + process.argv = [ '/usr/local/bin/node', '/usr/local/bin/arc', 'create' ] + let result = arcPackage({}) + assert.ok(!result, 'Invocation from global install should opt out of Arc installation') + + process.argv = [ '/usr/local/bin/node', '/usr/local/bin/arc', 'init' ] + result = arcPackage({}) + assert.ok(!result, 'Invocation from global install should opt out of Arc installation') + }) + + it('should write a package file when none exists', () => { + process.argv = [] + let result = arcPackage({ name, folder }) + assert.ok(result, 'Missing package file found should opt into Arc installation') + assert.equal(destination, join(__dirname, 'package.json'), 'Wrote package.json to specified folder') + assert.equal(JSON.parse(written)['name'], foo, 'package.json uses specified app name') + }) + + it('should determine whether to install Arc based on an existing package.json', () => { + process.argv = [] + exists = true + let result = arcPackage({ name, folder }) + assert.ok(!result, 'Found package file with Arc as dep should opt out of Arc installation') + + pkg = arcAsDevDep + result = arcPackage({ name, folder }) + assert.ok(!result, 'Found package file with Arc as dev dep should opt out of Arc installation') -test(`Package writer determines whether to install Arc based on an existing package.json`, t => { - t.plan(3) - process.argv = [] - exists = true - let result = arcPackage({ name, folder }) - t.notOk(result, 'Found package file with Arc as dep should opt out of Arc installation') - reset() - - pkg = arcAsDevDep - result = arcPackage({ name, folder }) - t.notOk(result, 'Found package file with Arc as dev dep should opt out of Arc installation') - reset() - - pkg = {} - result = arcPackage({ name, folder }) - t.ok(result, 'Found package file with no Arc installed, so opt into Arc installation') - reset() + pkg = {} + result = arcPackage({ name, folder }) + assert.ok(result, 'Found package file with no Arc installed, so opt into Arc installation') + }) }) diff --git a/test/unit/src/write-functions/write-code-test.js b/test/unit/src/write-functions/write-code-test.js index c0aa729..a6643cd 100644 --- a/test/unit/src/write-functions/write-code-test.js +++ b/test/unit/src/write-functions/write-code-test.js @@ -1,18 +1,12 @@ -let { join } = require('path') -let proxyquire = require('proxyquire') +let { describe, it, beforeEach, afterEach } = require('node:test') +let assert = require('node:assert/strict') +let Module = require('module') + let destination let written -let fsStub = { - writeFileSync: (dest, data) => { - destination = dest - written = data - }, -} -let sut = join(process.cwd(), 'src', 'write-functions', 'write-code') -let writeCode = proxyquire(sut, { - fs: fsStub, -}) -let test = require('tape') + +// Store original require +let originalRequire = Module.prototype.require let inventory = { inv: { @@ -21,21 +15,53 @@ let inventory = { }, } -test('Set up env', t => { - t.plan(1) - t.ok(writeCode, 'Loaded writeCode') -}) +describe('write-code', () => { + let writeCode + + beforeEach(() => { + // Reset state + destination = '' + written = '' + + // Mock fs module + Module.prototype.require = function (id) { + if (id === 'fs') { + return { + existsSync: originalRequire.apply(this, [ 'fs' ]).existsSync, + mkdirSync: originalRequire.apply(this, [ 'fs' ]).mkdirSync, + writeFileSync: (dest, data) => { + destination = dest + written = data + }, + } + } + return originalRequire.apply(this, arguments) + } + + // Clear module cache and require the module + delete require.cache[require.resolve('../../../../src/write-functions/write-code')] + writeCode = require('../../../../src/write-functions/write-code') + }) + + afterEach(() => { + // Restore original require + Module.prototype.require = originalRequire + }) + + it('should load the module', () => { + assert.ok(writeCode, 'Loaded writeCode') + }) -test('Should write template body if no body provided via argument', t => { - t.plan(2) - writeCode({ - handlerFile: 'src/http/get-catchall/index.js', - config: { - runtime: 'nodejs14.x', - }, - handlerModuleSystem: 'cjs', - pragma: 'http', - }, inventory) - t.equal(destination, 'src/http/get-catchall/index.js', 'Correct file location to be written to') - t.match(written, /async function http/, 'Correct argument-provided content written') + it('should write template body if no body provided via argument', async () => { + await writeCode({ + handlerFile: 'src/http/get-catchall/index.js', + config: { + runtime: 'nodejs14.x', + }, + handlerModuleSystem: 'cjs', + pragma: 'http', + }, inventory) + assert.equal(destination, 'src/http/get-catchall/index.js', 'Correct file location to be written to') + assert.match(written, /async function http/, 'Correct argument-provided content written') + }) })