Skip to content

Commit

Permalink
Add utils for entity dialog testing
Browse files Browse the repository at this point in the history
  • Loading branch information
volkanceylan committed Oct 13, 2024
1 parent 536343b commit c328c59
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 4 deletions.
41 changes: 41 additions & 0 deletions build/test-utils/entitydialogutils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { EntityDialog } from "@serenity-is/corelib";
import { waitForAjaxRequests } from "./waitutils";

export class EntityDialogTestWrapper<TDialog extends EntityDialog<any, any>> {
constructor(public readonly actual: TDialog) {
}

clickDeleteButton(): Promise<void> {
var button = this.actual.element.findFirst(".delete-button");
if (!button.length)
throw "Delete button not found in the dialog!";
if (button.hasClass("disabled"))
throw "Delete button is disabled!";
const spy = jest.spyOn(window, "confirm").mockReturnValue(true);
button.click();
spy.mockRestore();
return waitForAjaxRequests();
}

clickSaveButton(): Promise<void> {
var button = this.actual.element.findFirst(".save-and-close-button");
if (!button.length)
throw "Save button not found in the dialog!";
if (button.hasClass("disabled"))
throw "Save button is disabled!";
button.click();
return waitForAjaxRequests();
}


setTextInput(name: string, value: any) {
var input = this.actual["byId"](name);
if (!input.length)
throw `Input not found in the dialog: ${name}!`;
input.val(value).trigger("change");
}

waitForAjaxRequests(timeout: number = 10000): Promise<void> {
return waitForAjaxRequests(timeout);
}
}
4 changes: 3 additions & 1 deletion build/test-utils/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from "./mocks";
export * from "./entitydialogutils";
export * from "./mocks";
export * from "./waitutils";
92 changes: 91 additions & 1 deletion build/test-utils/jsdom-global.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,101 @@ const JSDOMEnvironment = pkg.default || pkg.JSDOMEnvironment || pkg;
export default class JSDOMEnvironmentGlobal extends JSDOMEnvironment {
async setup() {
await super.setup();
addCSSEscape(this.global);
this.global.jsdom = this.dom;
}

async teardown() {
this.global.jsdom = undefined;
await super.teardown();
}
}
}



function addCSSEscape(window) {
if (typeof window !== "undefined" && (!window.CSS || !window.CSS.escape)) {
// https://drafts.csswg.org/cssom/#serialize-an-identifier
var cssEscape = function (value) {
if (arguments.length == 0) {
throw new TypeError('`CSS.escape` requires an argument.');
}
var string = String(value);
var length = string.length;
var index = -1;
var codeUnit;
var result = '';
var firstCodeUnit = string.charCodeAt(0);

if (
// If the character is the first character and is a `-` (U+002D), and
// there is no second character, […]
length == 1 &&
firstCodeUnit == 0x002D
) {
return '\\' + string;
}

while (++index < length) {
codeUnit = string.charCodeAt(index);
// Note: there’s no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.

// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
// (U+FFFD).
if (codeUnit == 0x0000) {
result += '\uFFFD';
continue;
}

if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(
index == 1 &&
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
firstCodeUnit == 0x002D
)
) {
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' ';
continue;
}

// If the character is not handled by one of the above rules and is
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
// U+005A), or [a-z] (U+0061 to U+007A), […]
if (
codeUnit >= 0x0080 ||
codeUnit == 0x002D ||
codeUnit == 0x005F ||
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
codeUnit >= 0x0061 && codeUnit <= 0x007A
) {
// the character itself
result += string.charAt(index);
continue;
}

// Otherwise, the escaped character.
// https://drafts.csswg.org/cssom/#escape-a-character
result += '\\' + string.charAt(index);
}
return result;
};

if (!window.CSS) {
window.CSS = {};
}

window.CSS.escape = cssEscape;
}
}
4 changes: 2 additions & 2 deletions build/test-utils/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ export function mockFetch(map?: { [urlOrService: string]: ((info: MockFetchInfo)
fetchSpy = (window as any).fetch = jest.fn(async (url: string, init: RequestInit) => {
var callback = fetchMap[url] ?? fetchMap["*"];
if (!callback) {
console.error(`Fetch is not configured on the mock fetch implementation: (${url})!`);
throw `Fetch is not configured on the mock fetch implementation: (${url})!`;
console.error(`Mock fetch is not configured for URL: (${url})!`);
throw `Mock fetch is not configured for URL: (${url})!`;
}

var requestData = typeof init.body == "string" ? JSON.parse(init.body) : null;
Expand Down
4 changes: 4 additions & 0 deletions build/test-utils/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"compilerOptions": {
"noEmit": true,
"lib": [
"es2015",
"dom"
],
"outDir": "./out",
"typeRoots": [
"../../../Serenity/node_modules/@types",
Expand Down
22 changes: 22 additions & 0 deletions build/test-utils/waitutils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { getActiveRequests } from "@serenity-is/corelib";

export function waitForAjaxRequests(timeout: number = 10000): Promise<void> {
return waitUntil(() => typeof globalThis.jQuery !== 'undefined' ? globalThis.jQuery.active == 0 : (getActiveRequests() <= 0), timeout);
}

export function waitUntil(predicate: () => boolean, timeout: number = 10000, checkInterval: number = 10): Promise<void> {
var start = Date.now();
return new Promise((resolve, reject) => {
let interval = setInterval(() => {
if (!predicate()) {
if (Date.now() - start > timeout) {
clearInterval(interval);
reject("Timed out while waiting for condition to be true!");
}
return;
}
clearInterval(interval);
resolve(void 0);
}, checkInterval)
})
}

0 comments on commit c328c59

Please sign in to comment.