blob: 45c47b06bd7e8f0c65e35a0c903c483d89c8c179 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class JasmineUtils {
static isMsie() {
return navigator.userAgent.indexOf("MSIE") > -1 || navigator.userAgent.indexOf("Trident") > -1;
};
static checkGridCss(element, columnStart, columnEnd, rowStart, rowEnd) {
columnEnd = this.convertGridCss(columnEnd);
rowEnd = this.convertGridCss(rowEnd);
if (this.isMsie()) {
expect(getComputedStyle(element).msGridColumn).toBe(columnStart);
expect(getComputedStyle(element).msGridColumnSpan).toBe(columnEnd);
expect(getComputedStyle(element).msGridRow).toBe(rowStart);
expect(getComputedStyle(element).msGridRowSpan).toBe(rowEnd);
} else {
expect(getComputedStyle(element).gridColumnStart).toBe(columnStart);
expect(getComputedStyle(element).gridColumnEnd).toBe(columnEnd);
expect(getComputedStyle(element).gridRowStart).toBe(rowStart);
expect(getComputedStyle(element).gridRowEnd).toBe(rowEnd);
}
};
static convertGridCss(end) {
if (JasmineTestTool.msie) {
switch (end) {
case "auto":
return "1";
case "span 2":
return "2";
case "span 3":
return "3";
case "span 4":
return "4";
default:
return end;
}
} else {
return end;
}
};
}
class JasmineTestTool {
static ajaxReadyStateChangeEvent = "tobago.jtt.ajax.readyStateChange";
static ajaxReadyState;
steps = [];
done;
timeout;
/**
* @param done function from Jasmine; must called if all Steps done or timeout
* @param timeout for a single step; default 20000ms
*/
constructor(done, timeout) {
this.done = done;
this.timeout = timeout ? timeout : 20000;
}
/**
* Setup a test.
* @param startConditionFn the desired start condition
* @param doFn may be null; if start condition is not fulfilled, doFn is executed
* @param eventType if start condition is not fulfilled, an event is dispatched
* @param eventElement if start condition is not fulfilled, an event is dispatched
*/
setup(startConditionFn, doFn, eventType, eventElement) {
let eventFn;
if (typeof eventElement !== "function") {
eventFn = () => fail("'eventElement' must be a function but was: " + eventElement);
} else {
eventFn = () => eventElement().dispatchEvent(new Event(eventType, {bubbles: true}));
}
this.steps.push({
type: "setup",
startConditionFunc: startConditionFn,
doFunc: doFn,
eventFunc: eventFn,
substep: 4
});
}
/**
* Execute dispatchEvent() on the given element.
* @param type of the event, e.g. 'click' or 'change'
* @param element on which the event is dispatched, like a querySelector for a button element
* @param result function to indicate if the event dispatched correctly. Must be return 'false' before the event is
* dispatched. Must be return 'true' after the event is dispatched.
*/
event(type, element, result) {
let eventFn;
if (typeof element !== "function") {
eventFn = () => fail("'element' must be a function but was: " + element);
} else {
eventFn = () => element().dispatchEvent(new Event(type, {bubbles: true}));
}
this.steps.push({
type: "event",
eventType: type,
eventFunc: eventFn,
resultFunc: result,
substep: 3
});
}
do(fn) {
this.steps.push({
type: "do",
func: fn,
substep: 1
});
}
wait(fn) {
this.steps.push({
type: "wait",
func: fn,
substep: 1
});
}
start() {
const steps = this.steps;
let done = this.done;
const timeout = this.timeout;
let lastStepExecution;
console.debug("[JasmineTestTool] start");
registerAjaxReadyStateListener();
resetTimeout();
cycle();
function cycle() {
const nextStep = getNextStep();
if (isFinished()) {
done();
console.debug("[JasmineTestTool] finished");
} else if (isTimeout()) {
fail("Timeout of " + JSON.stringify(nextStep));
nextStep.substep = 0;
resetTimeout();
window.setTimeout(cycle, 1);
} else if (!isDocumentReady() || !isAjaxReady()) {
console.debug("[JasmineTestTool] documentReady: " + isDocumentReady() + " - ajaxReady: " + isAjaxReady());
window.setTimeout(cycle, 50);
} else if (nextStep.type === "setup" && nextStep.substep === 4) {
console.debug("[JasmineTestTool] setup/4-step: " + nextStep.startConditionFunc);
if (nextStep.startConditionFunc()) {
nextStep.substep = 0;
} else {
nextStep.substep--;
}
resetTimeout();
window.setTimeout(cycle, 1);
} else if (nextStep.type === "setup" && nextStep.substep === 3) {
console.debug("[JasmineTestTool] setup/3-step: " + nextStep.doFunc);
if (nextStep.doFunc === null) {
nextStep.substep--;
resetTimeout();
window.setTimeout(cycle, 1);
} else {
execute(nextStep.doFunc, nextStep);
}
} else if (nextStep.type === "setup" && nextStep.substep === 2) {
console.debug("[JasmineTestTool] setup/2-step: " + nextStep.eventFunc);
execute(nextStep.eventFunc, nextStep);
} else if (nextStep.type === "setup" && nextStep.substep === 1) {
console.debug("[JasmineTestTool] setup/1-step: wait for " + nextStep.startConditionFunc);
waitFor(nextStep.startConditionFunc, nextStep);
} else if (nextStep.type === "event" && nextStep.substep === 3) {
console.debug("[JasmineTestTool] event/3-step: " + nextStep.resultFunc);
if (nextStep.resultFunc()) {
fail("The result function (" + nextStep.resultFunc + ") returns already 'true' BEFORE the '"
+ nextStep.eventType + "' event is dispatched. Please define a result function which return 'false' before"
+ " dispatch event and return 'true' after dispatch event.");
nextStep.substep = 0;
resetTimeout();
window.setTimeout(cycle, 1);
} else {
nextStep.substep--;
resetTimeout();
window.setTimeout(cycle, 1);
}
} else if (nextStep.type === "event" && nextStep.substep === 2) {
console.debug("[JasmineTestTool] event/2-step: " + nextStep.eventFunc);
execute(nextStep.eventFunc, nextStep);
} else if (nextStep.type === "event" && nextStep.substep === 1) {
console.debug("[JasmineTestTool] event/1-step: wait for " + nextStep.resultFunc);
waitFor(nextStep.resultFunc, nextStep);
} else if (nextStep.type === "do") {
console.debug("[JasmineTestTool] do-step: " + nextStep.func);
execute(nextStep.func, nextStep);
} else if (nextStep.type === "wait") {
console.debug("[JasmineTestTool] wait-step: " + nextStep.func);
waitFor(nextStep.func, nextStep);
} else {
fail("an unexpected error has occurred!");
done();
}
}
function getNextStep() {
for (let step of steps) {
if (step.substep > 0) {
return step;
}
}
return null;
}
function isFinished() {
for (let step of steps) {
if (step.substep > 0) {
return false;
}
}
return true;
}
function isDocumentReady() {
return document.getElementById("page:testframe").contentWindow.document.readyState === "complete";
}
function registerAjaxReadyStateListener() {
JasmineTestTool.ajaxReadyState = XMLHttpRequest.UNSENT;
window.removeEventListener(JasmineTestTool.ajaxReadyStateChangeEvent, JasmineTestTool.changeAjaxReadyState);
window.addEventListener(JasmineTestTool.ajaxReadyStateChangeEvent, JasmineTestTool.changeAjaxReadyState);
}
function registerCustomXmlHttpRequest() {
class JasmineXMLHttpRequest extends XMLHttpRequest {
constructor() {
super();
this.addEventListener("readystatechange", function () {
window.dispatchEvent(new CustomEvent(JasmineTestTool.ajaxReadyStateChangeEvent,
{detail: {readyState: this.readyState}}));
});
}
}
document.getElementById("page:testframe").contentWindow.XMLHttpRequest = JasmineXMLHttpRequest;
}
function isAjaxReady() {
return JasmineTestTool.ajaxReadyState === XMLHttpRequest.UNSENT
|| JasmineTestTool.ajaxReadyState === XMLHttpRequest.DONE;
}
function isTimeout() {
return Date.now() > (lastStepExecution + timeout);
}
function resetTimeout() {
lastStepExecution = Date.now();
}
function execute(fn, nextStep) {
registerCustomXmlHttpRequest();
fn();
nextStep.substep--;
resetTimeout();
window.setTimeout(cycle, 1);
}
function waitFor(fn, nextStep) {
if (fn()) {
nextStep.substep--;
resetTimeout();
}
window.setTimeout(cycle, 50);
}
}
static changeAjaxReadyState(event) {
JasmineTestTool.ajaxReadyState = event.detail.readyState;
console.debug("[JasmineTestTool] ajaxReadyState: " + JasmineTestTool.ajaxReadyState);
}
}
export {JasmineUtils, JasmineTestTool};