Merge more testing coverage from henrikingo fork

* core_tests.js and navigation_tests.js have more tests
* qunit_test_runner.html runs QUnit in a browser (without karma) and
  provides a generic iframe based platform to test different  presentations.
* copy qunit.js and syn.js into the repo. This allows qunit_test_runner.html
  to work without any dependency on node/npm. (Karma obviously does need them.)
* Move jscs cli option to .jscsrc instead
This commit is contained in:
Henrik Ingo
2017-09-16 13:08:51 +03:00
parent 0b4bd08f44
commit 7aaea7fd37
12 changed files with 7511 additions and 156 deletions

View File

@@ -1,166 +1,266 @@
(function() {
var registerEventListener = function( target, eventType, callback ) {
target.addEventListener( eventType, callback );
return function removeRegisteredEventListener() {
target.removeEventListener( eventType, callback );
/*
* Copyright 2016 Henrik Ingo (@henrikingo)
*
* Released under the MIT license. See LICENSE file.
*/
/* 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() {
impress().init();
});
var assertInitWrapper = function() {
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 ) {
assert.expect( 1 );
assert.ok( impress, "impress declared in global scope" );
});
// Synchronous code and assertions
assert.ok( iframeWin.impress,
"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 ) {
assert.expect( 0 );
impress().init();
});
// The asserts below are true immediately after impress().init() returns.
// Therefore we test them here, not in an event handler.
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.expect( 4 );
assert.ok( !iframeDoc.body.classList.contains( "impress-disabled" ),
"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 impressSupported = document.body.classList.contains( "impress-supported" );
assert.ok( impressSupported, "Have class .impress-supported" );
assert.notOk( impressNotSupported, "Don't have class .impress-not-supported" );
var canvas = iframeDoc.querySelector( "div#impress > div" );
assert.ok( !canvas.classList.contains( "step" ) && canvas.id === "",
"Additional 'canvas' div inserted between div#impress root and steps." );
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" );
var impressEnabled = document.body.classList.contains( "impress-enabled" );
assert.ok( impressEnabled, "Have class .impress-enabled" );
assert.notOk( impressDisabled, "Don't have class .impress-disabled" );
});
assert.equal( iframeDoc.documentElement.style.height,
"100%",
"documentElement.style.height is 100%" );
QUnit.test( "Attributes", function( assert ) {
assert.expect( 10 );
// Steps initialization
var step1 = iframeDoc.querySelector( "div#step-1" );
assert.equal( step1.style.position,
"absolute",
"Step position is 'absolute'." );
var actual, expected;
var root = document.querySelector( "#impress" );
var canvas = document.querySelector( "div#impress > div" );
assert.ok( step1.classList.contains( "active" ),
"Step 1 has active css class." );
var canvasIsNotAStep = !canvas.classList.contains("step") && canvas.id === "";
assert.ok( canvasIsNotAStep, "Canvas do not have step element data" );
}
doneSync();
console.log( "End init() test (sync)" );
} ); // LoadIframe()
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";
// Note: Here we focus on testing the core functionality of moving between
// steps, the css classes set and unset, and events triggered.
// TODO: more complex animations and check position, transitions, delays, etc...
QUnit.test( "Impress Core API", function( assert ) {
console.log( "Begin core api test" );
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;
if ( actual === "left top" || actual === "0% 0%" ) {
actual = expected;
}
assert.strictEqual( actual, expected, "canvas.style.transformOrigin initialized correctly" );
// 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
actual = canvas.style.webkitTransformStyle || canvas.style.transformStyle;
expected = "preserve-3d";
assert.strictEqual( actual, expected, "canvas.style.transformStyle initialized correctly" );
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" );
actual = canvas.style.transitionDelay;
expected = "0ms";
assert.strictEqual( actual, expected, "canvas.style.transitionDelay initialized correctly" );
// On impress:stepenter, we do some assertions on the "entered" object.
// On impress:stepleave, we do some assertions on the "left" object.
// 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
];
actual = canvas.style.transitionDuration;
expected = "0ms";
assert.strictEqual( actual, expected, "canvas.style.transitionDuration initialized correctly" );
// 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();
console.log( "End core api test" );
}
}
};
actual = canvas.style.transitionProperty;
expected = "all";
assert.strictEqual( actual, expected, "canvas.style.transitionProperty initialized correctly" );
// 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." );
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 );
actual = canvas.style.transitionTimingFunction;
expected = "ease-in-out";
assert.strictEqual( actual, expected, "canvas.style.transitionTimingFunction initialized correctly" );
// Just by way of comparison, check transitionDuration again, in a non-init transition
var canvas = iframeDoc.querySelector( "div#impress > div" );
assert.equal( canvas.style.transitionDelay,
"0ms",
"canvas.style.transitionDelay set correctly" );
assert.equal( canvas.style.transitionDuration,
"1000ms",
"canvas.style.transitionDuration set correctly" );
actual = root.style.perspective;
expected = "";
assert.notStrictEqual( actual, expected, "root.style.perspective should be set explicitly for IE 11" );
readyForNext();
};
actual = document.documentElement.style.height;
expected = "100%";
assert.strictEqual( actual, expected, "documentElement.style.height is 100%" );
});
var assertStepEnterWrapper = function( event ) {
setTimeout( function() { assertStepEnter( event ); }, wait );
};
root.addEventListener( "impress:stepenter", assertStepEnterWrapper );
QUnit.test( "Steps", function( assert ) {
assert.expect( 2 );
// 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();
};
var actual, expected;
var step1 = document.querySelector( "div#step-1" );
var assertStepLeaveWrapper = function( event ) {
setTimeout( function() { assertStepLeave( event ); }, wait );
};
root.addEventListener( "impress:stepleave", assertStepLeaveWrapper );
actual = step1.style.position;
expected = "absolute";
assert.strictEqual( actual, expected, "Step position is 'absolute'" );
// 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." );
};
assert.ok( step1.classList.contains( "active" ), "Step 1 has active css class." );
});
// Done with setup. Start testing! -----------------------------------------------//
// Do no-op tests first, then trigger the sequence of transitions we setup above. //
QUnit.module( "Core API" );
assert.strictEqual( iframeWin.impress().goto( iframeDoc.querySelector( "div#impress" ) ),
false,
"goto() to a non-step element fails, as it should." );
assert.strictEqual( iframeWin.impress().goto(),
false,
"goto(<nothing>) fails, as it should." );
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();
impress().next();
assert.ok( step2.classList.contains( "active" ), step2.id + " add active css class." );
assert.notOk( step1.classList.contains( "active" ), step1.id + " remove active css class." );
// Reset to original state
var removeStepEnterEvent = registerEventListener( root, "impress:stepenter", function() {
removeStepEnterEvent();
done();
});
impress().goto( step1 );
});
QUnit.test( "impress:stepenter event", function( assert ) {
assert.expect( 4 );
var actual, expected;
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 removeTestEvent = registerEventListener( root, "impress:stepenter", function( event ) {
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" );
assert.notOk( step2.classList.contains( "future" ), event.target.id + " remove future css class" );
assert.notOk( step2.classList.contains( "past" ), event.target.id + " remove active css class." );
removeTestEvent();
// Reset to original state
var removeCleanupEvent = registerEventListener( root, "impress:stepenter", function() {
removeCleanupEvent();
done();
});
impress().goto( step1 );
});
impress().next();
});
QUnit.done(function( details ) {
// Impress.js will set the hash part of the url, we want to unset it when finished
// Otherwise a refresh of browser page would not start tests from the last step step
window.location.hash = "";
// Add back vertical scrollbar so we can read results if there were failures.
document.body.style.overflow = 'auto';
});
}());
// This starts executing the sequence above
assert.ok( iframeWin.impress().next(),
"next() called and returns ok (1->2)" );
} ); // InitPresentation()
} ); // LoadIframe()
} );