Testerrific

The absolute best, fastest, easiest way test your site

Testerrific tries to take the headache out of site testing by making things simple and concise.

NOTE: This whole site is a testing playground! Use the button below to clear existing tests, and you can click the "Run" button on any block of code to see how it affects the tests (code blocks are editable).

Features

Getting Started

Creating Tests

Global Options

Events & Functions

Other Examples & Tips


Features

Simple syntax

By far the easiest syntax of any testing suite. Write tests as simply as tt.test("a < 4")

Flexible

Test anything that resolves truthy or falsey, no need to adjust your code.

Powerful

Even though it's so simple, you can customize tests in a number of ways to create exactly the scenarios you need to check.

Intuitive UI

You can disable tests, pause execution, or even run a specific test on demand—all without having to go back to your code to make changes.

Reactive

Change the Testerrific data object (ie. 'tt') and the UI will update automatically, which helps a lot with on-the-fly tweaks and the trial-and-error phase of writing tests.

Async friendly

Whether you're waiting for the server, the DOM, even on user input, Testerrific has things like auto-retry, conditional checks, and promise-friendly inputs to make sure tests run when they should.

Helper functions and events

A whole set of functions and events to be able to track and adjust how your tests affect or respond to just about any situation on your site.

Lightweight & dependency-free

Testerrific weighs only 8.5kb gzipped (5.7kb JS, 2.8kb CSS) and doesn't require any other libraries.


Getting Started

Installation

Just link to the Testerrific JS and CSS files...

<!-- Download and link to the files locally: --> <script src="testerrific.min.js"></script> <link rel="Stylesheet" href="testerrific.min.css" type="text/css" /> <!-- OR use link to the files on jsdelivr CDN: --> <script src="https://cdn.jsdelivr.net/gh/thomhines/testerrific@master/testerrific.min.js"></script> <link rel="Stylesheet" href="https://cdn.jsdelivr.net/gh/thomhines/testerrific@master/testerrific.min.css" type="text/css" />

and then add some tests in your javascript.

The Basics

Tests are organized into test groups, and every group is saved as an array in tt.groups. Testerrific uses a "reactive" UI, meaning that changes made to the data saved in the tt objects are shown instantly in the interface. Adding or changing a test will automatically make that test show up in the tests list.

To start adding tests, simply run tt.test() to add a test to your list

tt.group('First Test Group'); tt.test('1 + 1 == 2'); tt.test("Is window tall enough?", 'window.innerHeight > 200'); tt.test("Is it after 8am?", () => { return (new Date()).getHours() >= 8 });

Creating Tests

Test Groups

group(label, [options]);

The group() function will create a new test group. Every test written after that will be in that test group until another test group is created.

label: (string) text shown as title for test group

options: (object) that can contain the following values: skip: (boolean) whether to skip this test or not only: (boolean) skip all other tests that are not also flagged as "only" collapse: (boolean) whether tests are shown or not when page is loaded beforeEach: (function/promise) function that gets run before each test in group afterEach: (function/promise) function that gets run after each test in group

Examples

To create a new test group:

tt.group("Simple Test Group");

You can also add settings to a group to modify how it loads and functions.

tt.group("Skipped Test Group", { skip: 1 }); tt.group("Another Test Group", { beforeEach: () => { /* Run this code before each test */ } });

Tests

test([label], check, [options]);

The test() function will create a new test (string, function, or promise) and add it to the end of the last test group. If you haven't defined a test group yet, Testerrific will make one for you.

label: (string) text shown as title for test. If no label is given and "check" value is a string, the "check" string will be used as the label.

check: (string) that evaluates as truthy/falsey.
OR
(function) that returns truthy/falsey.
OR
(promise) that resolves truthy/falsey.

options: (object) that can contain the following values: skip: (boolean) whether to skip this test or not only: (boolean) skip all other tests that are not also flagged as "only" wait_for_element: (string) CSS selector string of matching element(s). Test will not run until element is 100% visible max_time: (boolean) skip all other tests that are not also flagged as "only" run_if: (string that evals to truthy/false) Conditional that determines if test should be run message: (string) Message shown in UI for the duration of the test, usually instructions for tests that need manual intervention group: (string or integer) The title or the group index of the group the test should be added to position: (integer) Position within a group the test should be inserted (starting from 0) before: (function/promise) gets run before test. If a promise, test will wait for promise to resolve before beginning. after: (function/promise) gets run after test. If a promise, test will wait for promise to resolve before moving to next test.

