Merge pull request #621 from henrikingo/merge-testing
Merge more testing coverage from henrikingo fork
This commit is contained in:
5
.jscsrc
Normal file
5
.jscsrc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"preset": "jquery",
|
||||||
|
// Since we check quotemarks already in jshint, this can be turned off
|
||||||
|
"validateQuoteMarks": false
|
||||||
|
}
|
||||||
@@ -7,11 +7,26 @@ module.exports = function( config ) {
|
|||||||
// Frameworks to use
|
// Frameworks to use
|
||||||
frameworks: [ "qunit" ],
|
frameworks: [ "qunit" ],
|
||||||
|
|
||||||
|
proxies : {
|
||||||
|
'/test/' : '/base/test/',
|
||||||
|
'/js/' : '/base/js/',
|
||||||
|
'/node_modules/syn/dist/' : '/base/node_modules/syn/dist/'
|
||||||
|
},
|
||||||
|
|
||||||
// List of files / patterns to load in the browser
|
// List of files / patterns to load in the browser
|
||||||
files: [
|
files: [
|
||||||
"test/bootstrap.js",
|
// The QUnit tests
|
||||||
"js/impress.js",
|
"test/helpers.js",
|
||||||
"test/core_tests.js"
|
"test/core_tests.js",
|
||||||
|
"test/navigation_tests.js",
|
||||||
|
// Presentation files, for the iframe
|
||||||
|
//"test/core_tests_presentation.html"
|
||||||
|
//{pattern: "test/core_tests_presentation.html", watched: true, served: true, included: false}
|
||||||
|
{pattern: "test/*.html", watched: true, served: true, included: false},
|
||||||
|
{pattern: "test/plugins/*/*.html", watched: true, served: true, included: false},
|
||||||
|
// JS files for iframe
|
||||||
|
{pattern: "js/impress.js", watched: true, served: true, included: false},
|
||||||
|
{pattern: "node_modules/syn/dist/global/syn.js", watched: false, served: true, included: false}
|
||||||
],
|
],
|
||||||
|
|
||||||
// List of files to exclude
|
// List of files to exclude
|
||||||
@@ -43,10 +58,21 @@ module.exports = function( config ) {
|
|||||||
// - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`)
|
// - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`)
|
||||||
// - PhantomJS
|
// - PhantomJS
|
||||||
// - IE (only Windows; has to be installed with `npm install karma-ie-launcher`)
|
// - IE (only Windows; has to be installed with `npm install karma-ie-launcher`)
|
||||||
browsers: [ "Chrome" ],
|
//browsers: [ "Chrome" ],
|
||||||
|
//browsers: [ "Firefox" ],
|
||||||
|
browsers: [ "Chrome", "Firefox" ],
|
||||||
|
|
||||||
// If browser does not capture in given timeout [ms], kill it
|
client: {
|
||||||
captureTimeout: 60000,
|
clearContext: false,
|
||||||
|
qunit: {
|
||||||
|
showUI: true,
|
||||||
|
testTimeout: 120*1000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// If browser does not capture, or produce output, in given timeout [ms], kill it
|
||||||
|
captureTimeout: 60*1000,
|
||||||
|
browserNoActivityTimeout: 60*1000,
|
||||||
|
|
||||||
// Continuous Integration mode
|
// Continuous Integration mode
|
||||||
// if true, it capture browsers, run tests and exit
|
// if true, it capture browsers, run tests and exit
|
||||||
|
|||||||
@@ -22,20 +22,23 @@
|
|||||||
"url": "https://github.com/bartaz/impress.js/issues"
|
"url": "https://github.com/bartaz/impress.js/issues"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "jshint js/impress.js *.js test/bootstrap.js && jscs js/impress.js *.js test/bootstrap.js --preset=jquery",
|
"lint": "jshint js/impress.js test/*.js && jscs js/impress.js test/*.js",
|
||||||
"test": "karma start --single-run",
|
"test": "karma start --single-run",
|
||||||
"test:dev": "karma start",
|
"test:dev": "karma start",
|
||||||
"test:sauce": "karma start karma.conf-sauce.js"
|
"test:sauce": "karma start karma.conf-sauce.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chrome": "0.1.0",
|
"chrome": "0.1.0",
|
||||||
|
"firefox": "0.0.1",
|
||||||
"jscs": "2.11.0",
|
"jscs": "2.11.0",
|
||||||
"jshint": "2.9.1",
|
"jshint": "2.9.1",
|
||||||
"karma": "0.13.22",
|
"karma": "0.13.22",
|
||||||
"karma-chrome-launcher": "1.0.1",
|
"karma-chrome-launcher": "1.0.1",
|
||||||
"karma-cli": "1.0.0",
|
"karma-cli": "1.0.0",
|
||||||
|
"karma-firefox-launcher": "~0.1",
|
||||||
"karma-qunit": "1.0.0",
|
"karma-qunit": "1.0.0",
|
||||||
"karma-sauce-launcher": "1.0.0",
|
"karma-sauce-launcher": "1.0.0",
|
||||||
"qunitjs": "2.0.0-rc1"
|
"qunitjs": "2.0.0-rc1",
|
||||||
|
"syn": "0.10.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
qunit_test_runner.html
Normal file
26
qunit_test_runner.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
Copyright 2016 Henrik Ingo (@henrikingo)
|
||||||
|
Released under the MIT license. See LICENSE file.
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>QUnit tests for impress.js</title>
|
||||||
|
<link rel="stylesheet" href="node_modules/qunitjs/qunit/qunit.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="qunit"></div>
|
||||||
|
|
||||||
|
<div id="qunit-fixture"></div>
|
||||||
|
|
||||||
|
<script src="node_modules/qunitjs/qunit/qunit.js"></script>
|
||||||
|
<!-- The QUnit tests. -->
|
||||||
|
<script src="test/helpers.js"></script>
|
||||||
|
<!-- Core tests -->
|
||||||
|
<script src="test/core_tests.js"></script>
|
||||||
|
<!-- Plugins -->
|
||||||
|
<script src="test/navigation_tests.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
33
test/bootstrap.js
vendored
33
test/bootstrap.js
vendored
@@ -1,12 +1,25 @@
|
|||||||
/*jshint browser:true */
|
/*jshint browser:true */
|
||||||
|
|
||||||
var root = document.createElement( "div" );
|
// TODO: This is the bootstrap file for *karma*. Poorly named (since karma is
|
||||||
root.innerHTML = [
|
// only one option, in this repo) but keeping the same name now to avoid
|
||||||
"<div id='impress'>",
|
// unnecessary deviation with upstream.
|
||||||
" <div class='step' data-x='-1000' data-y='0'>First slide</div>",
|
// If you just want to run the tests locally, you can open test/index.html in Firefox.
|
||||||
" <div class='step' data-x='-800' data-y='0'>Second slide</div>",
|
|
||||||
" <div class='step' data-x='-600' data-y='0'>Third slide</div>",
|
// That's annoying: karma-qunit doesn't provide the qunit-fixture element
|
||||||
" <div class='step' data-x='-400' data-y='0'>Fourth slide</div>",
|
// https://github.com/karma-runner/karma-qunit/issues/18
|
||||||
"</div>"
|
|
||||||
].join( "" );
|
// This file contains so much HTML, that we will just respectfully disagree about js
|
||||||
document.body.appendChild( root );
|
/* jshint quotmark:single */
|
||||||
|
/* global document */
|
||||||
|
|
||||||
|
var fix = document.createElement( 'div' );
|
||||||
|
fix.id = 'qunit-fixture';
|
||||||
|
fix.innerHTML = [
|
||||||
|
'\n',
|
||||||
|
' <iframe id="presentation-iframe"\n',
|
||||||
|
' src="SET THIS IN YOUR QUNIT TESTS"\n',
|
||||||
|
' width="595" height="485"\n',
|
||||||
|
' frameborder="0" marginwidth="0" marginheight="0" scrolling="no"\n',
|
||||||
|
' style="border:1px solid #CCC; max-width: 100%;">\n',
|
||||||
|
' </iframe>'
|
||||||
|
].join( '' );
|
||||||
|
|||||||
@@ -1,166 +1,266 @@
|
|||||||
(function() {
|
/*
|
||||||
var registerEventListener = function( target, eventType, callback ) {
|
* Copyright 2016 Henrik Ingo (@henrikingo)
|
||||||
target.addEventListener( eventType, callback );
|
*
|
||||||
return function removeRegisteredEventListener() {
|
* Released under the MIT license. See LICENSE file.
|
||||||
target.removeEventListener( eventType, callback );
|
*/
|
||||||
};
|
|
||||||
|
/* global document, console, setTimeout, loadIframe, initPresentation, _impressSupported, QUnit */
|
||||||
|
|
||||||
|
QUnit.module( "Core Tests" );
|
||||||
|
|
||||||
|
QUnit.test( "Initialize Impress.js", function( assert ) {
|
||||||
|
console.log( "Begin init() test" );
|
||||||
|
|
||||||
|
// Init triggers impress:init and impress:stepenter events, which we want to catch.
|
||||||
|
var doneInit = assert.async();
|
||||||
|
var doneStepEnter = assert.async();
|
||||||
|
var doneSync = assert.async();
|
||||||
|
|
||||||
|
loadIframe( "test/core_tests_presentation.html", assert, function() {
|
||||||
|
var iframe = document.getElementById( "presentation-iframe" );
|
||||||
|
var iframeDoc = iframe.contentDocument;
|
||||||
|
var iframeWin = iframe.contentWindow;
|
||||||
|
var root = iframeDoc.querySelector( "div#impress" );
|
||||||
|
|
||||||
|
// Catch events triggered by init()
|
||||||
|
var assertInit = function() {
|
||||||
|
assert.ok( true, "impress:init event triggered." );
|
||||||
|
|
||||||
|
var canvas = iframeDoc.querySelector( "div#impress > div" );
|
||||||
|
|
||||||
|
// Delay and duration don't become set before the first transition actually happened
|
||||||
|
assert.equal( canvas.style.transitionDelay,
|
||||||
|
"0ms",
|
||||||
|
"canvas.style.transitionDelay initialized correctly" );
|
||||||
|
assert.equal( canvas.style.transitionDuration,
|
||||||
|
"0ms",
|
||||||
|
"canvas.style.transitionDuration initialized correctly" );
|
||||||
|
|
||||||
|
doneInit();
|
||||||
|
console.log( "End init() test (async)" );
|
||||||
};
|
};
|
||||||
|
|
||||||
QUnit.begin(function() {
|
var assertInitWrapper = function() {
|
||||||
impress().init();
|
setTimeout( function() { assertInit(); }, 10 );
|
||||||
});
|
};
|
||||||
|
root.addEventListener( "impress:init", assertInitWrapper );
|
||||||
|
|
||||||
QUnit.module( "Initialization" );
|
root.addEventListener( "impress:stepenter", function( event ) {
|
||||||
|
assert.ok( true, "impress:stepenter event triggered." );
|
||||||
|
var step1 = iframeDoc.querySelector( "div#step-1" );
|
||||||
|
assert.equal( event.target, step1,
|
||||||
|
event.target.id + " triggered impress:stepenter event." );
|
||||||
|
doneStepEnter();
|
||||||
|
} );
|
||||||
|
|
||||||
QUnit.test( "Global Scope", function( assert ) {
|
// Synchronous code and assertions
|
||||||
assert.expect( 1 );
|
assert.ok( iframeWin.impress,
|
||||||
assert.ok( impress, "impress declared in global scope" );
|
"impress declared in global scope" );
|
||||||
});
|
assert.strictEqual( iframeWin.impress().init(), undefined,
|
||||||
|
"impress().init() called." );
|
||||||
|
assert.strictEqual( iframeWin.impress().init(), undefined,
|
||||||
|
"It's ok to call impress().init() a second time, it's a no-op." );
|
||||||
|
|
||||||
QUnit.test( "Multiple API instantiation", function( assert ) {
|
// The asserts below are true immediately after impress().init() returns.
|
||||||
assert.expect( 0 );
|
// Therefore we test them here, not in an event handler.
|
||||||
impress().init();
|
var notSupportedClass = iframeDoc.body.classList.contains( "impress-not-supported" );
|
||||||
});
|
var yesSupportedClass = iframeDoc.body.classList.contains( "impress-supported" );
|
||||||
|
if ( !_impressSupported() ) {
|
||||||
|
assert.ok( notSupportedClass,
|
||||||
|
"body.impress-not-supported class still there." );
|
||||||
|
assert.ok( !yesSupportedClass,
|
||||||
|
"body.impress-supported class was NOT added." );
|
||||||
|
} else {
|
||||||
|
assert.ok( !notSupportedClass,
|
||||||
|
"body.impress-not-supported class was removed." );
|
||||||
|
assert.ok( yesSupportedClass,
|
||||||
|
"body.impress-supported class was added." );
|
||||||
|
|
||||||
QUnit.test( "Support Markup", function( assert ) {
|
assert.ok( !iframeDoc.body.classList.contains( "impress-disabled" ),
|
||||||
assert.expect( 4 );
|
"body.impress-disabled is removed." );
|
||||||
|
assert.ok( iframeDoc.body.classList.contains( "impress-enabled" ),
|
||||||
|
"body.impress-enabled is added." );
|
||||||
|
|
||||||
var impressNotSupported = document.body.classList.contains( "impress-not-supported" );
|
var canvas = iframeDoc.querySelector( "div#impress > div" );
|
||||||
var impressSupported = document.body.classList.contains( "impress-supported" );
|
assert.ok( !canvas.classList.contains( "step" ) && canvas.id === "",
|
||||||
assert.ok( impressSupported, "Have class .impress-supported" );
|
"Additional 'canvas' div inserted between div#impress root and steps." );
|
||||||
assert.notOk( impressNotSupported, "Don't have class .impress-not-supported" );
|
assert.equal( canvas.style.transform,
|
||||||
|
"rotateZ(0deg) rotateY(0deg) rotateX(0deg) translate3d(1000px, 0px, 0px)",
|
||||||
|
"canvas.style.transform initialized correctly" );
|
||||||
|
assert.equal( canvas.style.transformOrigin,
|
||||||
|
"left top 0px",
|
||||||
|
"canvas.style.transformOrigin initialized correctly" );
|
||||||
|
assert.equal( canvas.style.transformStyle,
|
||||||
|
"preserve-3d",
|
||||||
|
"canvas.style.transformStyle initialized correctly" );
|
||||||
|
assert.equal( canvas.style.transitionProperty,
|
||||||
|
"all",
|
||||||
|
"canvas.style.transitionProperty initialized correctly" );
|
||||||
|
assert.equal( canvas.style.transitionTimingFunction,
|
||||||
|
"ease-in-out",
|
||||||
|
"canvas.style.transitionTimingFunction initialized correctly" );
|
||||||
|
|
||||||
var impressDisabled = document.body.classList.contains( "impress-disabled" );
|
assert.equal( iframeDoc.documentElement.style.height,
|
||||||
var impressEnabled = document.body.classList.contains( "impress-enabled" );
|
"100%",
|
||||||
assert.ok( impressEnabled, "Have class .impress-enabled" );
|
"documentElement.style.height is 100%" );
|
||||||
assert.notOk( impressDisabled, "Don't have class .impress-disabled" );
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test( "Attributes", function( assert ) {
|
// Steps initialization
|
||||||
assert.expect( 10 );
|
var step1 = iframeDoc.querySelector( "div#step-1" );
|
||||||
|
assert.equal( step1.style.position,
|
||||||
|
"absolute",
|
||||||
|
"Step position is 'absolute'." );
|
||||||
|
|
||||||
var actual, expected;
|
assert.ok( step1.classList.contains( "active" ),
|
||||||
var root = document.querySelector( "#impress" );
|
"Step 1 has active css class." );
|
||||||
var canvas = document.querySelector( "div#impress > div" );
|
|
||||||
|
|
||||||
var canvasIsNotAStep = !canvas.classList.contains("step") && canvas.id === "";
|
|
||||||
assert.ok( canvasIsNotAStep, "Canvas do not have step element data" );
|
|
||||||
|
|
||||||
actual = canvas.style.webkitTransform || canvas.style.transform;
|
|
||||||
expected = "rotateZ(0deg) rotateY(0deg) rotateX(0deg) translate3d(1000px, 0px, 0px)";
|
|
||||||
assert.strictEqual( actual, expected, "canvas.style.transform initialized correctly" );
|
|
||||||
|
|
||||||
// Normalize result for IE 11 and Safari.
|
|
||||||
actual = canvas.style.webkitTransformOrigin || canvas.style.transformOrigin;
|
|
||||||
expected = "left top 0px";
|
|
||||||
|
|
||||||
if ( actual === "left top" || actual === "0% 0%" ) {
|
|
||||||
actual = expected;
|
|
||||||
}
|
}
|
||||||
assert.strictEqual( actual, expected, "canvas.style.transformOrigin initialized correctly" );
|
doneSync();
|
||||||
|
console.log( "End init() test (sync)" );
|
||||||
|
} ); // LoadIframe()
|
||||||
|
|
||||||
actual = canvas.style.webkitTransformStyle || canvas.style.transformStyle;
|
} );
|
||||||
expected = "preserve-3d";
|
|
||||||
assert.strictEqual( actual, expected, "canvas.style.transformStyle initialized correctly" );
|
|
||||||
|
|
||||||
actual = canvas.style.transitionDelay;
|
// Note: Here we focus on testing the core functionality of moving between
|
||||||
expected = "0ms";
|
// steps, the css classes set and unset, and events triggered.
|
||||||
assert.strictEqual( actual, expected, "canvas.style.transitionDelay initialized correctly" );
|
// TODO: more complex animations and check position, transitions, delays, etc...
|
||||||
|
QUnit.test( "Impress Core API", function( assert ) {
|
||||||
actual = canvas.style.transitionDuration;
|
console.log( "Begin core api test" );
|
||||||
expected = "0ms";
|
|
||||||
assert.strictEqual( actual, expected, "canvas.style.transitionDuration initialized correctly" );
|
|
||||||
|
|
||||||
actual = canvas.style.transitionProperty;
|
|
||||||
expected = "all";
|
|
||||||
assert.strictEqual( actual, expected, "canvas.style.transitionProperty initialized correctly" );
|
|
||||||
|
|
||||||
actual = canvas.style.transitionTimingFunction;
|
|
||||||
expected = "ease-in-out";
|
|
||||||
assert.strictEqual( actual, expected, "canvas.style.transitionTimingFunction initialized correctly" );
|
|
||||||
|
|
||||||
actual = root.style.perspective;
|
|
||||||
expected = "";
|
|
||||||
assert.notStrictEqual( actual, expected, "root.style.perspective should be set explicitly for IE 11" );
|
|
||||||
|
|
||||||
actual = document.documentElement.style.height;
|
|
||||||
expected = "100%";
|
|
||||||
assert.strictEqual( actual, expected, "documentElement.style.height is 100%" );
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.test( "Steps", function( assert ) {
|
|
||||||
assert.expect( 2 );
|
|
||||||
|
|
||||||
var actual, expected;
|
|
||||||
var step1 = document.querySelector( "div#step-1" );
|
|
||||||
|
|
||||||
actual = step1.style.position;
|
|
||||||
expected = "absolute";
|
|
||||||
assert.strictEqual( actual, expected, "Step position is 'absolute'" );
|
|
||||||
|
|
||||||
assert.ok( step1.classList.contains( "active" ), "Step 1 has active css class." );
|
|
||||||
});
|
|
||||||
|
|
||||||
QUnit.module( "Core API" );
|
|
||||||
|
|
||||||
QUnit.test( ".next()", function( assert ) {
|
|
||||||
assert.expect( 2 );
|
|
||||||
|
|
||||||
var root = document.querySelector( "div#impress" );
|
|
||||||
var step1 = document.querySelector( "div#step-1" );
|
|
||||||
var step2 = document.querySelector( "div#step-2" );
|
|
||||||
var done = assert.async();
|
var done = assert.async();
|
||||||
|
loadIframe( "test/core_tests_presentation.html", assert, function() {
|
||||||
|
initPresentation( assert, function() {
|
||||||
|
var iframe = document.getElementById( "presentation-iframe" );
|
||||||
|
var iframeDoc = iframe.contentDocument;
|
||||||
|
var iframeWin = iframe.contentWindow;
|
||||||
|
|
||||||
impress().next();
|
// Impress.js itself uses event listeners to manipulate most CSS classes.
|
||||||
|
// Wait a short while before checking, to avoid race.
|
||||||
|
// (See assertStepEnterWrapper and assertStepLeaveWrapper.)
|
||||||
|
var wait = 5; // Milliseconds
|
||||||
|
|
||||||
assert.ok( step2.classList.contains( "active" ), step2.id + " add active css class." );
|
var step1 = iframeDoc.querySelector( "div#step-1" );
|
||||||
assert.notOk( step1.classList.contains( "active" ), step1.id + " remove active css class." );
|
var step2 = iframeDoc.querySelector( "div#step-2" );
|
||||||
|
var step3 = iframeDoc.querySelector( "div#step-3" );
|
||||||
|
var step4 = iframeDoc.querySelector( "div#fourth" );
|
||||||
|
var root = iframeDoc.querySelector( "div#impress" );
|
||||||
|
|
||||||
// Reset to original state
|
// On impress:stepenter, we do some assertions on the "entered" object.
|
||||||
var removeStepEnterEvent = registerEventListener( root, "impress:stepenter", function() {
|
// On impress:stepleave, we do some assertions on the "left" object.
|
||||||
removeStepEnterEvent();
|
// Finally we call next() to initialize the next transition, and it starts all over again.
|
||||||
|
var i = 0;
|
||||||
|
var sequence = [ { left: step1,
|
||||||
|
entered: step2,
|
||||||
|
next: function() { return iframeWin.impress().goto( 2 ); },
|
||||||
|
text: "goto(<number>) called and returns ok (2->3)" },
|
||||||
|
{ left: step2,
|
||||||
|
entered: step3,
|
||||||
|
next: function() { return iframeWin.impress().goto( "fourth" ); },
|
||||||
|
text: "goto(<string>) called and returns ok (3->4)" },
|
||||||
|
{ left: step3,
|
||||||
|
entered: step4,
|
||||||
|
next: function() { return iframeWin.impress().next(); },
|
||||||
|
text: "next() wraps around to first step (4->1)" },
|
||||||
|
{ left: step4,
|
||||||
|
entered: step1,
|
||||||
|
next: function() { return iframeWin.impress().prev(); },
|
||||||
|
text: "prev() wraps around to last step (1->4)" },
|
||||||
|
{ left: step1,
|
||||||
|
entered: step4,
|
||||||
|
next: function() { return iframeWin.impress().prev(); },
|
||||||
|
text: "prev() called and returns ok (4->3)" },
|
||||||
|
{ left: step4,
|
||||||
|
entered: step3,
|
||||||
|
next: function() { return iframeWin.impress().goto( 0 ); },
|
||||||
|
text: "End of test suite, return to first step with goto(0)." },
|
||||||
|
{ left: step3,
|
||||||
|
entered: step1,
|
||||||
|
next: false } // False = end of sequence
|
||||||
|
];
|
||||||
|
|
||||||
|
// When both assertStepEnter and assertStepLeave are done, we can go to next step in sequence.
|
||||||
|
var readyCount = 0;
|
||||||
|
var readyForNext = function() {
|
||||||
|
readyCount++;
|
||||||
|
if ( readyCount % 2 === 0 ) {
|
||||||
|
if ( sequence[ i ].next ) {
|
||||||
|
assert.ok( sequence[ i ].next(), sequence[ i ].text );
|
||||||
|
i++;
|
||||||
|
assertImmediately();
|
||||||
|
} else {
|
||||||
done();
|
done();
|
||||||
});
|
console.log( "End core api test" );
|
||||||
impress().goto( step1 );
|
}
|
||||||
});
|
}
|
||||||
|
};
|
||||||
|
|
||||||
QUnit.test( "impress:stepenter event", function( assert ) {
|
// Things to check on impress:stepenter event -----------------------------//
|
||||||
assert.expect( 4 );
|
var assertStepEnter = function( event ) {
|
||||||
|
assert.equal( event.target, sequence[ i ].entered,
|
||||||
|
event.target.id + " triggered impress:stepenter event." );
|
||||||
|
assert.ok( event.target.classList.contains( "present" ),
|
||||||
|
event.target.id + " set present css class." );
|
||||||
|
assert.ok( !event.target.classList.contains( "future" ),
|
||||||
|
event.target.id + " unset future css class." );
|
||||||
|
assert.ok( !event.target.classList.contains( "past" ),
|
||||||
|
event.target.id + " unset past css class." );
|
||||||
|
assert.equal( "#/" + event.target.id, iframeWin.location.hash,
|
||||||
|
"Hash is " + "#/" + event.target.id );
|
||||||
|
|
||||||
var actual, expected;
|
// Just by way of comparison, check transitionDuration again, in a non-init transition
|
||||||
var root = document.querySelector( "div#impress" );
|
var canvas = iframeDoc.querySelector( "div#impress > div" );
|
||||||
var step1 = document.querySelector( "div#step-1" );
|
assert.equal( canvas.style.transitionDelay,
|
||||||
var step2 = document.querySelector( "div#step-2" );
|
"0ms",
|
||||||
var done = assert.async();
|
"canvas.style.transitionDelay set correctly" );
|
||||||
|
assert.equal( canvas.style.transitionDuration,
|
||||||
|
"1000ms",
|
||||||
|
"canvas.style.transitionDuration set correctly" );
|
||||||
|
|
||||||
var removeTestEvent = registerEventListener( root, "impress:stepenter", function( event ) {
|
readyForNext();
|
||||||
actual = event.target;
|
};
|
||||||
expected = step2;
|
|
||||||
assert.strictEqual( actual, expected, "Triggered event for the second step" );
|
|
||||||
|
|
||||||
assert.ok( step2.classList.contains( "present" ), event.target.id + " add present css class" );
|
var assertStepEnterWrapper = function( event ) {
|
||||||
assert.notOk( step2.classList.contains( "future" ), event.target.id + " remove future css class" );
|
setTimeout( function() { assertStepEnter( event ); }, wait );
|
||||||
assert.notOk( step2.classList.contains( "past" ), event.target.id + " remove active css class." );
|
};
|
||||||
|
root.addEventListener( "impress:stepenter", assertStepEnterWrapper );
|
||||||
|
|
||||||
removeTestEvent();
|
// Things to check on impress:stepleave event -----------------------------//
|
||||||
|
var assertStepLeave = function( event ) {
|
||||||
|
assert.equal( event.target, sequence[ i ].left,
|
||||||
|
event.target.id + " triggered impress:stepleave event." );
|
||||||
|
assert.ok( !event.target.classList.contains( "present" ),
|
||||||
|
event.target.id + " unset present css class." );
|
||||||
|
assert.ok( !event.target.classList.contains( "future" ),
|
||||||
|
event.target.id + " unset future css class." );
|
||||||
|
assert.ok( event.target.classList.contains( "past" ),
|
||||||
|
event.target.id + " set past css class." );
|
||||||
|
readyForNext();
|
||||||
|
};
|
||||||
|
|
||||||
// Reset to original state
|
var assertStepLeaveWrapper = function( event ) {
|
||||||
var removeCleanupEvent = registerEventListener( root, "impress:stepenter", function() {
|
setTimeout( function() { assertStepLeave( event ); }, wait );
|
||||||
removeCleanupEvent();
|
};
|
||||||
done();
|
root.addEventListener( "impress:stepleave", assertStepLeaveWrapper );
|
||||||
});
|
|
||||||
|
|
||||||
impress().goto( step1 );
|
// Things to check immediately after impress().goto() ---------------------------//
|
||||||
});
|
var assertImmediately = function() {
|
||||||
|
assert.ok( sequence[ i ].entered.classList.contains( "active" ),
|
||||||
|
sequence[ i ].entered.id + " set active css class." );
|
||||||
|
assert.ok( !sequence[ i ].left.classList.contains( "active" ),
|
||||||
|
sequence[ i ].left.id + " unset active css class." );
|
||||||
|
};
|
||||||
|
|
||||||
impress().next();
|
// Done with setup. Start testing! -----------------------------------------------//
|
||||||
});
|
// Do no-op tests first, then trigger the sequence of transitions we setup above. //
|
||||||
|
|
||||||
QUnit.done(function( details ) {
|
assert.strictEqual( iframeWin.impress().goto( iframeDoc.querySelector( "div#impress" ) ),
|
||||||
// Impress.js will set the hash part of the url, we want to unset it when finished
|
false,
|
||||||
// Otherwise a refresh of browser page would not start tests from the last step step
|
"goto() to a non-step element fails, as it should." );
|
||||||
window.location.hash = "";
|
assert.strictEqual( iframeWin.impress().goto(),
|
||||||
// Add back vertical scrollbar so we can read results if there were failures.
|
false,
|
||||||
document.body.style.overflow = 'auto';
|
"goto(<nothing>) fails, as it should." );
|
||||||
});
|
|
||||||
}());
|
// This starts executing the sequence above
|
||||||
|
assert.ok( iframeWin.impress().next(),
|
||||||
|
"next() called and returns ok (1->2)" );
|
||||||
|
} ); // InitPresentation()
|
||||||
|
} ); // LoadIframe()
|
||||||
|
} );
|
||||||
|
|||||||
24
test/core_tests_presentation.html
Normal file
24
test/core_tests_presentation.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
Copyright 2016 Henrik Ingo (@henrikingo)
|
||||||
|
Released under the MIT license. See LICENSE file.
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>The presentation steps used in an iframe in core_tests.js</title>
|
||||||
|
</head>
|
||||||
|
<!-- id is used by syn -->
|
||||||
|
<body class="impress-not-supported" id="bodyid">
|
||||||
|
<div id="impress">
|
||||||
|
<div class="step" data-x="-1000" data-y="0">First slide</div>
|
||||||
|
<div class="step" data-x="-800" data-y="0">Second slide <br /><a href="#fourth" id="linktofourth">link to fourth slide</a></div>
|
||||||
|
<div class="step" data-x="-600" data-y="0">Third slide<br /><a href="#step-1" id="linktofirst">link to first slide</a></div>
|
||||||
|
<div class="step" id="fourth" data-x="-400" data-y="0">Fourth slide</div>
|
||||||
|
</div>
|
||||||
|
<script src="../js/impress.js"></script>
|
||||||
|
<!-- This is a copy of dist/syn.js from bower install syn. (The one in npm install doesn't work in a browser.) -->
|
||||||
|
<!-- See http://bitovi.com/blog/2010/07/syn-a-standalone-synthetic-event-library.html for simple usage guide. -->
|
||||||
|
<script src="../node_modules/syn/dist/global/syn.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
110
test/helpers.js
Normal file
110
test/helpers.js
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
// This file contains so much HTML, that we will just respectfully disagree about js
|
||||||
|
/* jshint quotmark:single */
|
||||||
|
/* global document, console, setTimeout, navigator */
|
||||||
|
/* exported loadIframe, initPresentation, _impressSupported */
|
||||||
|
|
||||||
|
var loadIframe = function( src, assert, callback ) {
|
||||||
|
console.log( 'Begin loadIframe' );
|
||||||
|
|
||||||
|
// When running in Karma, the #qunit-fixture appears from somewhere and we can't set its
|
||||||
|
// contents in advance.
|
||||||
|
var fix = document.getElementById( 'qunit-fixture' );
|
||||||
|
fix.innerHTML = [
|
||||||
|
'\n',
|
||||||
|
' <iframe id="presentation-iframe"\n',
|
||||||
|
' src="SET THIS IN YOUR QUNIT TESTS"\n',
|
||||||
|
' width="595" height="485"\n',
|
||||||
|
' frameborder="0" marginwidth="0" marginheight="0" scrolling="no"\n',
|
||||||
|
' style="border:1px solid #CCC; max-width: 100%;">\n',
|
||||||
|
' </iframe>'
|
||||||
|
].join( '' );
|
||||||
|
|
||||||
|
var iframe = document.getElementById( 'presentation-iframe' );
|
||||||
|
|
||||||
|
var onLoad = function() {
|
||||||
|
assert.ok( true,
|
||||||
|
'Presentation loaded. iframe.src = ' + iframe.src );
|
||||||
|
try {
|
||||||
|
assert.ok( iframe.contentDocument,
|
||||||
|
'Verifying that tests can access the presentation inside the iframe. ' +
|
||||||
|
'Note: On Firefox this fails when using paths with "../" parts for the iframe.' );
|
||||||
|
}
|
||||||
|
catch ( err ) {
|
||||||
|
assert.ok( false,
|
||||||
|
'Error when trying to access presentation in iframe. Note: When using Chrome with ' +
|
||||||
|
'local files (file:///) this will fail with SecurityError. ' +
|
||||||
|
'You can however use Chrome over Karma.' );
|
||||||
|
}
|
||||||
|
console.log( 'End loadIframe' );
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: Seems to be some race in loading js files inside the iframe (in CircleCI).
|
||||||
|
// The error that happens is that window.impress isn't set yet, even if onLoad event triggered.
|
||||||
|
// Needs more investigation.
|
||||||
|
var onLoadWrapper = function( event ) {
|
||||||
|
setTimeout( function() { onLoad( event ); }, 1000 );
|
||||||
|
};
|
||||||
|
iframe.addEventListener( 'load', onLoadWrapper );
|
||||||
|
|
||||||
|
assert.ok( true,
|
||||||
|
'Setting iframe.src = ' + src );
|
||||||
|
iframe.src = src;
|
||||||
|
};
|
||||||
|
|
||||||
|
var initPresentation = function( assert, callback ) {
|
||||||
|
console.log( 'Begin initPresentation' );
|
||||||
|
var iframe = document.getElementById( 'presentation-iframe' );
|
||||||
|
var iframeDoc = iframe.contentDocument;
|
||||||
|
var iframeWin = iframe.contentWindow;
|
||||||
|
|
||||||
|
// Impress:stepenter is the last event triggered in init(), so we wait for that.
|
||||||
|
var waitForStepEnter = function( event ) {
|
||||||
|
assert.ok( true, 'impress (' + event.target.id + ') is now initialized.' );
|
||||||
|
iframeDoc.removeEventListener( 'impress:stepenter', waitForStepEnterWrapper );
|
||||||
|
console.log( 'End initPresentation' );
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unfortunately, impress.js uses the impress:stepenter event internally to
|
||||||
|
// do some things related to entering a step. This causes a race condition when
|
||||||
|
// we listen for the same event and expect it to be done with everything.
|
||||||
|
// We wait 5 ms to resolve the race condition, then it's safe to start testing.
|
||||||
|
var waitForStepEnterWrapper = function( event ) {
|
||||||
|
setTimeout( function() { waitForStepEnter( event ); }, 5 );
|
||||||
|
};
|
||||||
|
iframeDoc.addEventListener( 'impress:stepenter', waitForStepEnterWrapper );
|
||||||
|
|
||||||
|
assert.strictEqual( iframeWin.impress().init(), undefined, 'Initializing impress.' );
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to determine whether this browser is supported by
|
||||||
|
// impress.js or not. Copied from impress.js itself.
|
||||||
|
var _impressSupported = function() {
|
||||||
|
var pfx = ( function() {
|
||||||
|
var style = document.createElement( 'dummy' ).style,
|
||||||
|
prefixes = 'Webkit Moz O ms Khtml'.split( ' ' ),
|
||||||
|
memory = {};
|
||||||
|
return function( prop ) {
|
||||||
|
if ( typeof memory[ prop ] === 'undefined' ) {
|
||||||
|
var ucProp = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
|
||||||
|
props = ( prop + ' ' + prefixes.join( ucProp + ' ' ) + ucProp ).split( ' ' );
|
||||||
|
memory[ prop ] = null;
|
||||||
|
for ( var i in props ) {
|
||||||
|
if ( style[ props[ i ] ] !== undefined ) {
|
||||||
|
memory[ prop ] = props[ i ];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return memory[ prop ];
|
||||||
|
};
|
||||||
|
} )();
|
||||||
|
|
||||||
|
var ua = navigator.userAgent.toLowerCase();
|
||||||
|
return ( pfx( 'perspective' ) !== null ) &&
|
||||||
|
( document.body.classList ) &&
|
||||||
|
( document.body.dataset ) &&
|
||||||
|
( ua.search( /(iphone)|(ipod)|(android)/ ) === -1 );
|
||||||
|
};
|
||||||
|
|
||||||
169
test/navigation_tests.js
Normal file
169
test/navigation_tests.js
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 Henrik Ingo (@henrikingo)
|
||||||
|
*
|
||||||
|
* Released under the MIT license. See LICENSE file.
|
||||||
|
*/
|
||||||
|
/* global QUnit, loadIframe, initPresentation, document, window */
|
||||||
|
|
||||||
|
QUnit.module( "Navigation plugin" );
|
||||||
|
|
||||||
|
QUnit.test( "Navigation Plugin", function( assert ) {
|
||||||
|
window.console.log( "Begin navigation plugin" );
|
||||||
|
var done = assert.async();
|
||||||
|
|
||||||
|
loadIframe( "test/core_tests_presentation.html", assert, function() {
|
||||||
|
initPresentation( assert, function() {
|
||||||
|
var iframe = document.getElementById( "presentation-iframe" );
|
||||||
|
var iframeDoc = iframe.contentDocument;
|
||||||
|
var iframeWin = iframe.contentWindow;
|
||||||
|
|
||||||
|
var wait = 5; // Milliseconds
|
||||||
|
|
||||||
|
var step1 = iframeDoc.querySelector( "div#step-1" );
|
||||||
|
var step2 = iframeDoc.querySelector( "div#step-2" );
|
||||||
|
var step3 = iframeDoc.querySelector( "div#step-3" );
|
||||||
|
var step4 = iframeDoc.querySelector( "div#fourth" );
|
||||||
|
var root = iframeDoc.querySelector( "div#impress" );
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
var sequence = [ { left: step1,
|
||||||
|
entered: step2,
|
||||||
|
next: function() { return iframeWin.syn.type( "bodyid", " " ); },
|
||||||
|
text: "space (2->3)" },
|
||||||
|
{ left: step2,
|
||||||
|
entered: step3,
|
||||||
|
next: function() { return iframeWin.syn.type( "bodyid", "[right]" ); },
|
||||||
|
text: "[right] (3->4)" },
|
||||||
|
{ left: step3,
|
||||||
|
entered: step4,
|
||||||
|
next: function() { return iframeWin.syn.type( "bodyid", "\t" ); },
|
||||||
|
text: "tab (4->1)" },
|
||||||
|
{ left: step4,
|
||||||
|
entered: step1,
|
||||||
|
next: function() { return iframeWin.syn.type( "bodyid", "[down]" ); },
|
||||||
|
text: "[down] (1->2)" },
|
||||||
|
{ left: step1,
|
||||||
|
entered: step2,
|
||||||
|
next: function() { return iframeWin.syn.type( "bodyid", "[page-down]" ); },
|
||||||
|
text: "[page-down] (2->3)" },
|
||||||
|
{ left: step2,
|
||||||
|
entered: step3,
|
||||||
|
next: function() { return iframeWin.syn.type( "bodyid", "[page-up]" ); },
|
||||||
|
text: "[page-up] (3->2)" },
|
||||||
|
{ left: step3,
|
||||||
|
entered: step2,
|
||||||
|
next: function() { return iframeWin.syn.type( "bodyid", "[left]" ); },
|
||||||
|
text: "[left] (2->1)" },
|
||||||
|
{ left: step2,
|
||||||
|
entered: step1,
|
||||||
|
next: function() { return iframeWin.syn.type( "bodyid", "[up]" ); },
|
||||||
|
text: "[up] (1->4)" },
|
||||||
|
{ left: step1,
|
||||||
|
entered: step4,
|
||||||
|
next: function() { return iframeWin.syn.click( "step-2", {} ); },
|
||||||
|
text: "click on 2 (4->2)" },
|
||||||
|
{ left: step4,
|
||||||
|
entered: step2,
|
||||||
|
next: function() { return iframeWin.syn.click( "linktofourth", {} ); },
|
||||||
|
text: "click on link with href to id=fourth (2->4)" },
|
||||||
|
{ left: step2,
|
||||||
|
entered: step4,
|
||||||
|
next: function() { return iframeWin.impress().goto( 0 ); },
|
||||||
|
text: "Return to first step with goto(0)." },
|
||||||
|
{ left: step4,
|
||||||
|
entered: step1,
|
||||||
|
next: false }
|
||||||
|
];
|
||||||
|
|
||||||
|
var readyCount = 0;
|
||||||
|
var readyForNext = function() {
|
||||||
|
readyCount++;
|
||||||
|
if ( readyCount % 2 === 0 ) {
|
||||||
|
if ( sequence[ i ].next ) {
|
||||||
|
assert.ok( sequence[ i ].next(), sequence[ i ].text );
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
window.console.log( "End navigation plugin" );
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Things to check on impress:stepenter event -----------------------------//
|
||||||
|
var assertStepEnter = function( event ) {
|
||||||
|
assert.equal( event.target, sequence[ i ].entered,
|
||||||
|
event.target.id + " triggered impress:stepenter event." );
|
||||||
|
readyForNext();
|
||||||
|
};
|
||||||
|
|
||||||
|
var assertStepEnterWrapper = function( event ) {
|
||||||
|
window.setTimeout( function() { assertStepEnter( event ); }, wait );
|
||||||
|
};
|
||||||
|
root.addEventListener( "impress:stepenter", assertStepEnterWrapper );
|
||||||
|
|
||||||
|
// Things to check on impress:stepleave event -----------------------------//
|
||||||
|
var assertStepLeave = function( event ) {
|
||||||
|
assert.equal( event.target, sequence[ i ].left,
|
||||||
|
event.target.id + " triggered impress:stepleave event." );
|
||||||
|
readyForNext();
|
||||||
|
};
|
||||||
|
|
||||||
|
var assertStepLeaveWrapper = function( event ) {
|
||||||
|
window.setTimeout( function() { assertStepLeave( event ); }, wait );
|
||||||
|
};
|
||||||
|
root.addEventListener( "impress:stepleave", assertStepLeaveWrapper );
|
||||||
|
|
||||||
|
assert.ok( iframeWin.impress().next(), "next() called and returns ok (1->2)" );
|
||||||
|
} ); // InitPresentation()
|
||||||
|
} ); // LoadIframe()
|
||||||
|
} );
|
||||||
|
|
||||||
|
QUnit.test( "Navigation Plugin - No-op tests", function( assert ) {
|
||||||
|
window.console.log( "Begin navigation no-op" );
|
||||||
|
var done = assert.async();
|
||||||
|
|
||||||
|
loadIframe( "test/core_tests_presentation.html", assert, function() {
|
||||||
|
initPresentation( assert, function() {
|
||||||
|
var iframe = document.getElementById( "presentation-iframe" );
|
||||||
|
var iframeDoc = iframe.contentDocument;
|
||||||
|
var iframeWin = iframe.contentWindow;
|
||||||
|
|
||||||
|
var wait = 5; // Milliseconds
|
||||||
|
|
||||||
|
var root = iframeDoc.querySelector( "div#impress" );
|
||||||
|
|
||||||
|
// This should never happen -----------------------------//
|
||||||
|
var assertStepEnter = function( event ) {
|
||||||
|
assert.ok( false,
|
||||||
|
event.target.id + " triggered impress:stepenter event." );
|
||||||
|
};
|
||||||
|
|
||||||
|
var assertStepEnterWrapper = function( event ) {
|
||||||
|
window.setTimeout( function() { assertStepEnter( event ); }, wait );
|
||||||
|
};
|
||||||
|
root.addEventListener( "impress:stepenter", assertStepEnterWrapper );
|
||||||
|
|
||||||
|
// This should never happen -----------------------------//
|
||||||
|
var assertStepLeave = function( event ) {
|
||||||
|
assert.ok( false,
|
||||||
|
event.target.id + " triggered impress:stepleave event." );
|
||||||
|
};
|
||||||
|
|
||||||
|
var assertStepLeaveWrapper = function( event ) {
|
||||||
|
window.setTimeout( function() { assertStepLeave( event ); }, wait );
|
||||||
|
};
|
||||||
|
root.addEventListener( "impress:stepleave", assertStepLeaveWrapper );
|
||||||
|
|
||||||
|
// These are no-op actions, we're already in step-1 -----------------------//
|
||||||
|
assert.ok( iframeWin.syn.click( "step-1", {} ),
|
||||||
|
"Click on step that is currently active, should do nothing." );
|
||||||
|
assert.ok( iframeWin.syn.click( "linktofirst", {} ),
|
||||||
|
"Click on link pointing to step that is currently active, should do nothing." );
|
||||||
|
|
||||||
|
// After delay, if no event triggers are called. We're done.
|
||||||
|
window.setTimeout( function() {
|
||||||
|
window.console.log( "End navigation no-op" ); done();
|
||||||
|
}, 3000 );
|
||||||
|
} ); // InitPresentation()
|
||||||
|
} ); // LoadIframe()
|
||||||
|
} );
|
||||||
Reference in New Issue
Block a user