composer-placeholder.e2e.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. // The built shared Web/Electron composer hides guidance as soon as a draft contains whitespace.
  2. import { fileURLToPath } from 'node:url'
  3. import { chromium, type Page } from 'playwright'
  4. import { expect, it } from 'vitest'
  5. import { assertFixtureInventory, compareOrRefreshGolden, launchWebScaffold, watchConsole, webSnapshotMode } from './scaffold.ts'
  6. import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts'
  7. it('hides the placeholder for typed and pasted spaces and restores it after deletion', async () => {
  8. const scaffold = await launchWebScaffold({})
  9. try {
  10. const browser = await chromium.launch()
  11. let failurePage: Page | undefined
  12. try {
  13. const page = await newEnglishPage(browser)
  14. failurePage = page
  15. const tripwire = watchConsole(page)
  16. await page.goto(scaffold.authenticatedUrl)
  17. await connectFreshWorkspace(page, scaffold.workspaceCwd, 'composer-placeholder')
  18. const input = page.locator('[data-composer-input][contenteditable="true"]').first()
  19. const placeholder = page.locator('[data-composer-placeholder]').first()
  20. const observations: string[] = []
  21. const observe = async (label: string, visible: boolean) => {
  22. await expect.poll(() => placeholder.isVisible()).toBe(visible)
  23. observations.push(`- ${label}: placeholder ${visible ? 'visible' : 'hidden'}`)
  24. }
  25. const clear = async () => {
  26. await input.click()
  27. await page.keyboard.press('ControlOrMeta+KeyA')
  28. await page.keyboard.press('Backspace')
  29. }
  30. await observe('Empty draft', true)
  31. await input.click()
  32. await page.keyboard.press('Space')
  33. await observe('Single space', false)
  34. await page.keyboard.press('Space')
  35. await page.keyboard.press('Space')
  36. await observe('Consecutive spaces', false)
  37. await page.keyboard.press('Tab')
  38. await input.click()
  39. await observe('Focus restored', false)
  40. const draftMarkup = await input.innerHTML()
  41. await page.keyboard.press('Enter')
  42. expect(await input.innerHTML()).toBe(draftMarkup)
  43. await observe('Whitespace submission rejected', false)
  44. await clear()
  45. await observe('All content deleted', true)
  46. await page.context().grantPermissions(['clipboard-read', 'clipboard-write'])
  47. await page.evaluate(() => navigator.clipboard.writeText(' '))
  48. await page.keyboard.press('ControlOrMeta+KeyV')
  49. await expect.poll(() => input.textContent()).toBe(' ')
  50. await observe('Pasted spaces', false)
  51. await clear()
  52. await observe('Pasted content deleted', true)
  53. await assertFixtureInventory(
  54. fileURLToPath(new URL('./expected/composer-placeholder', import.meta.url)), ['visibility.expected.md'],
  55. )
  56. expect(tripwire.pageErrors).toEqual([])
  57. expect(tripwire.warnings).toEqual([])
  58. await compareOrRefreshGolden(
  59. fileURLToPath(new URL('./expected/composer-placeholder/visibility.expected.md', import.meta.url)),
  60. observations.join('\n'), webSnapshotMode(),
  61. )
  62. } catch (error) {
  63. if (failurePage !== undefined) await saveFailureShot(failurePage, 'web-e2e-composer-placeholder')
  64. throw error
  65. } finally {
  66. await browser.close()
  67. }
  68. } finally {
  69. await scaffold.close()
  70. }
  71. })