Basic (string) test

Test if a string evaluates as truthy or falsey

tt.test("1 > 0");

You can also add a label to make your test easier to read or understand.

tt.test("Is '1' a positive number?", "1 > 0");

Function tests

tt.test("Is today Thursday?", () => { return (new Date()).getDay() == 4; });

Async (promise) tests

Tests that return a promise will run until they resolve with a truthy or falsey value.

tt.test("Test as Promise example", () => { return new Promise(function(resolve, reject) { setTimeout(() => { resolve(true); }, 500); }) });

Manual tests

Tests that can't be accomplished or validated programatically can be

tt.manual_test("'manual test' example", "Clicking buttons below will cause test to pass or fail")

Test options

skip

Disable this test. Skipped tests are only disabled when the tests are first loaded. You can always re-enable a 'skipped' test or run it manually.

tt.test("'skip' example", "4 == 4", { skip: true });
only

Skip all other tests/groups. You can set multiple tests/groups as "only".

tt.test("'only' example", "4 == 4", { only: true });

This effect will only happen when Testerrific is first loaded, or if you run skip_non_only_tests().

tt.skip_non_only_tests()
Test Element
wait_for_element

Wait to run test until specified elements (string with CSS selector) are 100% visible. The test will wait up until the number of milliseconds set in tt.wait_for_element_timeout.

tt.run('Fade in .test_element', () => { $('.test_element').fadeIn(3000) }); tt.test('wait_for_element example', '4 == 4', { wait_for_element: '.test_element', after: () => { $('.test_element').fadeOut() } });
max_time (auto-retry)

By default, Testerrific will retry a test multiple times until it returns truthy, in case there are asynchronous factors that a test might be waiting on. This setting controls the amount of time (integer, in ms) to keep trying a test. Set to '0' to disable auto-retry.

tt.test("'max_time' example (wait 3 sec before giving up)", 'false', { max_time: 3000 });
run_if

A code-test check to determine if test should be run.

b = 3; tt.test("'run_if' example (run_if == false)", '1 > 0', { run_if: 'b == 2' }); tt.test("'run_if' example (run_if == true)", '1 > 0', { run_if: 'b == 3' });
message

Display a message while test is running. This can be helpful to give status updates or instructions to user for manual intervention.

