journal-to-canvas-slideshow/scripts/tests/test-utils.js

303 lines
11 KiB
JavaScript

"use strict";
import { ArtTileManager } from "../classes/ArtTileManager.js";
import { HelperFunctions } from "../classes/HelperFunctions.js";
import { ImageDisplayManager } from "../classes/ImageDisplayManager.js";
export class TestUtils {
/**
* Dispatch a simulated event, for when the simple element.click() won't do
* @param {HTMLElement} element - the element we're toggling
* @param {*} eventInterface - the interface such as MouseEvent, ChangeEvent, KeyboardEvent
* @param {String} eventName - the name of the event, such as "mouseenter", "change", "keydown"
* @param {Object} options - object for extra options to pass to the event
* @param {Boolean} options.bubbles - whether the event bubbles
* @param {Boolean} options.ctrlKey - whether we should consider the ctrl key pressed or not
* @example
*
*/
static dispatchEvent(
element,
eventInterface,
eventName,
options = {
bubbles: true,
ctrlKey: false,
}
) {
element.dispatchEvent(new eventInterface(eventName, options));
}
static dispatchMouseEnter(element) {
element.dispatchEvent(
new MouseEvent("mouseenter", {
bubbles: true,
})
);
}
/**
* Simulate keypress
* @param {*} element
*/
static dispatchKeypress(element, keyCode) {
element.dispatchEvent(
new KeyboardEvent("keydown", { key: keyCode, bubbles: true })
);
}
/**
* Simulate clicks, especially those with Ctrl or other keys pressed
* @param {HTMLElement} element
*/
static dispatchMouseDown(element) {
element.dispatchEvent(
new MouseEvent("click", {
ctrlKey: true, // if you aren't going to use them.
bubbles: true,
metaKey: true, // these are here for example's sake.
})
);
}
/**
* Simulate a "change" event on an element
* @param {HTMLElement} element - the element we're simulatnig an event uppon
*/
static dispatchChange(element) {
// element.fireEvent("onchange");
const e = new Event("change", { bubbles: true });
element.dispatchEvent(e);
// element.dispatchEvent("onchange");
}
static async getTileObject(tileID, sceneID = "") {
let tileObject = await ArtTileManager.getTileObjectByID(tileID, sceneID);
return tileObject;
}
static async getDocData(document, property = "") {
let data = game.version >= 10 ? document : document.data;
if (property) {
return foundry.utils.getProperty(data, property);
} else {
return data;
}
}
static async resizeTile(tileDoc, scene) {
//give it random dimensions bigger than scene
let width = (await TestUtils.getDocData(scene, "width")) + 30;
let height = (await TestUtils.getDocData(scene, "height")) + 30;
let updateData = {
_id: tileDoc.id,
width,
height,
};
await scene.updateEmbeddedDocuments("Tile", [updateData]);
}
/**
* change the tile's image to a test image
*/
static async changeTileImage(tileID, url = "") {
if (!url)
url = "/modules/journal-to-canvas-slideshow/demo-images/pd19-20049_1.webp";
await ImageDisplayManager.updateTileObjectTexture(tileID, "", url, "anyScene");
}
static async getArtGallerySettings(nestedPropertyString = "") {
let settings = await HelperFunctions.getSettingValue(
"artGallerySettings",
nestedPropertyString
);
return settings;
}
/**
* returns the "Computed Styles" Object or a property within if specified
* @param {JQuery or HTMLElement} element - the element whose styles we're getting
* @param {String} selector - the selector of the element
* @param {String} property - the style property we want to return
* @returns the Object representing the computed styles, or a property within
*/
static returnComputedStyles(element, selector, property = "") {
if (element.jquery) {
element = element[0];
}
let selectedElement = element;
if (selector) selectedElement = element.querySelector(selector);
if (!property) return getComputedStyle(selectedElement);
else return getComputedStyle(selectedElement).getPropertyValue(property);
}
static returnClassListAsArray(element, selector) {
if (element.jquery) {
element = element[0];
}
return Array.from(element.querySelector(selector).classList);
}
static getDocIdFromApp(app) {
return app.document.id;
}
/**
* We want to test each of the qualifications for if a frame tile
* is properly linked to an art tile here
*
* @param {Object} frameTile - the frame tile
* @param {Object} artTile - the art tile
*/
static async testFitToFrame(frameTileID, artTileID) {
const TU = TestUtils;
let artTileDoc = await TU.getTileObject(artTileID);
let frameDoc = await TU.getTileObject(frameTileID);
//TODO - test if the art tile fits within the frame (tile or scene)
let areas = await TU.getAreasOfDocs(frameDoc, artTileDoc);
return areas;
//TODO - test if the Config UI Updates to show that this art tile now has the frame tile as its child
}
static async duplicateTestScene(sourceScene) {
// let dupedSceneData;
let dupedSceneData = sourceScene.clone({ name: "Test Scene" });
if (game.version < 10) {
dupedSceneData = {
...foundry.utils.duplicate(sourceScene),
_id: foundry.utils.randomID(),
name: "Test Scene",
};
}
let scene = await Scene.create(dupedSceneData);
await scene.activate();
await scene.view();
return scene;
}
static async initializeScene(name = "Display") {
let sourceScene = game.scenes.getName(name);
await sourceScene.view();
return sourceScene;
}
/**
* Get the auto-view or auto-activate settings of the dedicatedDisplayData property
* @param {String} sceneOrJournal - whether we want to access the scene or the journal sub-object
* @param {String} viewOrActivate - whether we want to get the view or activate property
*/
static async getAutoViewOrActivate(
sceneOrJournal = "scene",
viewOrActivate = "view"
) {
const key = `dedicatedDisplayData[${sceneOrJournal}].auto${viewOrActivate}`;
const current = await HelperFunctions.getSettingValue(`artGallerySettings`, key);
return { key, current };
}
/**
* Toggle the auto-view or auto-activate settings of the dedicatedDisplayData property
* @param {String} sceneOrJournal - whether we want to access the scene or the journal sub-object
* @param {String} viewOrActivate - whether we want to toggle the view or activate property
*/
static async toggleAutoViewOrActivate(...args) {
let { key, current } = await TestUtils.getAutoViewOrActivate(...args); //(sceneOrJournal, viewOrActivate)
// const key = `dedicatedDisplayData[${sceneOrJournal}].auto${viewOrActivate}`;
// const current = await HelperFunctions.getSettingValue(`artGallerySettings`, key);
await HelperFunctions.setSettingValue("artGallerySettings", key, !current);
}
static async clickGlobalButton(configElement, actionName) {
configElement[0]
.querySelector(`[data-action='globalActions.click.actions.${actionName}']`)
.click();
await quench.utils.pause(900);
}
/**
* @description - renders the Scene Config
*/
static async renderConfig() {
let configApp = new SlideshowConfig();
await configApp._render(true);
let configElement = configApp.element;
return { configApp, configElement };
}
static async getDefaultImageSrc(type = "art") {
let defaultImageSrc = await TestUtils.getArtGallerySettings(
`defaultTileImages.paths.${type}TilePath`
);
return defaultImageSrc;
}
static async clickActionButton(actionName, element, options = { quench }) {
const actionQueryString = combine(actionName);
await clickButton(element, actionQueryString, quench);
}
/**
* click a button, optionally one with a data-action attribute
* @param {HTMLElement} element - the element to click
* @param {Selector} selector - the selector of the button we want to find
* @param {Object} options - options object
* @param {Object} options.quench - the quench thing to pause the button
* @param {String} options.actionName - the individual action name
* @param {String} options.parentPath - the parent path to find the options' name
*/
static async clickButton(element, selector, options) {
const { quench, actionName, parentPath } = options;
let ourButton = element.querySelector(selector);
ourButton.click();
await quench.utils.pause(900);
}
static getChildElements(element, selector, multiple = false) {
if (element.jquery) {
element = element[0];
}
if (multiple) {
return Array.from(element.querySelectorAll(selector));
} else {
return element.querySelector(selector);
}
}
static getAppFromWindow(type, searchText = "") {
let windows = Object.values(ui.windows);
function predicate(w) {
let allTrue = false;
if (w instanceof type) {
if (!searchText) {
allTrue = true;
} else {
if (w.element && w.element.text().includes(searchText))
allTrue = true;
}
return allTrue;
}
}
return Object.values(ui.windows).filter(predicate)[0];
}
static checkAppElementForId(app, id) {
let elementId = app.element?.attr("id");
if (!app.element || elementId != id) {
return false;
} else {
return true;
}
}
static async deleteTestScene(scene) {
let dupedSceneId = scene.id;
await Scene.deleteDocuments([dupedSceneId]);
}
static async getDimensions(doc) {
let width = await TestUtils.getDocData(doc, "width");
let height = await TestUtils.getDocData(doc, "height");
return {
width,
height,
};
}
static async getAreasOfDocs(frameDoc, artTileDoc) {
const frameDimensions = await TestUtils.getDimensions(frameDoc);
const frameArea = frameDimensions.width * frameDimensions.height;
const artDimensions = await TestUtils.getDimensions(artTileDoc);
const artArea = artDimensions.width * artDimensions.height;
return { artArea, frameArea };
}
}