[
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\non:\n  - push\n  - pull_request\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node: ['14', '16', '18']\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-node@v2\n        with:\n          node-version: ${{ matrix.node }}\n      - run: npm ci\n      - run: xvfb-run npm test\n        timeout-minutes: 5"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\nyarn.lock\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - 12\n  - 14\naddons:\n  apt:\n    packages:\n      - xvfb\ninstall:\n  - export DISPLAY=':99.0'\n  - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &\n  - npm install\n"
  },
  {
    "path": "History.md",
    "content": "\n0.3.0 / 2014-08-13 \n==================\n\n * bump browser-run for security reasons\n * add history\n\n0.2.0 / 2014-07-13 \n==================\n\n * ignore node_modules\n * update browser-run\n"
  },
  {
    "path": "Makefile",
    "content": "\ntest:\n\t@node_modules/.bin/tape test/*.js\n\n.PHONY: test\n\n"
  },
  {
    "path": "README.md",
    "content": "\n# tape-run\n\nA [tape](https://github.com/substack/tape) test runner that runs your tests in\na (headless) browser and returns 0/1 as exit code, so you can use it as your\n`npm test` script.\n\n[![CI](https://github.com/juliangruber/tape-run/actions/workflows/ci.yml/badge.svg)](https://github.com/juliangruber/tape-run/actions/workflows/ci.yml)\n[![downloads](https://img.shields.io/npm/dm/tape-run.svg)](https://www.npmjs.org/package/tape-run)\n\n## Usage\n\nFirst write a test utilizing [tape](https://github.com/substack/tape) and save\nit to `test/test.js`:\n\n```js\nvar test = require('tape');\n\ntest('a test', function (t) {\n  t.ok(true);\n  t.end();\n});\n```\n\nThen run this command using tape-run and\n[browserify](https://github.com/substack/node-browserify) and watch the magic happen\nas the TAP results stream in from a browser (default: electron):\n\n```bash\n$ browserify test/*.js | tape-run\nTAP version 13\n# one\nok 1 true\n\n1..1\n# tests 1\n# pass  1\n\n# ok\n\n$ echo $?\n0\n```\n\n## rollup\n\nIn simple cases you can run `rollup` and `tape-run` right from command line:\n```bash\n$ rollup test/test.js -f iife  | tape-run\n```\nIf you want to use a configuration file, here's an example for `rollup -c | tape-run`:\n```js\nimport resolve from 'rollup-plugin-node-resolve';\nimport commonjs from 'rollup-plugin-commonjs';\nimport builtins from 'rollup-plugin-node-builtins';\nimport istanbul from 'rollup-plugin-istanbul';\n\nexport default {\n  input: 'test/test.js',\n  output: { format: 'iife', sourcemap: 'inline' },\n  plugins: [\n    resolve(),\n    commonjs(),\n    builtins(),\n    istanbul({ exclude: ['dist'] })\n  ]\n}\n```\n\n## With webpack\n\nTo use with [webpack](https://webpack.github.io/), set up a `webpack.test.config.js` to bundle your tape tests. Then, include [webpack-tape-run](https://github.com/syarul/webpack-tape-run) plugin in it. As a result, `$ webpack --config webpack.test.config.js` builds your tests with webpack, runs them in a headless browser, and outputs tap into console with correct exit code. Neat!\n\n## API\n\nYou can use tape-run from JavaScript too:\n\n```js\nvar run = require('tape-run');\nvar browserify = require('browserify');\n\nbrowserify(__dirname + '/test/test.js')\n  .bundle()\n  .pipe(run())\n  .on('results', console.log)\n  .pipe(process.stdout);\n```\n\nAnd run it:\n\n```bash\n$ node example/api.js\nTAP version 13\n# one\nok 1 true\n\n1..1\n# tests 1\n# pass  1\n\n# ok\n{ ok: true,\n  asserts: [ { ok: true, number: 1, name: 'true' } ],\n  pass: [ { ok: true, number: 1, name: 'true' } ],\n  fail: [],\n  errors: [],\n  plan: { start: 1, end: 1 } }\n```\n\n### run([opts])\n\n`opts` can be:\n\n* `wait (Number) [Default: 1000]`: Make `tap-finished` wait longer for results.\nIncrease this value if tests finish without all tests being run.\n* `port (Number)`: If you specify a port it will wait for you to open a browser\non `http://localhost:<port>` and tests will be run there.\n* `static (String)`: Serve static files from this directory.\n* `browser (String)`: Browser to use. Defaults to `electron`. Available if installed:\n  * `chrome`\n  * `firefox`\n  * `ie`\n  * `phantom`\n  * `safari`\n* `keepOpen (Boolean)`: Leave the browser open for debugging after running tests.\n* `node (Boolean)` Enable nodejs integration for electron.\n* `sandbox (Boolean) [Default: true]`: Enable electron sandbox.\n* `basedir` (String): Set this if you need to require node modules in `node` mode.\n\nThe **CLI** takes the same arguments, plus `--render` (see blow):\n\n```bash\n$ tape-run --help\nPipe a browserify stream into this.\nbrowserify [opts] [files] | tape-run [opts]\n\nOptions:\n  --wait       Timeout for tap-finished\n  --port       Wait to be opened by a browser on that port\n  --static     Serve static files from this directory\n  --browser    Browser to use. Always available: electron. Available if installed: chrome, firefox, ie, phantom, safari  [default: \"electron\"]\n  --render     Command to pipe tap output to for custom rendering\n  --keep-open  Leave the browser open for debugging after running tests\n  --node       Enable nodejs integration for electron\n  --sandbox    Enable electron sandbox                                                                                   [default: true]\n  --basedir    Set this if you need to require node modules in node mode\n  --help       Print usage instructions\n```\n\n...or any of the [other options you can pass to browser-run](https://github.com/juliangruber/browser-run#runopts).\n\n## Custom Rendering\n\nIn order to apply custom transformations to tap output without sacrificing the proper exit code, pass `--render` with a command like [tap-spec](https://npmjs.org/package/tap-spec):\n\n```bash\n$ browserify test.js | tape-run --render=\"tap-spec\"\n\n  one\n\n    ✔ true\n\n```\n\n## Headless testing\n\nIn environments without a screen, you can use `Xvfb` to simulate one. We recommend using the default electron browser, \nwhich however requires you to add additional parts to your headless configurations.\n\n### GitHub Actions\n\nThis is a full example to run `npm test`. Refer to the last 2 lines in the YAML config:\n\n```yml\non:\n  - pull_request\n  - push\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v4\n    - run: npm install\n    - run: xvfb-run npm test\n      timeout-minutes: 5 # If the tests fails, the browser will hang open indefinitely\n```\n\n### Travis\n\nAdd this to your travis.yml:\n\n```yml\naddons:\n  apt:\n    packages:\n      - xvfb\ninstall:\n  - export DISPLAY=':99.0'\n  - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &\n  - npm install\n```\n\n[Full example](https://github.com/rhysd/Shiba/blob/055a11a0a2b4f727577fe61371a88d8db9277de5/.travis.yml).\n\n### Any gnu/linux box\n\n```bash\n$ sudo apt-get install xvfb # or equivalent\n$ export DISPLAY=':99.0'\n$ Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &\n$ browser-run ...\n```\n\n### Docker\n\nThere is also an example [Docker image](https://hub.docker.com/r/kipparker/docker-tape-run). [Source](https://github.com/fraserxu/docker-tape-run)\n\n## Installation\n\nWith [npm](http://npmjs.org) do\n\n```bash\n$ npm install tape-run -g # for cli\n$ npm install tape-run    # for api\n```\n\n## Sponsors\n\nThis module is proudly supported by my [Sponsors](https://github.com/juliangruber/sponsors)!\n\nDo you want to support modules like this to improve their quality, stability and weigh in on new features? Then please consider donating to my [Patreon](https://www.patreon.com/juliangruber). Not sure how much of my modules you're using? Try [feross/thanks](https://github.com/feross/thanks)!\n\n## Security contact information\n\nTo report a security vulnerability, please use the\n[Tidelift security contact](https://tidelift.com/security).\nTidelift will coordinate the fix and disclosure.\n\n## License\n\n(MIT)\n\nCopyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "bin/run.js",
    "content": "#!/usr/bin/env node\n\nvar run = require('..');\nvar yargs = require('yargs/yargs');\nvar { hideBin } = require('yargs/helpers');\nvar spawn = require('child_process').spawn;\n\nvar argv = yargs(hideBin(process.argv))\n  .usage('Pipe a browserify stream into this.\\nbrowserify [opts] [files] | $0 [opts]')\n\n  .option('wait', {\n    alias: 'w',\n    type: 'number',\n    description: 'Timeout for tap-finished'\n  })\n  .option('port', {\n    alias: 'p',\n    type: 'number',\n    description: 'Wait to be opened by a browser on that port'\n  })\n  .option('static', {\n    alias: 's',\n    type: 'string',\n    description: 'Serve static files from this directory'\n  })\n  .option('browser', {\n    alias: 'b',\n    type: 'string',\n    default: 'electron',\n    description: 'Browser to use. ' +\n    'Always available: electron. ' +\n    'Available if installed: chrome, firefox, ie, phantom, safari'\n  })\n  .option('render', {\n    alias: 'r',\n    type: 'string',\n    description: 'Command to pipe tap output to for custom rendering'\n  })\n  .option('keep-open', {\n    alias: ['k', 'keepOpen'],\n    type: 'boolean',\n    description: 'Leave the browser open for debugging after running tests'\n  })\n  .option('node', {\n    alias: ['n', 'node-integration', 'nodeIntegration'],\n    type: 'boolean',\n    description: 'Enable nodejs integration for electron'\n  })\n  .option('sandbox', {\n    type: 'boolean',\n    default: true,\n    description: 'Enable electron sandbox'\n  })\n  .option('basedir', {\n    description: 'Set this if you need to require node modules in node mode'\n  })\n  .parse();\n\nvar runner = run(argv);\n\nprocess.stdin\n  .pipe(runner)\n  .on('results', function (results) {\n    process.exit(Number(!results.ok));\n  });\n\nif (argv.render) {\n  var ps = spawn(argv.render);\n  runner.pipe(ps.stdin);\n  ps.stdout.pipe(process.stdout, { end: false });\n  ps.stderr.pipe(process.stderr, { end: false });\n} else {\n  runner.pipe(process.stdout);\n}\n"
  },
  {
    "path": "example/api.js",
    "content": "var run = require('..');\nvar browserify = require('browserify');\nvar resolve = require('path').resolve;\n\nvar script = process.argv[2] || __dirname + '/../test/fixtures/one.js';\nscript = resolve(script);\n\nbrowserify(script)\n  .bundle()\n  .pipe(run())\n  .on('results', console.log)\n  .pipe(process.stdout);\n"
  },
  {
    "path": "example/coverify.sh",
    "content": "#!/usr/bin/env bash\nBIN=\"../node_modules/.bin\"\n\n$BIN/browserify -t coverify ../test/fixtures/one.js | ../bin/run.js | $BIN/coverify\n\n"
  },
  {
    "path": "index.js",
    "content": "var browserRun = require('browser-run')\nvar finished = require('@juliangruber/tap-finished');\nvar through = require('through');\nvar throughout = require('throughout');\n\nmodule.exports = run;\n\nfunction run (opts) {\n  if (!opts) opts = {};\n\n  var input = through();\n  var browser = browserRun(opts);\n  var dpl = throughout(input, browser);\n\n  browser\n    .pipe(finished(opts, function (results) {\n      if(!opts.keepOpen) browser.stop();\n      dpl.emit('results', results);\n    }));\n\n  return dpl;\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"tape-run\",\n  \"description\": \"Headless tape test runner\",\n  \"version\": \"11.0.0\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/juliangruber/tape-run.git\"\n  },\n  \"homepage\": \"https://github.com/juliangruber/tape-run\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"make test\"\n  },\n  \"bin\": {\n    \"tape-run\": \"./bin/run.js\"\n  },\n  \"dependencies\": {\n    \"@juliangruber/tap-finished\": \"0.0.2\",\n    \"browser-run\": \"^12.0.0\",\n    \"through\": \"^2.3.8\",\n    \"throughout\": \"0.0.0\",\n    \"yargs\": \"^17.4.1\"\n  },\n  \"devDependencies\": {\n    \"browserify\": \"^14.0.0\",\n    \"coverify\": \"^1.4.1\",\n    \"tape\": \"^4.6.0\"\n  },\n  \"keywords\": [\n    \"tape\",\n    \"test\",\n    \"tap\",\n    \"runner\",\n    \"phantomjs\",\n    \"headless\"\n  ],\n  \"author\": {\n    \"name\": \"Julian Gruber\",\n    \"email\": \"mail@juliangruber.com\",\n    \"url\": \"http://juliangruber.com\"\n  },\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=14\"\n  }\n}\n"
  },
  {
    "path": "tea.yaml",
    "content": "# https://tea.xyz/what-is-this-file\n---\nversion: 1.0.0\ncodeOwners:\n  - '0xE7DEE1B8Bb97C3065850Cf582D6DED57C6009587'\nquorum: 1\n"
  },
  {
    "path": "test/api.js",
    "content": "var test = require('tape');\nvar run = require('..');\nvar browserify = require('browserify');\n\ntest('api: one', function (t) {\n  t.plan(1);\n\n  browserify(__dirname + '/fixtures/one.js')\n    .bundle()\n    .pipe(run())\n    .on('results', function (results) {\n      t.equal(results.ok, true);\n    })\n});\n\ntest('api: fail', function (t) {\n  t.plan(1);\n\n  browserify(__dirname + '/fixtures/fail.js')\n    .bundle()\n    .pipe(run())\n    .on('results', function (results) {\n      t.equal(results.ok, false);\n    });\n});\n\ntest('api: error', function (t) {\n  t.plan(1);\n\n  browserify(__dirname + '/fixtures/error.js')\n    .bundle()\n    .pipe(run())\n    .on('results', function (results) {\n      t.equal(results.ok, false);\n    });\n});\n\n"
  },
  {
    "path": "test/cli.js",
    "content": "var test = require('tape');\nvar spawn = require('child_process').spawn;\nvar browserify = require('browserify');\n\ntest('cli: one', function (t) {\n  t.plan(1);\n\n  var run = spawn('node', [ __dirname + '/../bin/run.js' ]);\n  run.stderr.pipe(process.stderr, { end: false });\n\n  run.on('exit', function (code) {\n    t.equals(code, 0);\n  });\n\n  browserify(__dirname + '/fixtures/one.js')\n    .bundle()\n    .pipe(run.stdin);\n});\n\ntest('cli: fail', function (t) {\n  t.plan(1);\n\n  var run = spawn('node', [ __dirname + '/../bin/run.js' ]);\n  run.stderr.pipe(process.stderr, { end: false });\n\n  run.on('exit', function (code) {\n    t.equals(code, 1);\n  });\n\n  browserify(__dirname + '/fixtures/fail.js')\n    .bundle()\n    .pipe(run.stdin);\n});\n\ntest('cli: error', function (t) {\n  t.plan(1);\n\n  var run = spawn('node', [ __dirname + '/../bin/run.js' ]);\n  run.stderr.pipe(process.stderr, { end: false });\n\n  run.on('exit', function (code) {\n    t.equals(code, 1);\n  });\n\n  browserify(__dirname + '/fixtures/error.js')\n    .bundle()\n    .pipe(run.stdin);\n});\n"
  },
  {
    "path": "test/fixtures/error.js",
    "content": "var test = require('tape')\n\ntest('...', function (t) {\n  t.ok(true);\n  throw new Error('hmm')\n  t.end()\n})\n"
  },
  {
    "path": "test/fixtures/fail.js",
    "content": "var test = require('tape');\n\ntest('fail', function (t) {\n  t.plan(1);\n  t.ok(false);\n});\n"
  },
  {
    "path": "test/fixtures/one.js",
    "content": "var test = require('tape');\n\ntest('one', function (t) {\n  t.plan(1);\n  t.ok(true, 'true');\n});\n"
  }
]