New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

packtester

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

packtester

Assert your published package actually works

latest
Source
npmnpm
Version
0.2.1
Version published
Maintainers
1
Created
Source

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 during prepublishOnly, 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 parsed package.json
  • {string} npmPath - Path to npm 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

Keywords

testing

FAQs

Package last updated on 07 Oct 2020

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts