Skip to content

Commit

Permalink
Moved test-utils from common-features repository
Browse files Browse the repository at this point in the history
  • Loading branch information
volkanceylan committed Oct 18, 2024
1 parent 553fdc3 commit b865908
Show file tree
Hide file tree
Showing 17 changed files with 572 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
artifacts/
dynamic-data/
coverage/
out/
/*/dist/**/*.js
Expand Down
1 change: 1 addition & 0 deletions packages/test-utils/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dynamic-data/
15 changes: 15 additions & 0 deletions packages/test-utils/editorutils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Fluent } from "@serenity-is/corelib";

export function typeText(editor: { value: string, element: Fluent }, value: string) {
editor.element.trigger("focus");
editor.value = value;
editor.element.trigger("blur");
editor.element.trigger("change");
}

export function typeNumber(editor: { value: number, element: Fluent }, value: number) {
editor.element.trigger("focus");
editor.value = value;
editor.element.trigger("blur");
editor.element.trigger("change");
}
51 changes: 51 additions & 0 deletions packages/test-utils/entitydialogutils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { EntityDialog } from "@serenity-is/corelib";
import { waitForAjaxRequests } from "./waitutils";

export class EntityDialogWrapper<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();
}

getTextInput(name: string) {
var input = this.actual["byId"](name);
if (!input.length)
throw `getTextInput: Input with name ${name} is not found in the dialog!`;
return input.val();
}

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

waitForAjaxRequests(timeout: number = 10000): Promise<void> {
return waitForAjaxRequests(timeout);
}

getForm<TForm>(type: { new(prefix: string): TForm }): TForm {
return new type(this.actual.idPrefix);
}
}
4 changes: 4 additions & 0 deletions packages/test-utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./entitydialogutils";
export * from "./editorutils";
export * from "./mocks";
export * from "./waitutils";
7 changes: 7 additions & 0 deletions packages/test-utils/jest-css-workaround.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
process() {
return {
code: `module.exports = "";`,
};
}
};
1 change: 1 addition & 0 deletions packages/test-utils/jest-defaults.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default function jestDefaults(): any;
50 changes: 50 additions & 0 deletions packages/test-utils/jest-defaults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { join, resolve } from "path";
import { fileURLToPath } from 'url';

const testUtils = resolve(join(fileURLToPath(new URL('.', import.meta.url)), './'));
const serenityRoot = resolve(join(testUtils, "../../"));

export default () => ({
coveragePathIgnorePatterns: [
"<rootDir>/node_modules/",
"/src/Serenity.Assets/"
],
extensionsToTreatAsEsm: ['.ts', '.tsx'],
moduleNameMapper: {
"^@serenity-is/(.*)$": ["<rootDir>/node_modules/@serenity-is/$1", "<rootDir>/../node_modules/@serenity-is/$1", "<rootDir>/../../node_modules/@serenity-is/$1"]
},
setupFiles: [
`${testUtils}/jest-setup.js`,
],
setupFilesAfterEnv: [
`${testUtils}/jest-setup-afterenv.js`
],
testEnvironment: `${testUtils}/jsdom-global.js`,
testMatch: [
"<rootDir>/test/**/*.spec.ts*",
"<rootDir>/src/**/*.spec.ts*"
],
transform: {
'\\.css$': `${testUtils}/jest-css-workaround.cjs`,
"^.+\.(t|j)sx?$": [`${serenityRoot}/node_modules/@swc/jest`, {
jsc: {
parser: {
syntax: "typescript",
decorators: true,
tsx: true
},
keepClassNames: true,
transform: {
react: {
runtime: 'automatic',
importSource: 'jsx-dom'
}
}
},
module: {
type: "commonjs"
}
}]
},
transformIgnorePatterns: []
});
17 changes: 17 additions & 0 deletions packages/test-utils/jest-setup-afterenv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
if (Object["__definePropertyMocked__"] !== true) {
Object["__definePropertyMocked__"] = true;
const originalDefineProperty = Object.defineProperty;
const mutableDefineProperty = (obj, prop, attributes) => {
// this is to prevent the error `Cannot redefine property: prototype`; prototype can not be configurable...
if (prop === "prototype") return originalDefineProperty(obj, prop, attributes);
return originalDefineProperty(
obj,
prop,
{
configurable: true,
...attributes
}
);
}
Object.defineProperty = mutableDefineProperty;
}
23 changes: 23 additions & 0 deletions packages/test-utils/jest-setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
if (!process.env.LISTENING_TO_UNHANDLED_REJECTION) {
process.on('unhandledRejection', err => {
try {
if (!err || !err.reason)
return;

const reason = err.reason;
if (reason.origin == "serviceCall" ||
reason.origin == "test") {
err.preventDefault();

if (!reason.silent &&
(reason.kind ?? "exception") === "exception") {
console.error(err);
}
}
}
catch {
}
})
// Avoid memory leak by adding too many listeners
process.env.LISTENING_TO_UNHANDLED_REJECTION = true
}
105 changes: 105 additions & 0 deletions packages/test-utils/jsdom-global.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import pkg from "../../../Serenity/node_modules/jest-environment-jsdom/build/index.js";

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;
}
}
Loading

0 comments on commit b865908

Please sign in to comment.