sw-test-env
Version:
A sandboxed ServiceWorker environment for testing
83 lines • 7.97 kB
JSON
{
"name": "sw-test-env",
"description": "A sandboxed ServiceWorker environment for testing",
"version": "3.0.0",
"author": "Alexander Pope <alex@pope-industries.com>",
"contributors": [
"Ola Christian Gundelsby <ola.christian.gundelsby@nrk.no>"
],
"repository": "https://github.com/popeindustries/sw-test-env.git",
"license": "MIT",
"keywords": [
"mock",
"pseudo",
"sandbox",
"service worker",
"ServiceWorker",
"test",
"testing",
"worker"
],
"type": "module",
"main": "sw-test-env.js",
"files": [
"bin",
"*.d.ts",
"*.js",
"README.MD"
],
"engines": {
"node": ">=16"
},
"dependencies": {
"esbuild": "~0.14.27",
"fake-indexeddb": "^3.1.7",
"form-data": "^4.0.0",
"mime-types": "^2.1.35",
"node-fetch": "^3.2.3"
},
"devDependencies": {
"@types/chai": "^4.3.0",
"@types/mime-types": "^2.1.1",
"@types/mocha": "^9.1.0",
"@types/node": "^17.0.23",
"@typescript-eslint/eslint-plugin": "^5.16.0",
"@typescript-eslint/parser": "^5.16.0",
"chai": "^4.3.6",
"dvlp": "^14.2.0",
"eslint": "^8.11.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"glob": "^7.2.0",
"husky": "^7.0.4",
"lint-staged": "^12.3.7",
"mocha": "^9.2.2",
"prettier": "^2.6.1",
"typescript": "4.6.3"
},
"prettier": {
"arrowParens": "always",
"printWidth": 120,
"singleQuote": true,
"trailingComma": "all"
},
"lint-staged": {
"*.js": [
"eslint"
],
"*.{js,json,md,html}": [
"prettier --write"
]
},
"scripts": {
"build": "node ./scripts/build.js",
"clean": "rm -f ./test/*.js && rm -rf docs",
"format": "prettier --write './{src,test}/**/*'",
"lint": "pnpm run lint:src && pnpm run lint:types",
"lint:src": "eslint './{src,test}/**/*.js'",
"lint:types": "tsc --noEmit --skipLibCheck",
"preinstall": "npx only-allow pnpm",
"test": "pnpm run build && mocha test/*.js --reporter spec --bail"
},
"readme": "[](https://npmjs.org/package/sw-test-env)\n[](https://github.com/popeindustries/sw-test-env/actions)\n\n# ServiceWorker Test Environment\n\nA sandboxed `ServiceWorker` context for testing your `ServiceWorker` code on the command line.\n\nTesting code written to run in a `ServiceWorker` is hard, and generally requires a browser environment and lots of ceremony to work. `sw-test-env` is the magic ingredient for easy unit/integration testing of `ServiceWorker` code. Just load your script, and poke, prod, inspect, and manipulate the `ServiceWorker` context:\n\n```js\nimport assert from 'assert';\nimport { connect } from 'sw-test-env';\n\n// Equivalent to opening a browser window and accessing window.navigator.serviceWorker\nconst sw = connect('http://localhost:3000', 'path/to/webroot');\n\nasync function test() {\n // Load and execute sw.js in a sandboxed ServiceWorker context\n const registration = await sw.register('sw.js');\n // Trigger the 'install' event\n await sw.trigger('install');\n // Inspect the cache contents by reading from the installing service worker's internal scope\n const cache = await sw.__serviceWorker__.self.caches.open('v1');\n const requests = await cache.keys();\n const urls = requests.map((request) => request.url);\n assert.ok(urls.includes('assets/index.js'));\n}\n```\n\n## Features\n\n- load and execute `ServiceWorker` script files in a sandboxed context\n- inspect the properties of the `ServiceWorker` scope (`clients`, `caches`, `registration`, variables, etc)\n- manually trigger events on `ServiceWorker` (`install`, `activate`, `fetch`, `error`, etc)\n- connect multiple clients\n- register multiple, scoped `ServiceWorker` instances\n- `postMessage` between clients and registered `ServiceWorker` instances\n- use `indexedDB`\n- TODO: register for notifications and push messages to connected clients\n\n## Caveats\n\n- limited `Response` streaming and body conversion (uses the primitives from [node-fetch](https://github.com/bitinn/node-fetch))\n- `fetch` calls will be executed, so a request mocking tool like [nock](https://github.com/node-nock/nock) is recommended\n- `importScripts()` in service worker files not supported (use `import` statements instead)\n- requires at least version 16 of Node\n- not yet possible to cache based on `VARY` header\n- not tested against spec test suite or specific browser behaviour\n\n## API\n\n#### **`connect(url: string, webroot: string): Promise<MockServiceWorkerContainer>`**\n\nCreate a new `MockServiceWorkerContainer` instance at `url` (default is `http://localhost:3333/`) with `webroot` (default is current working directory). This is equivalent to opening a browser at `url` and accessing the `window.navigator.serviceworker` object. See [MockServiceWorkerContainer](#mockserviceworkercontainer) below for additional behaviour.\n\nMultiple connections to same/different origins are supported, with access to `MockServiceWorker` instances determined by `scope`.\n\n**Note**: the `webroot` argument is used to resolve the path for registering the `MockServiceWorker`.\n\n#### **`destroy(): Promise<void>`**\n\nDestroy all active `MockServiceWorkerContainer` instances and their registered `MockServiceWorker` instances. Should generally be called after each test (for example, in `afterEach()` when using Mocha/Jest/etc).\n\n#### **`Headers, MessageChannel, Request, Response`**\n\nClasses for creating instances of `Headers`, `MessageChannel`, `Request`, and `Response` to be used when interacting with the `MockServiceWorker` context.\n\n### MockServiceWorkerContainer\n\nIn addition to the behaviour documented [here](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer), a `MockServiceWorkerContainer` instance returned by `connect()` has the following additions:\n\n#### **`register(scriptURL: String, options: { scope: string }): Promise<MockServiceWorkerRegistration>`**\n\nLoad and execute `scriptURL` in a `MockServiceWorker` context. `scriptURL` may be a relative or absolute filepath.\n\n**`options`** include:\n\n- **`scope: String`** the `MockServiceWorker` registration scope (defaults to `./`). Multiple `MockServiceWorker` instances can be registered on the same origin with different scopes.\n\n#### **`ready: Promise<void>`**\n\nForce registered script to `install` and `activate`:\n\n```js\nconst registration = await sw.register('sw.js');\nawait sw.ready;\nassert.equal(sw.controller.state, 'activated');\n```\n\n#### **`trigger(eventType: 'install' | 'activate'): Promise<void>`**\n\n#### **`trigger(eventType: 'fetch', options: FetchEventInit): Promise<Response>`**\n\n#### **`trigger(eventType: 'error' | 'unhandledrejection', error: Error): Promise<void>`**\n\nManually trigger an event in the `MockServiceWorker` scope:\n\n```js\nconst registration = await sw.register('sw.js');\nawait sw.ready;\nconst response = await sw.trigger('fetch', { request: '/assets/index.js' });\nassert.equal(response.url, 'http://localhost:3333/assets/index.js');\n```\n\n#### **`__serviceWorker__: MockServiceWorker`**\n\nAccess the registered `MockServiceWorker`, including it's internal `self` scope:\n\n```js\nconst registration = await sw.register('sw.js');\nawait sw.ready;\nconst cache = sw.__serviceWorker__.self.caches.open('v1');\nconst requests = await cache.keys();\nconst urls = requests.map((request) => request.url);\nassert.ok(urls.includes('assets/index.js'));\n```\n\n## Inspiration & Thanks\n\nSpecial thanks goes to Pinterest ([service-worker-mock](https://github.com/pinterest/service-workers/tree/master/packages/service-worker-mock)) and Nolan Lawson ([pseudo-worker](https://github.com/nolanlawson/pseudo-worker)) for their ideas (some of which were borrowed here) and inspiring work.\n"
}