Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
- Takes advantage of Node.js 22's built-in glob support
- Reduces external dependencies and improves performance
- No functional changes to dependency discovery behavior
- **Test infrastructure modernization**: Migrated from tape to Node.js native test runner
- Removed dependencies: `tape`, `nyc`, `cross-env`, `proxyquire`, `mock-tmp`
- Added dependency: `c8` (for code coverage)
- All tests now use Node.js built-in `node:test` and `node:assert` modules
- Module mocking now uses Node.js native mock functionality instead of proxyquire
- Temporary directory creation now uses native `fs.mkdtempSync()` instead of mock-tmp
- Test scripts no longer require cross-env for environment variable management

### Migration Guide

Expand All @@ -25,11 +32,22 @@ If you are upgrading from version 5.x:

3. **No code changes required**: The API remains unchanged, all existing code will continue to work

4. **For contributors**: If you're contributing to this project, note the new testing patterns:
- Use `node:test` and `node:assert` instead of tape
- Use native `mock.module()` for mocking instead of proxyquire
- Use `fs.mkdtempSync()` for temporary directories instead of mock-tmp
- Test scripts now use `node --test` directly
- Coverage reports use `c8` instead of `nyc`

### Changed

- Updated `engines.node` in package.json from `>=20` to `>=22`
- Migrated from `@architect/utils/glob` to native `fs.globSync` for file pattern matching
- Updated CI test matrix to use Node.js 22.x and 24.x
- Migrated all test files from tape to Node.js native test runner
- Updated test scripts to use `node --test` instead of tape
- Replaced nyc with c8 for code coverage reporting
- Removed cross-env from all test scripts (no longer needed with native test runner)

---

Expand Down
15 changes: 6 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
"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 tape 'test/unit/**/*-tests.js'",
"test:integration": "cross-env tape 'test/integration/**/*-tests.js'",
"test:integration:fast": "cross-env tape 'test/integration/symlink/**/*-tests.js' 'test/integration/*-tests.js'",
"coverage": "nyc --reporter=lcov --reporter=text npm run test:unit",
"test:unit": "node --test 'test/unit/**/*-tests.js'",
"test:integration": "node --test --test-concurrency=1 'test/integration/**/*-tests.js'",
"test:integration:fast": "node --test --test-concurrency=1 'test/integration/symlink/**/*-tests.js' 'test/integration/*-tests.js'",
"test:verify-migration": "node scripts/verify-migration.js",
"coverage": "c8 --reporter=lcov --reporter=text node --test 'test/unit/**/*-tests.js'",
"lint": "eslint . --fix",
"rc": "npm version prerelease --preid RC",
"vendor": "cd src/actions/autoinstall/python/py/ && vendoring sync && zip -r9 vendor.zip ./vendor"
Expand Down Expand Up @@ -42,13 +43,9 @@
},
"devDependencies": {
"@architect/eslint-config": "~3.0.0",
"cross-env": "~10.0.0",
"c8": "~10.1.3",
"eslint": "~9.36.0",
"mock-tmp": "~0.0.4",
"nyc": "~17.1.0",
"pnpm": "~10.17.1",
"proxyquire": "~2.1.3",
"tape": "~5.9.0",
"yarn": "~1.22.22"
}
}
82 changes: 82 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,88 @@ Note: by default `update` also updates dependencies in shared folders like `src/
Copies shared code (from `src/shared` and `src/views`, or your custom `@shared` + `@views` paths, if any) into all functions.


# Testing

This project uses Node.js's native test runner (`node:test` module) for all tests.

## Running Tests

```bash
# Run all tests (lint + integration + coverage)
npm test

# Run only unit tests
npm run test:unit

# Run only integration tests
npm run test:integration

# Run tests without linting
npm run test:nolint

# Run coverage report
npm run coverage
```

## Test Structure

- **Unit tests**: Located in `test/unit/` directory
- **Integration tests**: Located in `test/integration/` directory
- All test files use the `-tests.js` suffix

## Writing Tests

Tests use Node.js native testing modules:

```javascript
const { test } = require('node:test')
const assert = require('node:assert')

test('example test', async (t) => {
const result = someFunction()
assert.strictEqual(result, expectedValue)
})
```

### Mocking

For module mocking, use Node.js native mock functionality:

```javascript
const { test, mock } = require('node:test')

test('test with mocks', async (t) => {
mock.module('./some-module', {
namedExports: { someFunction: () => 'mocked value' }
})
const module = require('./module-under-test')
// Test with mocked dependency
})
```

### Temporary Directories

For tests requiring temporary directories, use native `fs` operations:

```javascript
const { mkdtempSync, rmSync } = require('fs')
const { tmpdir } = require('os')
const { join } = require('path')

test('test with temp dir', async (t) => {
const tmp = mkdtempSync(join(tmpdir(), 'test-'))
t.after(() => rmSync(tmp, { recursive: true, force: true }))
// Use tmp directory in test
})
```

## Coverage

Code coverage is collected using `c8` and reports are generated in the `coverage/` directory:
- `coverage/lcov-report/` - HTML coverage report
- `coverage/lcov.info` - LCOV format for CI integration


[shared]: #hydratesharedoptions-callback
[install]: #hydrateinstalloptions-callback
[update]: #hydrateupdateoptions-callback
Expand Down
44 changes: 21 additions & 23 deletions test/integration/_shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,52 +148,50 @@ let viewsArtifactsDisabled = [


// Test resetters
function reset (t, callback) {
function reset (callback) {
process.chdir(join(__dirname, '..'))
destroyPath(mockTmp)
cp(mockSource, mockTmp, { recursive: true, force: true }, function (err) {
if (err) t.fail(err)
else {
process.chdir(mockTmp)
callback()
}
if (err) throw err
process.chdir(mockTmp)
callback()
})
}
function resetAndCopyShared (t, callback) {
reset(t, function () {
function resetAndCopyShared (callback) {
reset(function () {
cp('_shared', 'src', { recursive: true, force: true }, function done (err) {
if (err) t.fail(err)
else callback()
if (err) throw err
callback()
})
})
}
function resetAndCopySharedAutoinstall (t, callback) {
reset(t, function () {
function resetAndCopySharedAutoinstall (callback) {
reset(function () {
cp('_shared-autoinstall', '.', { recursive: true, force: true }, function done (err) {
if (err) t.fail(err)
else callback()
if (err) throw err
callback()
})
})
}
function resetAndCopySharedCustom (t, callback) {
reset(t, function () {
function resetAndCopySharedCustom (callback) {
reset(function () {
cp('_shared-custom', '.', { recursive: true, force: true }, function done (err) {
if (err) t.fail(err)
else callback()
if (err) throw err
callback()
})
})
}
function resetAndCopySharedPlugins (t, callback) {
reset(t, function () {
function resetAndCopySharedPlugins (callback) {
reset(function () {
cp('_shared-plugins', 'src', { recursive: true, force: true }, function done (err) {
if (err) t.fail(err)
else callback()
if (err) throw err
callback()
})
})
}

// Ensure we don't create empty folders with copied files
let checkFolderCreation = t => t.notOk(existsSync(join('src', 'events', 'silence')), `Did not copy and create function folder that should not exist`)
let checkFolderCreation = assert => assert.ok(!existsSync(join('src', 'events', 'silence')), `Did not copy and create function folder that should not exist`)


module.exports = {
Expand Down
Loading