/** * Utility functions for browser tests. * * @author n1474335 [n1474335@gmail.com] * @copyright Crown Copyright 2023 * @license Apache-2.0 */ /** @function * Clears the recipe and input * * @param {Browser} browser - Nightwatch client */ function clear(browser) { browser .useCss() .click("#clr-recipe") .click("#clr-io") .waitForElementNotPresent("#rec-list li.operation") .expect.element("#input-text .cm-content").text.that.equals(""); } /** @function * Sets the input to the desired string * * @param {Browser} browser - Nightwatch client * @param {string} input - The text to populate the input with * @param {boolean} [type=true] - Whether to type the characters in by using sendKeys, * or to set the value of the editor directly (useful for special characters) */ function setInput(browser, input, type=true) { clear(browser); if (type) { browser .useCss() .sendKeys("#input-text .cm-content", input) .pause(100); } else { browser.execute(text => { window.app.setInput(text); }, [input]); } } /** @function * Triggers a bake * * @param {Browser} browser - Nightwatch client */ function bake(browser) { browser .click("#bake") .waitForElementNotVisible("#stale-indicator", 5000) .waitForElementNotVisible("#output-loader", 5000); } /** @function * Sets the character encoding in the input or output * * @param {Browser} browser - Nightwatch client * @param {string} io - Either "input" or "output" * @param {string} enc - The encoding to be set */ function setChrEnc(browser, io, enc) { io = `#${io}-text`; browser .useCss() .waitForElementNotVisible("#snackbar-container", 6000) .click(io + " .chr-enc-value") .waitForElementVisible(io + " .chr-enc-select .cm-status-bar-select-scroll") .click("link text", enc) .waitForElementNotVisible(io + " .chr-enc-select .cm-status-bar-select-scroll") .expect.element(io + " .chr-enc-value").text.that.equals(enc); } /** @function * Sets the end of line sequence in the input or output * * @param {Browser} browser - Nightwatch client * @param {string} io - Either "input" or "output" * @param {string} eol - The sequence to set */ function setEOLSeq(browser, io, eol) { io = `#${io}-text`; browser .useCss() .waitForElementNotVisible("#snackbar-container", 6000) .click(io + " .eol-value") .waitForElementVisible(io + " .eol-select .cm-status-bar-select-content") .click(`${io} .cm-status-bar-select-content a[data-val=${eol}]`) .waitForElementNotVisible(io + " .eol-select .cm-status-bar-select-content") .expect.element(io + " .eol-value").text.that.equals(eol); } /** @function * Copies whatever is currently selected * * @param {Browser} browser - Nightwatch client */ function copy(browser) { browser.perform(function() { const actions = this.actions({async: true}); // Ctrl + Ins used as this works on Windows, Linux and Mac return actions .keyDown(browser.Keys.CONTROL) .keyDown(browser.Keys.INSERT) .keyUp(browser.Keys.INSERT) .keyUp(browser.Keys.CONTROL); }); } /** @function * Pastes into the target element * * @param {Browser} browser - Nightwatch client * @param {string} el - Target element selector */ function paste(browser, el) { browser .click(el) .perform(function() { const actions = this.actions({async: true}); // Shift + Ins used as this works on Windows, Linux and Mac return actions .keyDown(browser.Keys.SHIFT) .keyDown(browser.Keys.INSERT) .keyUp(browser.Keys.INSERT) .keyUp(browser.Keys.SHIFT); }) .pause(100); } /** @function * Loads a recipe and input * * @param {Browser} browser - Nightwatch client * @param {string|Array} opName - name of operation to be loaded, array for multiple ops * @param {string} input - input text for test * @param {Array|Array>} args - arguments, nested if multiple ops */ function loadRecipe(browser, opName, input, args) { let recipeConfig; if (typeof(opName) === "string") { recipeConfig = JSON.stringify([{ "op": opName, "args": args }]); } else if (opName instanceof Array) { recipeConfig = JSON.stringify( opName.map((op, i) => { return { op: op, args: args.length ? args[i] : [] }; }) ); } else { throw new Error("Invalid operation type. Must be string or array of strings. Received: " + typeof(opName)); } clear(browser); setInput(browser, input, false); browser .urlHash("recipe=" + recipeConfig) .waitForElementPresent("#rec-list li.operation"); } /** @function * Tests whether the output matches a given value * * @param {Browser} browser - Nightwatch client * @param {string|RegExp} expected - The expected output value */ function expectOutput(browser, expected) { browser.execute(expected => { const output = window.app.manager.output.outputEditorView.state.doc.toString(); if (expected instanceof RegExp) { return expected.test(output); } else { return expected === output; } }, [expected]); } /** @function * Uploads a file using the #open-file input * * @param {Browser} browser - Nightwatch client * @param {string} filename - A path to a file in the samples directory */ function uploadFile(browser, filename) { const filepath = require("path").resolve(__dirname + "/../samples/" + filename); // The file input cannot be interacted with by nightwatch while it is hidden, // so we temporarily expose it for the purposes of this test. browser.execute(() => { document.getElementById("open-file").style.display = "block"; }); browser .pause(100) .setValue("#open-file", filepath) .pause(100); browser.execute(() => { document.getElementById("open-file").style.display = "none"; }); browser.waitForElementVisible("#input-text .cm-file-details"); } /** @function * Uploads a folder using the #open-folder input * * @param {Browser} browser - Nightwatch client * @param {string} foldername - A path to a folder in the samples directory */ function uploadFolder(browser, foldername) { const folderpath = require("path").resolve(__dirname + "/../samples/" + foldername); // The folder input cannot be interacted with by nightwatch while it is hidden, // so we temporarily expose it for the purposes of this test. browser.execute(() => { document.getElementById("open-folder").style.display = "block"; }); browser .pause(100) .setValue("#open-folder", folderpath) .pause(500); browser.execute(() => { document.getElementById("open-folder").style.display = "none"; }); browser.waitForElementVisible("#input-text .cm-file-details"); } module.exports = { clear: clear, setInput: setInput, bake: bake, setChrEnc: setChrEnc, setEOLSeq: setEOLSeq, copy: copy, paste: paste, loadRecipe: loadRecipe, expectOutput: expectOutput, uploadFile: uploadFile, uploadFolder: uploadFolder };