packtester
v0.2.1
Published
Assert your published package actually works
Downloads
7
Maintainers
Readme
packtester
Assert your published package actually works
Motivation
Running your regular test suite (e.g., npm test
) in CI will miss packaging-related issues, such as missing files and package exports.
There's no staging registry you can test with, so when something's published, it's published. If there's a problem with it, you have to issue a patch and publish again. We can't avoid the problem entirely, but packtester
gets us closer.
This is kind of a pain to setup manually, so automating it might be nice, right?
Install
$ npm install packtester --save-dev
Setup (Automatic)
TODO: via
init
command; needs implementation
Setup (Manual)
Add a pretest
script to your scripts
field in package.json
:
{
"scripts": {
"pretest": "packtester",
"test": "my-regular-test-script"
}
}
It's recommended to also run
packtester
duringprepublishOnly
, so it will check at the last minute before you publish.
Create a __pack_tests__
directory. All files (with .js
, .cjs
, and .mjs
extensions, by default) in this directory will be run with your module installed as a dependency. Here's an example file:
// packtester.packtest.js
const assert = require('assert');
// remember, use your package like a consumer would
const pkg = require('packtester/package.json'); // yeah yeah I know
let packtester;
assert.doesNotThrow(() => {
packtester = require(pkg.name);
}, `could not require('${pkg.name}')`);
// packtester exports a function, `packTest`
assert.ok(
typeof packtester.packTest === 'function',
'did not export "packTest" function'
);
// ESM!
assert.doesNotReject(import(pkg.name), `could not import('${pkg.name}')`);
assert.doesNotThrow(() => {
require(`${pkg.name}/${pkg.main}`);
}, `could not require('${pkg.name}/${pkg.main}') directly`);
You do not need to add test files for packtester
to your published package (unless you want to); in other words, they don't need to be in the files
prop of package.json
and/or can be added to .npmignore
, if desired.
Suggested CI Configuration
Run packtester
as a job or step before the main test suite (e.g., npm test
) as a "smoke test," and have subsequent steps wait for this to complete successfully.
GitHub Actions Example
Add a smoke-test
script to package.json
(remove the "pretest": "packtester"
script, if present):
{
"scripts": {
"smoke-test": "packtester",
"test": "your-test-command"
}
}
And in your workflow file (e.g., .github/workflows/my-workflow.yml
):
jobs:
smoke-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: bahmutov/npm-install@v1
- name: Smoke Test
run: npm run smoke-test
test:
runs-on: ubuntu-latest
needs: smoke-test
steps:
- uses: actions/checkout@v2
- uses: bahmutov/npm-install@v1
- name: Full Test Suite
run: npm test
Options
Custom Targets
By supplying positional arguments to packtester
, you can point it at any directory, file, or glob. Example:
{
"scripts": {
"pretest": "packtester \"my-smoke-tests/**/*.js\"",
"test": "my-regular-test-script"
}
}
Custom package.json
packtester
needs the package.json
of your package to run. Use the --package <package.json>
command-line option to use a specific package.json
file. This may be useful in a monorepo or workspace. Example:
{
"scripts": {
"pretest": "packtester --package=./packages/subpackage/package.json",
"test": "my-regular-test-script"
}
}
More Help
Run npx packtester --help
to see more usage options.
API
packtester
exports a single property, packTest
, which is an async
function.
packtester.packTest([opts]): Promise<void>
Does everything the packtester
CLI does.
opts
is an options object and supports properties (all optional):
{string|string[]}
target
- One or more target files, dirs, globs. Defaults to__pack_tests__
{string}
cwd
- Current working directory{PackageJson}
pkg
- A parsedpackage.json
{string}
npmPath
- Path tonpm
executable{number}
logLevel
- Log level, 0-5, with 0 being "error" and 5 being "trace"
About Tests
The purpose of these tests is to make assertions about the state of your package's public API. The question you're trying to answer is this: is my package usable when installed via a package manager?
Remember: you won't have your devDependencies
installed; this means no test frameworks, assertion libraries, etc. The built-in assert module works well for this use case.
ESM Example
TODO
How It Works
packtester
:
- Runs
npm pack
on your project to generate a tarball in a temporary directory - Runs
npm install
against the tarball in the temp dir - Copies the target tests into temp dir
- Runs the target tests, exiting with non-zero code if they fail
- Removes the temp dir
By installing from a tarball created from npm pack
, we simulate what would happen if you installed your project via a package manager, e.g., npm install my-package
.
License
Copyright © 2020 Christopher Hiller. Licensed Apache-2.0