00_nightwatch.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /**
  2. * Tests to ensure that the app loads correctly in a reasonable time and that operations can be run.
  3. *
  4. * @author n1474335 [n1474335@gmail.com]
  5. * @copyright Crown Copyright 2018
  6. * @license Apache-2.0
  7. */
  8. module.exports = {
  9. before: browser => {
  10. browser
  11. .resizeWindow(1280, 800)
  12. .url(browser.launchUrl);
  13. },
  14. "Loading screen": browser => {
  15. // Check that the loading screen appears and then disappears within a reasonable time
  16. browser
  17. .waitForElementVisible("#preloader", 300)
  18. .waitForElementNotPresent("#preloader", 10000);
  19. },
  20. "App loaded": browser => {
  21. browser.useCss();
  22. // Check that various important elements are loaded
  23. browser.expect.element("#operations").to.be.visible;
  24. browser.expect.element("#recipe").to.be.visible;
  25. browser.expect.element("#input").to.be.present;
  26. browser.expect.element("#output").to.be.present;
  27. browser.expect.element(".op-list").to.be.present;
  28. browser.expect.element("#rec-list").to.be.visible;
  29. browser.expect.element("#controls").to.be.visible;
  30. browser.expect.element("#input-text").to.be.visible;
  31. browser.expect.element("#output-text").to.be.visible;
  32. },
  33. "Operations loaded": browser => {
  34. browser.useXpath();
  35. // Check that an operation in every category has been populated
  36. browser.expect.element("//li[contains(@class, 'operation') and text()='To Base64']").to.be.present;
  37. browser.expect.element("//li[contains(@class, 'operation') and text()='To Binary']").to.be.present;
  38. browser.expect.element("//li[contains(@class, 'operation') and text()='AES Decrypt']").to.be.present;
  39. browser.expect.element("//li[contains(@class, 'operation') and text()='PEM to Hex']").to.be.present;
  40. browser.expect.element("//li[contains(@class, 'operation') and text()='Power Set']").to.be.present;
  41. browser.expect.element("//li[contains(@class, 'operation') and text()='Parse IP range']").to.be.present;
  42. browser.expect.element("//li[contains(@class, 'operation') and text()='Remove Diacritics']").to.be.present;
  43. browser.expect.element("//li[contains(@class, 'operation') and text()='Sort']").to.be.present;
  44. browser.expect.element("//li[contains(@class, 'operation') and text()='To UNIX Timestamp']").to.be.present;
  45. browser.expect.element("//li[contains(@class, 'operation') and text()='Extract dates']").to.be.present;
  46. browser.expect.element("//li[contains(@class, 'operation') and text()='Gzip']").to.be.present;
  47. browser.expect.element("//li[contains(@class, 'operation') and text()='Keccak']").to.be.present;
  48. browser.expect.element("//li[contains(@class, 'operation') and text()='JSON Beautify']").to.be.present;
  49. browser.expect.element("//li[contains(@class, 'operation') and text()='Detect File Type']").to.be.present;
  50. browser.expect.element("//li[contains(@class, 'operation') and text()='Play Media']").to.be.present;
  51. browser.expect.element("//li[contains(@class, 'operation') and text()='Disassemble x86']").to.be.present;
  52. browser.expect.element("//li[contains(@class, 'operation') and text()='Register']").to.be.present;
  53. },
  54. "Recipe can be run": browser => {
  55. const toHex = "//li[contains(@class, 'operation') and text()='To Hex']";
  56. const op = "#rec-list .operation .op-title";
  57. // Check that operation is visible
  58. browser
  59. .useXpath()
  60. .expect.element(toHex).to.be.visible;
  61. // Add it to the recipe by double clicking
  62. browser
  63. .useXpath()
  64. .moveToElement(toHex, 10, 10)
  65. .useCss()
  66. .waitForElementVisible(".popover-body", 1000)
  67. .doubleClick("xpath", toHex);
  68. // Confirm that it has been added to the recipe
  69. browser
  70. .useCss()
  71. .waitForElementVisible(op, 100)
  72. .expect.element(op).text.to.contain("To Hex");
  73. // Enter input
  74. browser
  75. .useCss()
  76. .sendKeys("#input-text .cm-content", "Don't Panic.")
  77. .pause(1000)
  78. .click("#bake");
  79. // Check output
  80. browser
  81. .useCss()
  82. .waitForElementNotVisible("#stale-indicator", 1000)
  83. .expect.element("#output-text .cm-content").text.that.equals("44 6f 6e 27 74 20 50 61 6e 69 63 2e");
  84. // Clear recipe
  85. browser
  86. .useCss()
  87. .moveToElement(op, 10, 10)
  88. .waitForElementNotPresent(".popover-body", 1000)
  89. .click("#clr-recipe")
  90. .waitForElementNotPresent(op);
  91. },
  92. "Test every module": browser => {
  93. browser.useCss();
  94. // BSON
  95. loadOp("BSON deserialise", browser)
  96. .waitForElementNotVisible("#output-loader", 5000);
  97. // Charts
  98. loadOp("Entropy", browser)
  99. .waitForElementNotVisible("#output-loader", 5000);
  100. // Ciphers
  101. loadOp("AES Encrypt", browser)
  102. .waitForElementNotVisible("#output-loader", 5000);
  103. // Code
  104. loadOp("XPath expression", browser)
  105. .waitForElementNotVisible("#output-loader", 5000);
  106. // Compression
  107. loadOp("Gzip", browser)
  108. .waitForElementNotVisible("#output-loader", 5000);
  109. // Crypto
  110. loadOp("MD5", browser)
  111. .waitForElementNotVisible("#output-loader", 5000);
  112. // Default
  113. loadOp("Fork", browser)
  114. .waitForElementNotVisible("#output-loader", 5000);
  115. // Diff
  116. loadOp("Diff", browser)
  117. .waitForElementNotVisible("#output-loader", 5000);
  118. // Encodings
  119. loadOp("Encode text", browser)
  120. .waitForElementNotVisible("#output-loader", 5000);
  121. // Hashing
  122. loadOp("Streebog", browser)
  123. .waitForElementNotVisible("#output-loader", 5000);
  124. // Image
  125. loadOp("Extract EXIF", browser)
  126. .waitForElementNotVisible("#output-loader", 5000);
  127. // PGP
  128. loadOp("PGP Encrypt", browser)
  129. .waitForElementNotVisible("#output-loader", 5000);
  130. // PublicKey
  131. loadOp("Hex to PEM", browser)
  132. .waitForElementNotVisible("#output-loader", 5000);
  133. // Regex
  134. loadOp("Strings", browser)
  135. .waitForElementNotVisible("#output-loader", 5000);
  136. // Shellcode
  137. loadOp("Disassemble x86", browser)
  138. .waitForElementNotVisible("#output-loader", 5000);
  139. // URL
  140. loadOp("URL Encode", browser)
  141. .waitForElementNotVisible("#output-loader", 5000);
  142. // UserAgent
  143. loadOp("Parse User Agent", browser)
  144. .waitForElementNotVisible("#output-loader", 5000);
  145. // YARA
  146. loadOp("YARA Rules", browser)
  147. .waitForElementNotVisible("#output-loader", 5000);
  148. browser.click("#clr-recipe");
  149. },
  150. "Move around the UI": browser => {
  151. const otherCat = "//a[contains(@class, 'category-title') and contains(@data-target, '#catOther')]",
  152. genUUID = "//li[contains(@class, 'operation') and text()='Generate UUID']";
  153. browser.useXpath();
  154. // Scroll to a lower category
  155. browser
  156. .getLocationInView(otherCat)
  157. .expect.element(otherCat).to.be.visible;
  158. // Open category
  159. browser
  160. .click(otherCat)
  161. .expect.element(genUUID).to.be.visible;
  162. // Add op to recipe
  163. /* mouseButtonUp drops wherever the actual cursor is, not necessarily in the right place,
  164. so we can't test Sortable.js properly using Nightwatch. html-dnd doesn't work either.
  165. Instead of relying on drag and drop, we double click on the op to load it. */
  166. browser
  167. .getLocationInView(genUUID)
  168. .moveToElement(genUUID, 10, 10)
  169. .doubleClick("xpath", genUUID)
  170. .useCss()
  171. .waitForElementVisible(".operation .op-title", 1000)
  172. .waitForElementNotVisible("#stale-indicator", 1000)
  173. .expect.element("#output-text .cm-content").text.which.matches(/[\da-f-]{36}/);
  174. browser.click("#clr-recipe");
  175. },
  176. "Search": browser => {
  177. // Search for an op
  178. browser
  179. .useCss()
  180. .clearValue("#search")
  181. .setValue("#search", "md5")
  182. .useXpath()
  183. .waitForElementVisible("//ul[@id='search-results']//b[text()='MD5']", 1000);
  184. },
  185. after: browser => {
  186. browser.end();
  187. }
  188. };
  189. /**
  190. * Clears the current recipe and loads a new operation.
  191. *
  192. * @param {string} opName
  193. * @param {Browser} browser
  194. */
  195. function loadOp(opName, browser) {
  196. return browser
  197. .useCss()
  198. .click("#clr-recipe")
  199. .urlHash("op=" + opName);
  200. }