tt.test("'message' example", 'a != 3', { message: 'Just saying hello!', max_time: 3000 // max_time increased to allow message to appear for longer });
group & position

Group value can either be the index (integer, starting from 0) or title (string) of an existing test group. Position is the where the test should be inserted within the group (integer, starting from 0). If no position is given, the test will be added to the end of the selected group.

// Add this test to the 4th spot of the 4th test group tt.test('Add test to specific group example', '1 > 0', { group: 'Simple Test Group' }); tt.test('Add test at Group and Position index example', '1 > 0', { group: 3, position: 3 });
before & after

(function/promise) gets run before/after test

a = 0 tt.test("'before()' example", 'a == 1', { before: () => { a = 1 } });

Scheduled Functions

run([label], fn, [options])

Run an arbitrary function as an item in the tests list.

label: (string) text shown as title for test group. If no label is given and "check" value is a string, the check value will be used as the label fn: (function/promise) Function to be run. If a promise is given, tests will wait for promise to resolve before continuing. options: (object) Options to affect how function is run. See options for test() function above for list of available options.

tt.run("change a to -3", () => { a = -3 }); tt.test("Is a still positive?", "a > 0");

wait(time)

Wait a specified amount of time (in ms) before moving to next test.

tt.wait(3000);

pause()

Pause tests at this point. User will need to manually click 'Resume' in order for tests to continue.

tt.pause();

Global Options

Because Testerrific's UI is reactive, you can manipulate a number of aspects by changing properties of the tt object.

max_time

The amount of time (in ms) to keep trying a test until it returns truthy. This applies to all tests unless a test overwrites its default max_time setting.

tt.max_time = 1000

visible

Whether or not the tests panel is visible or shown.

To start with the Testerrific panel closed, for instance, simply add this to your code that gets run on page load:

tt.visible = false;

Helper Functions & Events

start_tests([group_index])

Run all of the unskipped tests. If a group_index is given, it will only run the tests in that group. If no index is given, all tests will be run starting from the first group.

tt.start_tests();

pause_tests()

Pause execution of tests.
Note: the tests will only get paused at the conclusion of the current test

tt.pause_tests();

resume_tests()

Resume execution of tests.

tt.resume_tests();

run_test(group_index, test_index)

Run specific test. Both group_index and test_index are integers of the position of which group and test to run (starting from 0).

tt.run_test(0,2);

pass_test([group_index], [test_index])

Set specific test as 'passed'. Both group_index and test_index are integers of the position of which group and test to run (starting from 0). If either index is blank, pass_test() will assume the group and/or test currently being run.

You can use this to pass tests triggered by outside actions, such as...

tt.pass_test(0,2);

fail_test([group_index], [test_index])

Set specific test as 'failed'. Both group_index and test_index are integers of the position of which group and test to run (starting from 0). If either index is blank, fail_test() will assume the group and/or test currently being run.

You can use this to fail tests triggered by outside actions, such as...

tt.fail_test(0,2);

skip_test([group_index], [test_index])

Set specific test as 'skipped'. Both group_index and test_index are integers of the position of which group and test to run (starting from 0). If either index is blank, skip_test() will assume the group and/or test currently being run.

You can use this to skip tests triggered by outside actions, such as...

tt.skip_test(0,2);

finish_tests()

Quit execution of tests, cancelling any test that is currently being run.

tt.finish_tests();

reset_tests()

Reset all results and timers for all tests.

tt.reset_tests();

alert(message, [time_limit])

Display text 'message' (string) for the number of milliseconds set in time_limit. If time_limit is not set, it will display the message indefinitely or until another message is shown.

tt.alert('You obviously love to press the buttons', 3000);

toggle_tests_panel()

Open tests panel if closed, close it if it's open.

tt.toggle_tests_panel();

enable_all_groups()

Mark all groups and tests as enabled (ie. not 'skipped').

tt.enable_all_groups();

disable_all_groups()

Mark all groups and tests as disabled (ie. 'skipped').

tt.disable_all_groups();

collapse_all_groups()

Visually collapse all groups in the tests panel. Tests within a collapsed group will still run even if they aren't visible.

tt.collapse_all_groups();

expand_all_groups()

Visually expand all groups in the tests panel.

tt.expand_all_groups();

toggle_view_group(group_index)

Toggle whether the tests within a specific test group are visible.

tt.toggle_view_group(0);

toggle_skip_group(group_index)

Toggle whether the tests within a specific test group are enabled (ie. not 'skipped') or not.

tt.toggle_skip_group(0);

toggle_skip_test(group_index, test_index)

Toggle whether a specific test within a specific test group are enabled (ie. not 'skipped') or not.

tt.toggle_skip_test(1, 3);

tt.totals([type] = 'all', [group_index]) ... allows 'all', 'run', 'passed', 'failed', 'skipped', or 'error'

Returns the number of tests that have a certain result type for a specific test group. Result types can be 'all', 'run', 'passed', 'failed', 'skipped', or 'error'. If not type is given, totals() will assume 'all'. If not group_index is given, totals() will return a count for all test groups.

alert(` Total number of tests: ${tt.totals()} Total number 'passed' tests: ${tt.totals('passed')} Total number of 'skipped' tests in the 2nd test group: ${tt.totals('skipped', 1)} `);

Helpful Hints and Examples

Start with test groups collapsed

Each group and test is an element in an array (tt.groups). To start with all of the test groups closed, just loop through all of your groups and set their 'collapse' property to true like this:

tt.groups.forEach((group) => { group.collapse = true });

Skipping tests via code

To skip/unskip a test programmatically, simply set the `skip` property for that test to true/false in the tt.groups array. This code will re-enable Test #4 in Group 1:

tt.groups[1].tests[3].skip = false;

Run tests on keystroke

This one's already been run. Press Cmd-G or Ctrl-G to start running the tests!

$(window).keydown(function(event) { if(event.metaKey = true && event.key == 'g') { event.preventDefault(); event.stopPropagation(); tt.start_tests(); } });

Duplicating a test group

There are times when you want to run a set of tests that are very similar to another set of tests. You can duplicate and modify a test group simply by copying and altering elements of the tt.groups array.

tt.groups.push(tt.groups[0]); tt.groups[tt.groups.length - 1].label = "This is a copy of the first test group";