JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 175
  • Score
    100M100P100Q91855F
  • License ISC

Verifies that your package will work after it is published by running your unit tests in a special test folder.

Package Exports

  • testpack-cli

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (testpack-cli) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

testpack-cli: Test your package before publishing

Usage: testpack [Options] [<Test patterns>]

Attempts to verify that your npm package is set up properly by installing the packaged version against your unit tests in a special test folder with its own custom package.json file.

<Test patterns> are glob patterns used to recognize source files that are test-related and so should be copied to the new project. The default test patterns are test* *test.* *tests.* *test*/** tsconfig.json. Note: the glob package is used to match test patterns. It requires slash (/) as the path separator even on Windows; backslashes escape "special" characters such as braces.

Here's what it does:

  1. It runs npm pack to create a preview copy of your package.
  2. It creates a test folder. By default the folder is ../YPN-testpack where YPN is your package's name, and if the test folder already exists, its contents are deleted. You can use --test-folder to change the folder's path and name.
  3. In the test folder, a new package.json file derived from your existing one is created, in which all dependencies are deleted except common unit test frameworks (e.g. jasmine, mocha, jest). Using --packagejson you can request additional changes to the new package.json.
  4. Runs npm install in the test folder
  5. Installs any additional packages you requested with --install
  6. Unpacks the tgz file generated by npm pack using npm install
  7. Copies your test files to the new folder, preserving their original directory structure.
  8. Changes import/require commands in the tests to remove the "local" prefix ./ or ../src, except when importing test files, so that your tests are importing from node_modules instead. If your package is called P, you should ideally create a single "main" source file called P.js or P.ts which you import using import {...} from "./P" in your tests. The test folder's copy will import "P" instead.
  9. Runs npm run test (or another script according to --test-script)

All command-line options are optional. By default, if your test files have import or require commands that refer to a string starting with ./ or ../src/, that prefix will be stripped out of the copy unless they refer to one of the test files.

Options

--dirty
      The contents of the test folder are normally deleted at the start.
      This option skips the deletion step, potentially leaving extra files
      in the test folder (also: runs faster npm ci instead of npm install)
-p, --packagejson=key:value  
      Merges data into the new package.json file. If the new value is a 
      primitive, it overwrites the old value. If the old value is a 
      primitive, it is treated as an array. If both are arrays, they are
      concatenated. If either one is an object, they are merged in the 
      obvious way, recursively. For example:
        Old value: `{"a":["hi"], "b":7, "c":[3], "x":{"D":4}}`
        New value: `{"a":1,"b":[8],"c":[4],"x":{"D":{"two":2},"E":5}}`
        Out: `{"a":1,"b":[7,8],"c":[3,4],"x":{"D":{"0":4,"two":2},"E":5}}`
      You can use `undefined` to delete an existing value, e.g.
        --packagejson={testpack:undefined,repository:undefined}
-o, --test-folder=path
      Path to test folder. Created if necessary.
-r, --replace-import /pat1/pat2/
      Searches js/mjs/ts/tsx test files for require/import filenames using 
      regex pattern 1, replacing it with pattern 2 (pattern 2 can use $1
      through $9 to re-emit captured strings). Replacements only affect
      non-test files unless you add --replace-test-imports. If this option
      is not used then the prefix is stripped from paths that start with 
      `./` or `./src/` or `../src/`. UTF-8 encoding is assumed.
--regex ext/regex/
      For the purpose of modifying import/require commands, files with the
      specified extension(s) are searched using this regular expression,
      and the first captured group is treated as a filename that may need 
      to be modified. For example, this built-in regex is used to match
      require commands that use double quotes:
        --regex js/require\s*\(\s*"((?:[^\\"]|\\.)*)"/
      You can specify multiple extensions separated by commas: `js,mjs`
-R, --rmdir
      Remove entire test folder when done (by default, only the the tgz
      produced by `npm pack` is deleted.)
--delete-on-fail
      Delete the test folder & tgz even when tests fail.
-s, --test-script=name
      Name of test script to run with `npm run` (default: `test`).
--install package
      Runs `npm install --save-dev package` in the test project.
--keep package
      Prevents removal of package(s) from dependencies or devDependencies.
--prepacked
      Skips running `npm pack` and looks for the .tgz file it normally
      produces (name-version.tgz). This option also prevents the deletion 
      of the tar.gz file on exit.
--prepacked=file
      Skips running `npm pack` and unpacks the specified file.
--verbose
      Emit more text describing what testpack is doing
--show-json
      Shows the JSON equivalent of the specified arguments, then quits.
      You can put these settings in a "testpack" section of package.json.
-!, --nontest pattern
      Ignores the specified files (glob pattern) when searching for tests.

Caution: your shell may transform special characters before they reach testpack. For example, on Windows, --packagejson=key:"value" doesn't work because the shell removes the quotes, causing an error message from testpack.

If you prefer, options can be placed in a "testpack" section of your package.json file. For example,

  "testpack": { "test-script":"foo", "verbose": true }

is equivalent to --test-script=foo --verbose.

How to use it

  1. Prepare to your package for publishing as you normally would (instructions)

  2. In a terminal: npm install --save-dev --global testpack-cli

  3. Run it with: testpack

  4. Run npm publish once it all works.

  5. To combine steps 4 and 5, use a script like npm run safePublish

    "scripts": { "safePublish": "testpack && npm publish", ... }

If your package is a TypeScript project, make sure that your tests in the test folder are importing the compiled JavaScript version, because your end-users might not be using TypeScript. One way to guarantee this is to exclude all .ts files from your package (if you do that, be sure source maps are disabled in your tsconfig.json.) Your tests should still be written in TypeScript to make sure your d.ts files work; use "declaration": true in tsconfig.json so they can access type information.

testpack-cli versus package-preview

I created testpack because I wasn't happy with package-preview. Package-preview does not create a special test folder and it cannot edit the import/require commands in your source files. Instead, package-preview seems to be designed with the assumption that it will always run before your tests. However, your package may need to be built (with Babel or TypeScript) before it is packaged, and package-preview installs it with a separate copy of all the dependencies of your package. This is usually a slow process - a process you don't want to run every time you run your unit tests.

For example, I wrote a very simple package whose unit tests took 1 second. Once I added package-preview, I needed 18 seconds to run package-preview before the unit tests could start.

Unfortunately, I couldn't find any way to import a module from node_modules if the path started with ./ - that prefix seems to be treated as proof that it's not in node_modules. Likewise, I couldn't find any way import a module from the current directory if it did not start with ./. In normal JavaScript you could try using environment variables to figure out whether you need to use . or not, e.g. require(process.env.TESTPACK ? "mymodule" : "./index"). However if you are using TypeScript or import statements, this is not possible.

Thus, the purpose of testpack is to avoid slowing down the normal unit test process when you are not about to publish. Your tests can import a local copy of your code from ./ or ../src/ so they run quickly. When you're ready to publish, you use the slower testpack process to create a special-purpose test environment with modified imports.

Note: I bet one of you JavaScript wizards knows how I could have avoided all this trouble with ./. TypeScript users might think that TypeScript aliases could potentially solve this problem, but they can't because they are compile-time only. That is, if you tell TypeScript that ./A is an alias for B, then TypeScript loads B for type checking but it generates code that still refers to ./A! And ts-node inherits this problem; thus if you are writing code for the command line / Node.js, aliases don't seem to help at all.

Package-preview does have one special virtue: it uses pnpm to isolate the packed package (i.e. the almost-published tgz) from any other packages installed in the same project that are not declared as dependencies in the packed package. Testpack doesn't have as much isolation, e.g. it keeps unit test frameworks. So, suppose that your packed package tries to use a dependency X but it doesn't declare the dependency in package.json like it should. If your unit test framework also uses dependency X, your code may still work when it should actually break. I apologize for that but I don't have time to implement fancier isolation. Perhaps someone will make a pull request?