vhs-tape
A tape extension for testing frontend components.
Usage
Code example
const vhs = const MorphComponent = const html = { super this_loadMsg = loadMsg this_msg = 'Hello, not mounted yet' this_count = 0 thisonclick = thisonclick } { return html` Click me Counter: ` } { this_msg = this_loadMsg this } { this_count++ this }
See example.js for more helper functions.
Run your code
Note : You have to install one of those dependencies before running the command line.
budo
Withbudo --live --open example.js
nanotron
Withnanotron example.js
tape-run (and browserify)
WithTape-run documentation invite us to use browserify
browserify example.js | tape-run
API
WIP See https://github.com/hyperdivision/vhs-tape/blob/master/index.js#L53-L91
Tests are written exactly like tape tests except your test body can be an async function and t
has the following helpers.
vhs = require('vhs-tape')
Import the vhs test function. Works almost identically to tape
, except your test function can be async. Async test bodies do not need to call t.done()
, simply return from the async test body, or throw.
vhs(description, async testFn)
Describe your test with a description
string, and pass an async testFn
which receives the t
assertion variable. This assertion variable includes all of the tape
helpers, with a few extras that are helpful for testing dom elements and components.
vhs.delay(ms)(description, async testFn)
Delay all vhs-test helpers by ms
, unless otherwise noted in the test helper description.
vhs.slow(description, async testFn)
Shorthand for vhs.delay(500)
.
vhs.skip(description, async testFn)
Same as tape
t.skip
.
vhs.only(description, async testFn)
Same as tape
t.only
.
t.element
The HTMLElement element where your test should work inside.
await t.appendChild([parentElOrQuery], el, [msg])
Takes an element el
, append it and then waits for onload. You can also pass a different parent element or query selector parentElOrQuery
to append to. Asserts when complete with a msg
.
const newDiv = documentnewDivinnerText = 'New div to append'await t
await t.removeChild(elementOrQuerySelector, [msg])
Takes a loaded element el
or query selector and removes it from its parent element and then waits for onunload. Asserts when complete with a msg
.
await t.sleep(ms, [msg])
Async sleep for ms
and asserts when complete with msg
.
await t.onload(element, [msg])
Wait for the element to be fully mounted and rendered into the page.
const myElement = documenttelementawait t
await t.onunload(element, [msg])
Same as t.onload
except it lets you wait for an element to be fully unloaded from the document.
await t.raf([msg])
Lets you wait for an animation frame to fire. This gives an opportunity for the page to repaint and reflow after making modifications to the DOM. Always waits for a RequestAnimationFrame and ignores any delay parameters. Only asserts when passed a msg
. Does not insert additional delays.
await t.delay([msg])
Similar to await t.raf()
, except this will sleep when a test delay is set, so you can watch your test in slow motion. When no delay is set, these will revert to just a t.raf()
. Only asserts when passed a msg
.
await t.click(elementOrQuerySelector, [msg])
Accepts a query selector string that resolves to an element or an element. Calls element.click()
followed by a t.delay()
.
await t.focus(elementOrQuerySelector, [msg])
Accepts a query selector string that resolves to an element or an element. Calls element.focus()
followed by a t.delay()
.
await t.blur(elementOrQuerySelector, [msg])
Accepts a query selector string that resolves to an element or an element. Calls element.blur()
followed by a t.delay()
.
await t.type(string, [event], [msg])
Dispatches new window.KeyboardEvent
defaulting to the keydown
event, for each character in string
. Helpful for typing into the currently focused element on screen. This helper is a WIP, and doesn't work everywhere. Includes a t.delay()
call so updates are rendered every keypress.
await t.typeValue(elementOrQuerySelector, string, [msg])
Sumulate typing to an elementOrQuerySelector
by repeatedly setting the value and waiting for a delay.
await once(emitter, name, [msg])
Shortcut to use 'events.once'
, which is useful for catching events as promises.
CLI
VSH-Tape ships with a headless test runner that utilizes browserify and tape-run.
Pass a glob string, or series of glob strings as arguments to locate test files. Browserify flags are passed at the end after the --
and tape-run opts are passed as a subarg
under the --tape-run
flag. Note: tape-run opts are not aliased. Refer to the tape-run README to see the available options.
If no file glob is passed, the default '**/*.vhs.js'
is used. Ensure that you quote your file globs so that your CLI doesn't try to perform a depth limited globbing search instead of the built in globber.
Usage:
vhs-tape '**/*.vhs.js' [opts] --tape-run [tape-run opts] -- [browserify opts]
Options:
--help, -h show help message
--version show version
--tape-run tape-run subargs
--ignore file globs to ignore default: node_modules/** .git/**
-- [browserify options] raw flags to pass to browserify
WIP: Interactive test runner
FAQ
How do I run vhs-tests?
vhs-tests
are geared towards a Node.js style common.js environment, so you will need a bundler like browserify or webpack to bundle them into the browser or an electron app.
How do I load global styles or assumed side effects?
If your components or tests require global styles or sprite sheets to work, write a module that mounts these assets into the page as a side effect of require
ing or import
ing that file.
In each test, require the global style module, and your module loading system will de-duplicate the calls to the global side-effects, and each of your tests will still work.
// global-styles.cssconst css = // Mounts global styles when global-styles.css is imported once// Be sure that your mounting logic can accomidate your production app and the test documentdocument || documentbody
In each test that needs these assets you would then do the following:
const vhs = // vhs('The rest of your tests...
Additionally, you can always load a test bundle into a page with styles and spritesheets already mounted, or utilize features in your bundler to hande that insertion for you.
Contributors
- @tony-go - logo and features