add local storage availability check, prep for code review

This commit is contained in:
Robin Scholtes 2023-05-12 14:47:45 +12:00
parent 5b25b74775
commit 02a4dd5bd3
9 changed files with 39 additions and 261 deletions

View file

@ -68,8 +68,8 @@ class HTMLOperation {
html += "<i class='material-icons check-icon op-icon'>check</i>";
}
// 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 += `<i title="${this.name}" class='material-icons icon-add-favourite star-icon op-icon ${isFavourite ? "fav-op" : ""}'>

View file

@ -0,0 +1 @@
actual mobile device tests go here

View file

@ -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;

View file

@ -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,

View file

@ -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 = {

View file

@ -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<string>} opName - name of operation to be loaded, array for multiple ops
* @param {string} input - input text for test
* @param {Array<string>|Array<Array<string>>} 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
};