/** * 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(1280, 800).url(browser.launchUrl); }, "Loading screen": (browser) => { // Check that the loading screen appears and then disappears within a reasonable time browser .waitForElementVisible("#preloader", 300) .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("#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 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; browser.expect.element( "//li[contains(@class, 'operation') and text()='AES Decrypt']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='PEM to Hex']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Power Set']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Parse IP range']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Remove Diacritics']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Sort']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='To UNIX Timestamp']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Extract dates']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Gzip']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Keccak']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='JSON Beautify']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Detect File Type']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Play Media']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Disassemble x86']", ).to.be.present; browser.expect.element( "//li[contains(@class, 'operation') and text()='Register']", ).to.be.present; }, "Recipe can be run": (browser) => { const toHex = "//li[contains(@class, 'operation') and text()='To Hex']"; const op = "#rec-list .operation .op-title"; // Check that operation is visible browser.useXpath().expect.element(toHex).to.be.visible; // Add it to the recipe by double clicking browser .useXpath() .moveToElement(toHex, 10, 10) .useCss() .waitForElementVisible(".popover-body", 1000) .doubleClick("xpath", toHex); // Confirm that it has been added to the recipe browser .useCss() .waitForElementVisible(op, 100) .expect.element(op) .text.to.contain("To Hex"); // Enter input browser .useCss() .sendKeys("#input-text .cm-content", "Don't Panic.") .pause(1000) .click("#bake"); // Check output browser .useCss() .waitForElementNotVisible("#stale-indicator", 1000) .expect.element("#output-text .cm-content") .text.that.equals("44 6f 6e 27 74 20 50 61 6e 69 63 2e"); // Clear recipe browser .useCss() .moveToElement(op, 10, 10) .waitForElementNotPresent(".popover-body", 1000) .click("#clr-recipe") .waitForElementNotPresent(op); }, "Test every module": (browser) => { browser.useCss(); // BSON loadOp("BSON deserialise", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Charts loadOp("Entropy", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Ciphers loadOp("AES Encrypt", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Code loadOp("XPath expression", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Compression loadOp("Gzip", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Crypto loadOp("MD5", browser).waitForElementNotVisible("#output-loader", 5000); // Default loadOp("Fork", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Diff loadOp("Diff", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Encodings loadOp("Encode text", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Hashing loadOp("Streebog", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Image loadOp("Extract EXIF", browser).waitForElementNotVisible( "#output-loader", 5000, ); // PGP loadOp("PGP Encrypt", browser).waitForElementNotVisible( "#output-loader", 5000, ); // PublicKey loadOp("Hex to PEM", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Regex loadOp("Strings", browser).waitForElementNotVisible( "#output-loader", 5000, ); // Shellcode loadOp("Disassemble x86", browser).waitForElementNotVisible( "#output-loader", 5000, ); // URL loadOp("URL Encode", browser).waitForElementNotVisible( "#output-loader", 5000, ); // UserAgent loadOp("Parse User Agent", browser).waitForElementNotVisible( "#output-loader", 5000, ); // YARA loadOp("YARA Rules", browser).waitForElementNotVisible( "#output-loader", 5000, ); browser.click("#clr-recipe"); }, "Move around the UI": (browser) => { const otherCat = "//a[contains(@class, 'category-title') and contains(@data-target, '#catOther')]", genUUID = "//li[contains(@class, 'operation') and text()='Generate UUID']"; browser.useXpath(); // Scroll to a lower category browser.getLocationInView(otherCat).expect.element(otherCat).to.be .visible; // Open category browser.click(otherCat).expect.element(genUUID).to.be.visible; // Add op to recipe /* mouseButtonUp drops wherever the actual cursor is, not necessarily in the right place, so we can't test Sortable.js properly using Nightwatch. html-dnd doesn't work either. Instead of relying on drag and drop, we double click on the op to load it. */ browser .getLocationInView(genUUID) .moveToElement(genUUID, 10, 10) .doubleClick("xpath", genUUID) .useCss() .waitForElementVisible(".operation .op-title", 1000) .waitForElementNotVisible("#stale-indicator", 1000) .expect.element("#output-text .cm-content") .text.which.matches(/[\da-f-]{36}/); browser.click("#clr-recipe"); }, Search: (browser) => { // Search for an op browser .useCss() .clearValue("#search") .setValue("#search", "md5") .useXpath() .waitForElementVisible( "//ul[@id='search-results']//b[text()='MD5']", 1000, ); }, "Alert bar": (browser) => { // Bake nothing to create an empty output which can be copied utils.clear(browser); utils.bake(browser); // Alert bar shows and contains correct content browser .click("#copy-output") .waitForElementVisible("#snackbar-container") .waitForElementVisible("#snackbar-container .snackbar-content") .expect.element("#snackbar-container .snackbar-content") .text.to.equal("Copied raw output successfully."); // Alert bar disappears after the correct amount of time // Should disappear after 2000ms browser .waitForElementNotPresent( "#snackbar-container .snackbar-content", 2500, ) .waitForElementNotVisible("#snackbar-container"); }, after: (browser) => { browser.end(); }, }; /** * Clears the current recipe and loads a new operation. * * @param {string} opName * @param {Browser} browser */ function loadOp(opName, browser) { return browser .useCss() .click("#clr-recipe") .urlHash("op=" + opName); }