suggestionsBrowserKey.mjs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. import { describe, it, before, after } from 'mocha'
  2. import { expect } from 'chai'
  3. import { By, Condition } from 'selenium-webdriver'
  4. import {
  5. DEFAULT_UI_WAIT_MS,
  6. argumentFieldChoicesId,
  7. argumentFieldId,
  8. getRootAndWait,
  9. getActionButton,
  10. takeScreenshotOnFailure,
  11. waitForDashboardLoaded,
  12. waitForLogsPage,
  13. waitForArgumentFormPage,
  14. waitForArgumentFormReady,
  15. waitForExecutionComplete,
  16. } from '../../lib/elements.js'
  17. async function clickBackFromLogsPage() {
  18. const goBackButtons = await webdriver.findElements(By.css('button[title="Go back"]'))
  19. if (goBackButtons.length > 0) {
  20. await goBackButtons[0].click()
  21. return 'history'
  22. }
  23. const dashboardBackButtons = await webdriver.findElements(By.css('button[title^="Back to "]'))
  24. if (dashboardBackButtons.length > 0) {
  25. await dashboardBackButtons[0].click()
  26. return 'dashboard'
  27. }
  28. throw new Error('No back button found on execution logs page')
  29. }
  30. async function ensureOnDashboard() {
  31. let url = await webdriver.getCurrentUrl()
  32. if (url.includes('/logs/')) {
  33. const backType = await clickBackFromLogsPage()
  34. if (backType === 'history') {
  35. await webdriver.wait(
  36. new Condition('wait for argument form after logs back', async () => {
  37. const currentUrl = await webdriver.getCurrentUrl()
  38. return currentUrl.includes('/argumentForm')
  39. }),
  40. DEFAULT_UI_WAIT_MS
  41. )
  42. url = await webdriver.getCurrentUrl()
  43. } else {
  44. await waitForDashboardLoaded()
  45. url = await webdriver.getCurrentUrl()
  46. }
  47. }
  48. if (url.includes('/argumentForm')) {
  49. const cancelButton = await webdriver.findElement(By.css('button[name="cancel"]'))
  50. await cancelButton.click()
  51. await waitForDashboardLoaded()
  52. }
  53. const actionButtons = await webdriver.findElements(By.css('[title="Test suggestionsBrowserKey"]'))
  54. if (actionButtons.length === 1) {
  55. return
  56. }
  57. await getRootAndWait()
  58. }
  59. async function openArgumentForm() {
  60. await ensureOnDashboard()
  61. const btn = await getActionButton(webdriver, 'Test suggestionsBrowserKey')
  62. await btn.click()
  63. await waitForArgumentFormPage()
  64. await waitForArgumentFormReady()
  65. }
  66. async function getTestInput() {
  67. return await webdriver.findElement(By.id(argumentFieldId('testInput')))
  68. }
  69. async function getTestInput2() {
  70. return await webdriver.findElement(By.id(argumentFieldId('testInput2')))
  71. }
  72. async function getDatalistOptions(inputName = 'testInput') {
  73. return await webdriver.findElements(By.css(`datalist#${argumentFieldChoicesId(inputName)} option`))
  74. }
  75. async function submitForm() {
  76. const submitButton = await webdriver.findElement(By.css('button[name="start"]'))
  77. await submitButton.click()
  78. }
  79. async function getLocalStorageItem(key) {
  80. return await webdriver.executeScript(`return localStorage.getItem('${key}')`)
  81. }
  82. async function clearLocalStorage() {
  83. await webdriver.executeScript('return localStorage.clear()')
  84. }
  85. describe('config: suggestionsBrowserKey', function () {
  86. before(async function () {
  87. await runner.start('suggestionsBrowserKey')
  88. await getRootAndWait()
  89. })
  90. after(async () => {
  91. await runner.stop()
  92. })
  93. afterEach(function () {
  94. takeScreenshotOnFailure(this.currentTest, webdriver)
  95. })
  96. it('Input fields with suggestionsBrowserKey are rendered', async function () {
  97. await openArgumentForm()
  98. const input1 = await getTestInput()
  99. expect(await input1.getTagName()).to.equal('input')
  100. expect(await input1.getAttribute('type')).to.equal('text')
  101. const label1 = await webdriver.findElement(By.css(`label[for="${argumentFieldId('testInput')}"]`))
  102. expect(await label1.getText()).to.contain('Test Input')
  103. const input2 = await getTestInput2()
  104. expect(await input2.getTagName()).to.equal('input')
  105. expect(await input2.getAttribute('type')).to.equal('text')
  106. const label2 = await webdriver.findElement(By.css(`label[for="${argumentFieldId('testInput2')}"]`))
  107. expect(await label2.getText()).to.contain('Test Input 2')
  108. })
  109. it('Submitting form saves value to localStorage', async function () {
  110. await clearLocalStorage()
  111. await openArgumentForm()
  112. const input = await getTestInput()
  113. // Use default argument type "ascii" (alphanumeric only) so tests pass when
  114. // config does not set a looser type (e.g. CI merge base without type lines).
  115. const testValue = 'testvalue123'
  116. await input.clear()
  117. await input.sendKeys(testValue)
  118. await submitForm()
  119. await waitForLogsPage()
  120. await waitForExecutionComplete()
  121. const stored = await getLocalStorageItem('olivetin-suggestions-test-suggestions-key')
  122. expect(stored).to.not.be.null
  123. const suggestions = JSON.parse(stored)
  124. expect(suggestions).to.be.an('array')
  125. expect(suggestions).to.include(testValue)
  126. })
  127. it('Previously saved values appear in datalist', async function () {
  128. const testValue = 'savedsuggestion456'
  129. await webdriver.executeScript(`
  130. const key = 'olivetin-suggestions-test-suggestions-key';
  131. localStorage.setItem(key, JSON.stringify(['${testValue}']));
  132. `)
  133. await openArgumentForm()
  134. const datalist = await webdriver.findElement(By.id(argumentFieldChoicesId('testInput')))
  135. expect(datalist).to.not.be.null
  136. const options = await getDatalistOptions()
  137. expect(options.length).to.be.greaterThan(0)
  138. let foundValue = false
  139. for (const option of options) {
  140. const value = await option.getAttribute('value')
  141. if (value === testValue) {
  142. foundValue = true
  143. break
  144. }
  145. }
  146. expect(foundValue).to.be.true
  147. })
  148. it('Multiple submissions accumulate suggestions', async function () {
  149. await clearLocalStorage()
  150. await openArgumentForm()
  151. const input1 = await getTestInput()
  152. await input1.clear()
  153. await input1.sendKeys('firstvalue')
  154. await submitForm()
  155. await waitForLogsPage()
  156. await waitForExecutionComplete()
  157. await openArgumentForm()
  158. const input2 = await getTestInput()
  159. await input2.clear()
  160. await input2.sendKeys('secondvalue')
  161. await submitForm()
  162. await waitForLogsPage()
  163. await waitForExecutionComplete()
  164. const stored = await getLocalStorageItem('olivetin-suggestions-test-suggestions-key')
  165. expect(stored).to.not.be.null
  166. const suggestions = JSON.parse(stored)
  167. expect(suggestions).to.be.an('array')
  168. expect(suggestions).to.include('firstvalue')
  169. expect(suggestions).to.include('secondvalue')
  170. expect(suggestions[0]).to.equal('secondvalue')
  171. })
  172. it('Empty values are not saved to localStorage', async function () {
  173. await clearLocalStorage()
  174. await openArgumentForm()
  175. const input = await getTestInput()
  176. await input.clear()
  177. await submitForm()
  178. await waitForLogsPage()
  179. await waitForExecutionComplete()
  180. const stored = await getLocalStorageItem('olivetin-suggestions-test-suggestions-key')
  181. if (stored !== null) {
  182. const suggestions = JSON.parse(stored)
  183. expect(suggestions).to.be.an('array')
  184. expect(suggestions).to.have.length(0)
  185. }
  186. })
  187. it('Suggestions are shared across inputs with the same suggestionsBrowserKey', async function () {
  188. this.timeout(12000)
  189. await clearLocalStorage()
  190. await openArgumentForm()
  191. const input1 = await getTestInput()
  192. await input1.clear()
  193. await input1.sendKeys('sharedfrominput1')
  194. await submitForm()
  195. await waitForLogsPage()
  196. await waitForExecutionComplete()
  197. await openArgumentForm()
  198. const datalist1 = await webdriver.findElement(By.id(argumentFieldChoicesId('testInput')))
  199. expect(datalist1).to.not.be.null
  200. const options1 = await getDatalistOptions('testInput')
  201. let foundInInput1 = false
  202. for (const option of options1) {
  203. const value = await option.getAttribute('value')
  204. if (value === 'sharedfrominput1') {
  205. foundInInput1 = true
  206. break
  207. }
  208. }
  209. expect(foundInInput1).to.be.true
  210. const datalist2 = await webdriver.findElement(By.id(argumentFieldChoicesId('testInput2')))
  211. expect(datalist2).to.not.be.null
  212. const options2 = await getDatalistOptions('testInput2')
  213. let foundInInput2 = false
  214. for (const option of options2) {
  215. const value = await option.getAttribute('value')
  216. if (value === 'sharedfrominput1') {
  217. foundInInput2 = true
  218. break
  219. }
  220. }
  221. expect(foundInInput2).to.be.true
  222. const input2 = await getTestInput2()
  223. await input2.clear()
  224. await input2.sendKeys('sharedfrominput2')
  225. await submitForm()
  226. await waitForLogsPage()
  227. await waitForExecutionComplete()
  228. await openArgumentForm()
  229. const options1After = await getDatalistOptions('testInput')
  230. let foundValue1 = false
  231. let foundValue2 = false
  232. for (const option of options1After) {
  233. const value = await option.getAttribute('value')
  234. if (value === 'sharedfrominput1') {
  235. foundValue1 = true
  236. }
  237. if (value === 'sharedfrominput2') {
  238. foundValue2 = true
  239. }
  240. }
  241. expect(foundValue1).to.be.true
  242. expect(foundValue2).to.be.true
  243. const options2After = await getDatalistOptions('testInput2')
  244. foundValue1 = false
  245. foundValue2 = false
  246. for (const option of options2After) {
  247. const value = await option.getAttribute('value')
  248. if (value === 'sharedfrominput1') {
  249. foundValue1 = true
  250. }
  251. if (value === 'sharedfrominput2') {
  252. foundValue2 = true
  253. }
  254. }
  255. expect(foundValue1).to.be.true
  256. expect(foundValue2).to.be.true
  257. })
  258. })