Simple helper for unit testing with JavaScript Testing Frameworks (e.g. Jasmine, QUnit, etc.), to load HTML pages as fixtures.
This provides a new window (<iframe>
) for your code which handles DOM, or that which requires independent name spaces (global
), etc.
(If you want more features, other great tools such as jasmine-jquery that has many matchers and jQuery supporting will help you.)
Example (Jasmine): https://anseki.github.io/test-page-loader/
(Each frame is opened by clicking a gray bar.)
Features:
- Load HTML pages into
<iframe>
instead of an element likediv#qunit-fixture
. This is useful for tests that need running based on document (i.e. window,<body>
, etc.), or tests that need independent name spaces (global
). For example, testing a function that does something according to various document situations, or testing a library that has cache data (i.e. each test code requires initial condition). - Don't remove the
<iframe>
s that were used for each test and show those on main page, if you want. This is useful for tests that should be checked by looking in addition to the test. - No dependency library. You need to add just only one file, and this works without depending on anything (even Testing Framework).
Load a test-page-loader.js
file into your main page that is "test runner".
<script src="path/to/test-page-loader.js"></script>
A function loadPage
is provided in global scope (i.e. window).
loadPage(url, ready[, title])
Type: string
An URL of the HTML page to load.
A new <iframe>
element is added to the main page, and then this URL is loaded.
Type: Function
ready(window, document, body[, done])
A callback function that is called when the page that was specified by url
was loaded.
Your test code usually be written in this function, or another function that is called in this function.
In this function, window
points a window of <iframe>
that loaded the url
(i.e. iframe.contentWindow
). document
and body
also are those of <iframe>
(i.e. these are shortcut to iframe.contentDocument
and iframe.contentDocument.body
).
See Asynchronous Support for done
.
For example, Jasmine:
loadPage('spec/foo-class/bar-method.html', function(window, document, body) {
body.appendChild(document.createElement('div')); // `body` and `document` in `<iframe>`
expect(document.getElementsByTagName('div').length).toBeGreaterThan(0);
});
QUnit:
loadPage('spec/foo-class/bar-method.html', function(window, document, body) {
body.appendChild(document.createElement('div')); // `body` and `document` in `<iframe>`
assert.ok(document.getElementsByTagName('div').length > 0);
});
Type: string
By default, an <iframe>
element is removed when the testing that used it was finished.
If the title
argument is given, the <iframe>
is kept and shown in the main page for result that should be checked by looking in addition to the test.
You can pass a string as a heading of the <iframe>
. If you want to pass the same title to methods of Testing Framework, you can get the title that was specified to it by document.title
(i.e. a title of the document that is loaded into <iframe>
). Note that a document.title
is not changed if it is already set.
See also: window.setTitle
For example, Jasmine:
// `fixture.html` has no `<title>`.
loadPage('fixture.html', function(window, document, body) {
it(document.title, function() { // Jasmine prints "FOO should be BAR" in result list.
// Do something ...
});
}, 'FOO should be BAR');
QUnit:
// `fixture.html` has no `<title>`.
loadPage('fixture.html', function(window, document, body) {
// Do something ...
assert.equal(true, true, document.title); // QUnit prints "FOO should be BAR" in result list.
}, 'FOO should be BAR');
If loadPage
is called multiple times, each requested page is loaded in turn.
By default, loading next page starts when current ready
callback was exited. You can make the next loading wait by making the ready
callback take done
argument. done
is callback function, and loading next page waits until done
callback is called.
For example:
loadPage('page-1.html', function(window, document, body, done) {
setTimeout(function() {
done(); // After 3sec., start loading `page-2.html`.
}, 3000);
// `ready` is exited here, but don't start loading `page-2.html` yet.
});
loadPage('page-2.html', function(window, document, body) {
// Do something ...
});
Note that testing functions of some Testing Frameworks such as Jasmine work inside of specific scope. Therefore, for example, it()
function that is called after describe()
function exited doesn't work.
If you want to control the sequence of loading pages and testing those, controlling timing to call loadPage
by Testing Framework (e.g. done
of Jasmine or assert.async()
of QUnit) is better than controlling timing to call testing functions by done
of ready
callback. (See Examples.)
A window of <iframe>
that is passed to the ready
callback has setTitle
method.
You can change the title
(heading of the <iframe>
) that was specified (or not specified) in loadPage
.
For example, load multiple pages, and set the proper title for the each test. Or, set null
to remove the <iframe>
, when the test was passed.
For example, Jasmine:
var frameWindow, frameDone, currentSpec;
beforeEach(function(beforeDone) {
loadPage('page.html', function(window, document, body, done) {
frameWindow = window;
frameDone = done;
beforeDone(); // Make `it()` start when the page was loaded.
}); // `title` is not yet specified.
});
afterEach(function(done) {
frameWindow.setTitle(
currentSpec.result.failedExpectations.length ?
currentSpec.getFullName() : // 'test-1' and 'test-2' that are specified for `it` method.
null // Drop this `<iframe>` when all tests are passed.
);
frameDone();
done();
});
var test1 = it('test-1', function(done) {
currentSpec = test1;
// Do something ...
expect(1).toBe(0);
done();
});
var test2 = it('test-2', function(done) {
currentSpec = test2;
// Do something ...
expect(1).toBe(1);
done();
});
Note that the setTitle
method works only before ready
callback is exited or done
callback is called in asynchronous mode.
If you have not installed test-page-loader yet, install it first.
You need Node.js (and NPM) installed and available in your $PATH
.
Run the following command to install test-page-loader:
npm install test-page-loader
And, run the following commands for examples:
cd node_modules/test-page-loader
npm install
npm run examples
Note: The above node_modules
is a path that the library was installed into. You might want to do the first command with --only=dev
instead of these commands, but that might not work correctly because version of your NPM has a bug.
And then, access to the following by web browser:
The cd ...
and npm install
commands are required only a first time.
It uses node-static-alias and log4js for http accessing.