0.15.2 ā€¢ Published 3 days ago

moonshiner v0.15.2

Weekly downloads
-
License
MIT
Repository
-
Last release
3 days ago

Moonshiner

High-proof testing

Installation ā€¢ Writing tests ā€¢ Browser tests ā€¢ Visual tests

Installation

$ npm install --save-dev moonshiner

Writing tests

Write tests by importing and using familiar test methods:

// tests/test.js
import { describe, it } from 'moonshiner';

describe('My tests', () => {
  it('passes', () => {
    assert.ok(true)
  });

  it('fails', () => {
    assert.ok(false)
  });
});

Running tests

Run tests by executing your test script with Node:

$ node tests/test.js

šŸš€ Running tests

  My tests
    āœ… passes
    āŒ fails

āŒ Failed:

  My tests
    fails
      AssertionError: The expression evaluated to a falsy value:

        assert.ok(false)

šŸ Summary

  āœ… 1 passing
  āŒ 1 failing

Browser tests

Moonshiner tests are isomorphic and can run in both Node and Browser environments. Moonshiner also features the ability to automatically launch browsers and serve files. This is done using the configure function from within a Node test script.

// tests/run.js
import { configure } from 'moonshiner';

configure({
  // launch Google Chrome
  browser: 'Chrome',
  // serve the current working directory at /
  server: {
    serve: ['.']
  }
});

The server serve option may also specify virtual files to serve that don't actually exist locally. This can be used to create a virtual index for our browser tests.

// ...
  server: {
    serve: ['.', {
      '/index.html': `
        <!doctype html>
        <html lang="en">
        <body>
          <script type="module" src="/test.js"></script>
        </body>
        </html>`,
    }]
  }
// ...

Now when we run this new test script, Moonshiner will automatically start a server and launch a headless browser before running any tests. As tests in the browser are run, they are also reported upstream with any Node tests.

Frameworks and bundlers

You can use typical test hooks such as before() and after() to perform setup and teardown respectively. However in most cases, configuration options are often derived during setup and need to be available before calling configure(). This can be done in async modules, either before Moonshiner runs, or after disabling autorun and calling run() directly.

import { configure, after } from 'moonshiner';
import { createServer } from 'vite';

// create a vite server and start listening
const vite = await createServer({ /* ... */ });
await vite.listen();

configure({
  browser: {
    name: 'Chrome',
    // provide the vite url to the browser
    url: vite.resolvedUrls.local[0],
  }
});

// clean up vite after tests run
after(async () => {
  await vite.close();
});
import { configure, run } from 'moonshiner';
import { rollup } from 'rollup';

// disable autorun before bundling, as it might take a while
configure({ autorun: 0 });

// generate a rollup bundle
const bundler = await rollup({ /* ... */ });
const bundle = await bundler.generate({ output: 'esm' });

configure({
  browser: 'Chrome',
  server: {
    // transform bundle output into a format expected by `serve`
    serve: [bundle.output.reduce((files, f) => {
      files[`/${f.fileName}`] = f.code ?? f.source;
      return files;
    }, {})]
  }
});

// manually run tests
run();

Visual tests

When running tests in supported browsers, a screenshot() method is made available to test contexts. This method can be used to capture screenshots of the current page using the test name as the screenshot name. If a screenshot already exists and it does not match the new screenshot, the new screenshot is saved beside the existing one and a test error is raised.

By default, screenshots are compared using strict equality of their base64 contents. A custom screenshot compare() method can be configured to compare screenshots using other methods. The example below uses odiff, a pixel differencing tool.

// tests/run.js
import { configure } from 'moonshiner';
import { compare } from 'odiff-bin';

configure({
  browser: 'Chrome',
  screenshots: {
    /** optional path where screenshots will be saved */
    // directory: '__screenshots__',
    /** optional custom suffix used for new screenshots */
    // newSuffix: '.new'
    /** optional custom suffix used for diff images */
    // newSuffix: '.diff'
    /** optional screenshot comparison function */
    async compare(baseline, comparison, diff) {
      // accepts image paths to compare, producing a diff image if not matching
      let { match } = await compare(baseline, comparison, diff);
      // should return { match: true } if no difference is found
      return { match };
    }
  },
  // ...
});

When comparing screenshots, the compare function will be called with the existing screenshot path and the new screenshot path. This function should return an object with a match property which should be true when screenshots match. The compare function is also called with a third argument, a diff path, which can be used to save a diff image with the other screenshots. Any existing diff image is removed before comparing new screenshots.

Still brewing

Planned features are still coming soon, such as additional reporters, a CLI, and more!

1.0.0-beta.5

3 days ago

1.0.0-beta.4

4 days ago

1.0.0-beta.2

10 days ago

1.0.0-beta.3

10 days ago

1.0.0-beta.1

11 days ago

1.0.0-beta.0

22 days ago

0.15.2

2 months ago

0.15.1

2 months ago

0.15.0

3 months ago

0.11.0

11 months ago

0.12.0

10 months ago

0.11.1

10 months ago

0.13.0

10 months ago

0.14.0

10 months ago

0.13.1

10 months ago

0.10.0

11 months ago

0.9.0

1 year ago

0.8.3

1 year ago

0.8.2

1 year ago

0.8.1

1 year ago

0.8.0

1 year ago

0.7.0

1 year ago

0.6.1

1 year ago

0.6.0

1 year ago

0.5.3

1 year ago

0.5.2

1 year ago

0.5.1

1 year ago

0.5.0

1 year ago

0.4.3

1 year ago

0.4.2

1 year ago

0.4.1

1 year ago

0.4.0

1 year ago

0.3.0

1 year ago

0.2.1

1 year ago

0.2.0

1 year ago

0.0.1

1 year ago