suggestionsBrowserKey.mjs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. import { describe, it, before, after } from 'mocha'
  2. import { expect } from 'chai'
  3. import { By, Condition } from 'selenium-webdriver'
  4. import {
  5. getRootAndWait,
  6. getActionButton,
  7. takeScreenshotOnFailure,
  8. getTerminalBuffer,
  9. } from '../../lib/elements.js'
  10. async function openArgumentForm() {
  11. await getRootAndWait()
  12. const btn = await getActionButton(webdriver, 'Test suggestionsBrowserKey')
  13. await btn.click()
  14. await webdriver.wait(
  15. new Condition('wait for argument form page', async () => {
  16. const url = await webdriver.getCurrentUrl()
  17. return url.includes('/actionBinding/') && url.includes('/argumentForm')
  18. }),
  19. 5000
  20. )
  21. }
  22. async function getTestInput() {
  23. return await webdriver.findElement(By.id('testInput'))
  24. }
  25. async function getTestInput2() {
  26. return await webdriver.findElement(By.id('testInput2'))
  27. }
  28. async function getDatalistOptions(inputName = 'testInput') {
  29. return await webdriver.findElements(By.css(`datalist#${inputName}-choices option`))
  30. }
  31. async function submitForm() {
  32. const submitButton = await webdriver.findElement(By.css('button[name="start"]'))
  33. await submitButton.click()
  34. }
  35. async function waitForLogsPage() {
  36. await webdriver.wait(
  37. new Condition('wait for logs page', async () => {
  38. const url = await webdriver.getCurrentUrl()
  39. return url.includes('/logs/') && !url.endsWith('/logs')
  40. }),
  41. 5000
  42. )
  43. }
  44. async function waitForExecutionComplete() {
  45. await webdriver.wait(
  46. new Condition('wait for execution status', async () => {
  47. const statusElements = await webdriver.findElements(By.id('execution-dialog-status'))
  48. return statusElements.length > 0
  49. }),
  50. 5000
  51. )
  52. await webdriver.wait(
  53. new Condition('wait for execution to finish', async () => {
  54. try {
  55. const statusElement = await webdriver.findElement(By.id('execution-dialog-status'))
  56. const statusText = await statusElement.getText()
  57. return !statusText.includes('Executing')
  58. } catch (e) {
  59. return false
  60. }
  61. }),
  62. 5000
  63. )
  64. await webdriver.sleep(500)
  65. }
  66. async function getLocalStorageItem(key) {
  67. return await webdriver.executeScript(`return localStorage.getItem('${key}')`)
  68. }
  69. async function clearLocalStorage() {
  70. await webdriver.executeScript('return localStorage.clear()')
  71. }
  72. describe('config: suggestionsBrowserKey', function () {
  73. before(async function () {
  74. await runner.start('suggestionsBrowserKey')
  75. })
  76. after(async () => {
  77. await runner.stop()
  78. })
  79. afterEach(function () {
  80. takeScreenshotOnFailure(this.currentTest, webdriver)
  81. })
  82. it('Input fields with suggestionsBrowserKey are rendered', async function () {
  83. await openArgumentForm()
  84. const input1 = await getTestInput()
  85. expect(await input1.getTagName()).to.equal('input')
  86. expect(await input1.getAttribute('type')).to.equal('text')
  87. const label1 = await webdriver.findElement(By.css('label[for="testInput"]'))
  88. expect(await label1.getText()).to.contain('Test Input')
  89. const input2 = await getTestInput2()
  90. expect(await input2.getTagName()).to.equal('input')
  91. expect(await input2.getAttribute('type')).to.equal('text')
  92. const label2 = await webdriver.findElement(By.css('label[for="testInput2"]'))
  93. expect(await label2.getText()).to.contain('Test Input 2')
  94. })
  95. it('Submitting form saves value to localStorage', async function () {
  96. this.timeout(15000)
  97. // Clear localStorage first
  98. await clearLocalStorage()
  99. await openArgumentForm()
  100. const input = await getTestInput()
  101. const testValue = 'test-value-123'
  102. await input.clear()
  103. await input.sendKeys(testValue)
  104. await submitForm()
  105. await waitForLogsPage()
  106. await waitForExecutionComplete()
  107. // Verify value was saved to localStorage
  108. const stored = await getLocalStorageItem('olivetin-suggestions-test-suggestions-key')
  109. expect(stored).to.not.be.null
  110. const suggestions = JSON.parse(stored)
  111. expect(suggestions).to.be.an('array')
  112. expect(suggestions).to.include(testValue)
  113. })
  114. it('Previously saved values appear in datalist', async function () {
  115. this.timeout(15000)
  116. // First, save a value to localStorage
  117. const testValue = 'saved-suggestion-456'
  118. await webdriver.executeScript(`
  119. const key = 'olivetin-suggestions-test-suggestions-key';
  120. localStorage.setItem(key, JSON.stringify(['${testValue}']));
  121. `)
  122. // Open the form
  123. await openArgumentForm()
  124. // Check that datalist exists and contains the saved value
  125. const datalist = await webdriver.findElement(By.id('testInput-choices'))
  126. expect(datalist).to.not.be.null
  127. const options = await getDatalistOptions()
  128. expect(options.length).to.be.greaterThan(0)
  129. // Check if the saved value appears in the datalist
  130. let foundValue = false
  131. for (const option of options) {
  132. const value = await option.getAttribute('value')
  133. if (value === testValue) {
  134. foundValue = true
  135. break
  136. }
  137. }
  138. expect(foundValue).to.be.true
  139. })
  140. it('Multiple submissions accumulate suggestions', async function () {
  141. this.timeout(20000)
  142. // Clear localStorage first
  143. await clearLocalStorage()
  144. // Submit first value
  145. await openArgumentForm()
  146. const input1 = await getTestInput()
  147. await input1.clear()
  148. await input1.sendKeys('first-value')
  149. await submitForm()
  150. await waitForLogsPage()
  151. await waitForExecutionComplete()
  152. // Submit second value
  153. await openArgumentForm()
  154. const input2 = await getTestInput()
  155. await input2.clear()
  156. await input2.sendKeys('second-value')
  157. await submitForm()
  158. await waitForLogsPage()
  159. await waitForExecutionComplete()
  160. // Verify both values are in localStorage
  161. const stored = await getLocalStorageItem('olivetin-suggestions-test-suggestions-key')
  162. expect(stored).to.not.be.null
  163. const suggestions = JSON.parse(stored)
  164. expect(suggestions).to.be.an('array')
  165. expect(suggestions).to.include('first-value')
  166. expect(suggestions).to.include('second-value')
  167. expect(suggestions[0]).to.equal('second-value') // Most recent should be first
  168. })
  169. it('Empty values are not saved to localStorage', async function () {
  170. this.timeout(15000)
  171. // Clear localStorage first
  172. await clearLocalStorage()
  173. await openArgumentForm()
  174. const input = await getTestInput()
  175. // Leave input empty (or clear it if it has a default)
  176. await input.clear()
  177. await submitForm()
  178. await waitForLogsPage()
  179. await waitForExecutionComplete()
  180. // Verify empty value was not saved - localStorage should be null or empty-equivalent
  181. const stored = await getLocalStorageItem('olivetin-suggestions-test-suggestions-key')
  182. // Should be null OR empty JSON array string ("[]") OR parse to empty array
  183. if (stored !== null) {
  184. const suggestions = JSON.parse(stored)
  185. expect(suggestions).to.be.an('array')
  186. expect(suggestions).to.have.length(0)
  187. }
  188. // If stored is null, that's also acceptable - no assertion needed
  189. })
  190. it('Suggestions are shared across inputs with the same suggestionsBrowserKey', async function () {
  191. this.timeout(20000)
  192. // Clear localStorage first
  193. await clearLocalStorage()
  194. // Submit a value using the first input
  195. await openArgumentForm()
  196. const input1 = await getTestInput()
  197. await input1.clear()
  198. await input1.sendKeys('shared-value-from-input1')
  199. await submitForm()
  200. await waitForLogsPage()
  201. await waitForExecutionComplete()
  202. // Open the form again and verify the value appears in both datalists
  203. await openArgumentForm()
  204. // Check first input's datalist
  205. const datalist1 = await webdriver.findElement(By.id('testInput-choices'))
  206. expect(datalist1).to.not.be.null
  207. const options1 = await getDatalistOptions('testInput')
  208. let foundInInput1 = false
  209. for (const option of options1) {
  210. const value = await option.getAttribute('value')
  211. if (value === 'shared-value-from-input1') {
  212. foundInInput1 = true
  213. break
  214. }
  215. }
  216. expect(foundInInput1).to.be.true
  217. // Check second input's datalist
  218. const datalist2 = await webdriver.findElement(By.id('testInput2-choices'))
  219. expect(datalist2).to.not.be.null
  220. const options2 = await getDatalistOptions('testInput2')
  221. let foundInInput2 = false
  222. for (const option of options2) {
  223. const value = await option.getAttribute('value')
  224. if (value === 'shared-value-from-input1') {
  225. foundInInput2 = true
  226. break
  227. }
  228. }
  229. expect(foundInInput2).to.be.true
  230. // Now submit a value using the second input
  231. const input2 = await getTestInput2()
  232. await input2.clear()
  233. await input2.sendKeys('shared-value-from-input2')
  234. await submitForm()
  235. await waitForLogsPage()
  236. await waitForExecutionComplete()
  237. // Verify both values appear in both datalists
  238. await openArgumentForm()
  239. // Check that both values are in the first input's datalist
  240. const options1After = await getDatalistOptions('testInput')
  241. let foundValue1 = false
  242. let foundValue2 = false
  243. for (const option of options1After) {
  244. const value = await option.getAttribute('value')
  245. if (value === 'shared-value-from-input1') {
  246. foundValue1 = true
  247. }
  248. if (value === 'shared-value-from-input2') {
  249. foundValue2 = true
  250. }
  251. }
  252. expect(foundValue1).to.be.true
  253. expect(foundValue2).to.be.true
  254. // Check that both values are in the second input's datalist
  255. const options2After = await getDatalistOptions('testInput2')
  256. foundValue1 = false
  257. foundValue2 = false
  258. for (const option of options2After) {
  259. const value = await option.getAttribute('value')
  260. if (value === 'shared-value-from-input1') {
  261. foundValue1 = true
  262. }
  263. if (value === 'shared-value-from-input2') {
  264. foundValue2 = true
  265. }
  266. }
  267. expect(foundValue1).to.be.true
  268. expect(foundValue2).to.be.true
  269. })
  270. })