diff --git a/src/web/HTMLOperation.mjs b/src/web/HTMLOperation.mjs index 36b11519..820dd396 100755 --- a/src/web/HTMLOperation.mjs +++ b/src/web/HTMLOperation.mjs @@ -68,8 +68,8 @@ class HTMLOperation { html += "check"; } - // check if local storage has favourites at all - const isFavourite = localStorage.favourites?.includes(this.name) + // check if local storage is available *and* has favourites at all ( otherwise we use the default favs ) + const isFavourite = this.app.isLocalStorageAvailable() && localStorage.favourites?.includes(this.name); if (window.innerWidth < this.app.breakpoint) { html += ` diff --git a/tests/browser/00_nightwatch.js b/tests/browser/desktop-ui/00_nightwatch.js similarity index 100% rename from tests/browser/00_nightwatch.js rename to tests/browser/desktop-ui/00_nightwatch.js diff --git a/tests/browser/01_io.js b/tests/browser/desktop-ui/01_io.js similarity index 100% rename from tests/browser/01_io.js rename to tests/browser/desktop-ui/01_io.js diff --git a/tests/browser/02_ops.js b/tests/browser/desktop-ui/02_ops.js similarity index 100% rename from tests/browser/02_ops.js rename to tests/browser/desktop-ui/02_ops.js diff --git a/tests/browser/mobile-device/TODO.md b/tests/browser/mobile-device/TODO.md new file mode 100644 index 00000000..0f04e744 --- /dev/null +++ b/tests/browser/mobile-device/TODO.md @@ -0,0 +1 @@ +actual mobile device tests go here diff --git a/tests/browser/mobile/00_nightwatch.js b/tests/browser/mobile-ui/00_nightwatch.js similarity index 94% rename from tests/browser/mobile/00_nightwatch.js rename to tests/browser/mobile-ui/00_nightwatch.js index bfec3af8..3ba2a865 100644 --- a/tests/browser/mobile/00_nightwatch.js +++ b/tests/browser/mobile-ui/00_nightwatch.js @@ -1,9 +1,17 @@ +/** + * Tests to ensure that the app loads correctly in a reasonable time and that operations can be run. + * + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2018 + * @license Apache-2.0 + */ + const utils = require("./browserUtils.js"); module.exports = { before: browser => { browser - .resizeWindow(412, 915) // Galaxy S20 Ultra-ish size + .resizeWindow(1280, 800) .url(browser.launchUrl); }, @@ -11,33 +19,25 @@ module.exports = { // Check that the loading screen appears and then disappears within a reasonable time browser .waitForElementVisible("#preloader", 300) - .waitForElementNotPresent("#preloader", 30000); + .waitForElementNotPresent("#preloader", 10000); }, "App loaded": browser => { browser.useCss(); // Check that various important elements are loaded browser.expect.element("#operations").to.be.visible; - browser.expect.element("#search").to.be.visible; browser.expect.element("#recipe").to.be.visible; browser.expect.element("#input").to.be.present; browser.expect.element("#output").to.be.present; + browser.expect.element(".op-list").to.be.present; browser.expect.element("#rec-list").to.be.visible; browser.expect.element("#controls").to.be.visible; browser.expect.element("#input-text").to.be.visible; browser.expect.element("#output-text").to.be.visible; }, - // "Operations dropdown loaded": browser => { - // browser - // .useCss() - // .click("#search") - // .expect.element("#operations-dropdown").to.be.visible - // .expect.element("#categories").to.be.visible - // .expect.element(".op-list").to.be.present; - // }, - "Operations loaded": browser => { + browser.useXpath(); // Check that an operation in every category has been populated browser.expect.element("//li[contains(@class, 'operation') and text()='To Base64']").to.be.present; browser.expect.element("//li[contains(@class, 'operation') and text()='To Binary']").to.be.present; diff --git a/tests/browser/mobile/01_io.js b/tests/browser/mobile-ui/01_io.js similarity index 99% rename from tests/browser/mobile/01_io.js rename to tests/browser/mobile-ui/01_io.js index a3715e16..67d1fdff 100644 --- a/tests/browser/mobile/01_io.js +++ b/tests/browser/mobile-ui/01_io.js @@ -1,3 +1,12 @@ +/** + * Tests for input and output of various types to ensure the editors work as expected + * and retain data integrity, especially when it comes to special characters. + * + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ + // import { // clear, // utils.setInput, diff --git a/tests/browser/mobile/02_ops.js b/tests/browser/mobile-ui/02_ops.js similarity index 98% rename from tests/browser/mobile/02_ops.js rename to tests/browser/mobile-ui/02_ops.js index f7e447c2..e2c8a219 100644 --- a/tests/browser/mobile/02_ops.js +++ b/tests/browser/mobile-ui/02_ops.js @@ -1,3 +1,18 @@ +/** + * Tests for operations. + * The primary purpose for these test is to ensure that the operations + * output something vaguely expected (i.e. they aren't completely broken + * after a dependency update or changes to the UI), rather than to confirm + * that this output is actually accurate. Accuracy of output and testing + * of edge cases should be carried out in the operations test suite found + * in /tests/operations as this is much faster and easier to configure + * than the UI tests found here. + * + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2021 + * @license Apache-2.0 + */ + const utils = require("./browserUtils.js"); module.exports = { diff --git a/tests/browser/mobile/browserUtils.js b/tests/browser/mobile/browserUtils.js deleted file mode 100644 index b73dca91..00000000 --- a/tests/browser/mobile/browserUtils.js +++ /dev/null @@ -1,247 +0,0 @@ -/** - * 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() - .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() - .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 -};