browserUtils.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /**
  2. * Utility functions for browser tests.
  3. *
  4. * @author n1474335 [n1474335@gmail.com]
  5. * @copyright Crown Copyright 2023
  6. * @license Apache-2.0
  7. */
  8. /** @function
  9. * Clears the recipe and input
  10. *
  11. * @param {Browser} browser - Nightwatch client
  12. */
  13. function clear(browser) {
  14. browser
  15. .useCss()
  16. .click("#clr-recipe")
  17. .click("#clr-io")
  18. .waitForElementNotPresent("#rec-list li.operation")
  19. .expect.element("#input-text .cm-content").text.that.equals("");
  20. }
  21. /** @function
  22. * Sets the input to the desired string
  23. *
  24. * @param {Browser} browser - Nightwatch client
  25. * @param {string} input - The text to populate the input with
  26. * @param {boolean} [type=true] - Whether to type the characters in by using sendKeys,
  27. * or to set the value of the editor directly (useful for special characters)
  28. */
  29. function setInput(browser, input, type=true) {
  30. clear(browser);
  31. if (type) {
  32. browser
  33. .useCss()
  34. .sendKeys("#input-text .cm-content", input)
  35. .pause(100);
  36. } else {
  37. browser.execute(text => {
  38. window.app.setInput(text);
  39. }, [input]);
  40. }
  41. }
  42. /** @function
  43. * Triggers a bake
  44. *
  45. * @param {Browser} browser - Nightwatch client
  46. */
  47. function bake(browser) {
  48. browser
  49. .click("#bake")
  50. .waitForElementNotVisible("#stale-indicator", 5000)
  51. .waitForElementNotVisible("#output-loader", 5000);
  52. }
  53. /** @function
  54. * Sets the character encoding in the input or output
  55. *
  56. * @param {Browser} browser - Nightwatch client
  57. * @param {string} io - Either "input" or "output"
  58. * @param {string} enc - The encoding to be set
  59. */
  60. function setChrEnc(browser, io, enc) {
  61. io = `#${io}-text`;
  62. browser
  63. .useCss()
  64. .click(io + " .chr-enc-value")
  65. .waitForElementVisible(io + " .chr-enc-select .cm-status-bar-select-scroll")
  66. .click("link text", enc)
  67. .waitForElementNotVisible(io + " .chr-enc-select .cm-status-bar-select-scroll")
  68. .expect.element(io + " .chr-enc-value").text.that.equals(enc);
  69. }
  70. /** @function
  71. * Sets the end of line sequence in the input or output
  72. *
  73. * @param {Browser} browser - Nightwatch client
  74. * @param {string} io - Either "input" or "output"
  75. * @param {string} eol - The sequence to set
  76. */
  77. function setEOLSeq(browser, io, eol) {
  78. io = `#${io}-text`;
  79. browser
  80. .useCss()
  81. .click(io + " .eol-value")
  82. .waitForElementVisible(io + " .eol-select .cm-status-bar-select-content")
  83. .click(`${io} .cm-status-bar-select-content a[data-val=${eol}]`)
  84. .waitForElementNotVisible(io + " .eol-select .cm-status-bar-select-content")
  85. .expect.element(io + " .eol-value").text.that.equals(eol);
  86. }
  87. /** @function
  88. * Copies whatever is currently selected
  89. *
  90. * @param {Browser} browser - Nightwatch client
  91. */
  92. function copy(browser) {
  93. browser.perform(function() {
  94. const actions = this.actions({async: true});
  95. // Ctrl + Ins used as this works on Windows, Linux and Mac
  96. return actions
  97. .keyDown(browser.Keys.CONTROL)
  98. .keyDown(browser.Keys.INSERT)
  99. .keyUp(browser.Keys.INSERT)
  100. .keyUp(browser.Keys.CONTROL);
  101. });
  102. }
  103. /** @function
  104. * Pastes into the target element
  105. *
  106. * @param {Browser} browser - Nightwatch client
  107. * @param {string} el - Target element selector
  108. */
  109. function paste(browser, el) {
  110. browser
  111. .click(el)
  112. .perform(function() {
  113. const actions = this.actions({async: true});
  114. // Shift + Ins used as this works on Windows, Linux and Mac
  115. return actions
  116. .keyDown(browser.Keys.SHIFT)
  117. .keyDown(browser.Keys.INSERT)
  118. .keyUp(browser.Keys.INSERT)
  119. .keyUp(browser.Keys.SHIFT);
  120. })
  121. .pause(100);
  122. }
  123. /** @function
  124. * Loads a recipe and input
  125. *
  126. * @param {Browser} browser - Nightwatch client
  127. * @param {string|Array<string>} opName - name of operation to be loaded, array for multiple ops
  128. * @param {string} input - input text for test
  129. * @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
  130. */
  131. function loadRecipe(browser, opName, input, args) {
  132. let recipeConfig;
  133. if (typeof(opName) === "string") {
  134. recipeConfig = JSON.stringify([{
  135. "op": opName,
  136. "args": args
  137. }]);
  138. } else if (opName instanceof Array) {
  139. recipeConfig = JSON.stringify(
  140. opName.map((op, i) => {
  141. return {
  142. op: op,
  143. args: args.length ? args[i] : []
  144. };
  145. })
  146. );
  147. } else {
  148. throw new Error("Invalid operation type. Must be string or array of strings. Received: " + typeof(opName));
  149. }
  150. clear(browser);
  151. setInput(browser, input, false);
  152. browser
  153. .urlHash("recipe=" + recipeConfig)
  154. .waitForElementPresent("#rec-list li.operation");
  155. }
  156. /** @function
  157. * Tests whether the output matches a given value
  158. *
  159. * @param {Browser} browser - Nightwatch client
  160. * @param {string|RegExp} expected - The expected output value
  161. */
  162. function expectOutput(browser, expected) {
  163. browser.execute(expected => {
  164. const output = window.app.manager.output.outputEditorView.state.doc.toString();
  165. if (expected instanceof RegExp) {
  166. return expected.test(output);
  167. } else {
  168. return expected === output;
  169. }
  170. }, [expected]);
  171. }
  172. /** @function
  173. * Uploads a file using the #open-file input
  174. *
  175. * @param {Browser} browser - Nightwatch client
  176. * @param {string} filename - A path to a file in the samples directory
  177. */
  178. function uploadFile(browser, filename) {
  179. const filepath = require("path").resolve(__dirname + "/../samples/" + filename);
  180. // The file input cannot be interacted with by nightwatch while it is hidden,
  181. // so we temporarily expose it for the purposes of this test.
  182. browser.execute(() => {
  183. document.getElementById("open-file").style.display = "block";
  184. });
  185. browser
  186. .pause(100)
  187. .setValue("#open-file", filepath)
  188. .pause(100);
  189. browser.execute(() => {
  190. document.getElementById("open-file").style.display = "none";
  191. });
  192. browser.waitForElementVisible("#input-text .cm-file-details");
  193. }
  194. /** @function
  195. * Uploads a folder using the #open-folder input
  196. *
  197. * @param {Browser} browser - Nightwatch client
  198. * @param {string} foldername - A path to a folder in the samples directory
  199. */
  200. function uploadFolder(browser, foldername) {
  201. const folderpath = require("path").resolve(__dirname + "/../samples/" + foldername);
  202. // The folder input cannot be interacted with by nightwatch while it is hidden,
  203. // so we temporarily expose it for the purposes of this test.
  204. browser.execute(() => {
  205. document.getElementById("open-folder").style.display = "block";
  206. });
  207. browser
  208. .pause(100)
  209. .setValue("#open-folder", folderpath)
  210. .pause(500);
  211. browser.execute(() => {
  212. document.getElementById("open-folder").style.display = "none";
  213. });
  214. browser.waitForElementVisible("#input-text .cm-file-details");
  215. }
  216. module.exports = {
  217. clear: clear,
  218. setInput: setInput,
  219. bake: bake,
  220. setChrEnc: setChrEnc,
  221. setEOLSeq: setEOLSeq,
  222. copy: copy,
  223. paste: paste,
  224. loadRecipe: loadRecipe,
  225. expectOutput: expectOutput,
  226. uploadFile: uploadFile,
  227. uploadFolder: uploadFolder
  228. };