basic.spec.ts 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. import { expect } from '@playwright/test'
  2. import fs from 'fs/promises'
  3. import path from 'path'
  4. import { test } from './fixtures'
  5. import { randomString, createRandomPage, newBlock, enterNextBlock } from './utils'
  6. test('render app', async ({ page }) => {
  7. // NOTE: part of app startup tests is moved to `fixtures.ts`.
  8. await page.waitForFunction('window.document.title != "Loading"')
  9. expect(await page.title()).toMatch(/^Logseq.*?/)
  10. })
  11. test('toggle sidebar', async ({ page }) => {
  12. let sidebar = page.locator('#left-sidebar')
  13. // Left sidebar is toggled by `is-open` class
  14. if (/is-open/.test(await sidebar.getAttribute('class'))) {
  15. await page.click('#left-menu.button')
  16. await expect(sidebar).not.toHaveClass(/is-open/)
  17. } else {
  18. await page.click('#left-menu.button')
  19. await page.waitForTimeout(10)
  20. await expect(sidebar).toHaveClass(/is-open/)
  21. await page.click('#left-menu.button')
  22. await page.waitForTimeout(10)
  23. await expect(sidebar).not.toHaveClass(/is-open/)
  24. }
  25. await page.click('#left-menu.button')
  26. await page.waitForTimeout(10)
  27. await expect(sidebar).toHaveClass(/is-open/)
  28. await page.waitForSelector('#left-sidebar .left-sidebar-inner', { state: 'visible' })
  29. await page.waitForSelector('#left-sidebar a:has-text("New page")', { state: 'visible' })
  30. })
  31. test('search', async ({ page }) => {
  32. await page.click('#search-button')
  33. await page.waitForSelector('[placeholder="Search or create page"]')
  34. await page.fill('[placeholder="Search or create page"]', 'welcome')
  35. await page.waitForTimeout(500)
  36. const results = await page.$$('#ui__ac-inner .block')
  37. expect(results.length).toBeGreaterThanOrEqual(1)
  38. })
  39. test('create page and blocks, save to disk', async ({ page, graphDir }) => {
  40. const pageTitle = await createRandomPage(page)
  41. // do editing
  42. await page.fill('textarea >> nth=0', 'this is my first bullet')
  43. await enterNextBlock(page)
  44. // wait first block
  45. await page.waitForSelector('.ls-block >> nth=0')
  46. await page.fill('textarea >> nth=0', 'this is my second bullet')
  47. await enterNextBlock(page)
  48. await page.fill('textarea >> nth=0', 'this is my third bullet')
  49. await page.press('textarea >> nth=0', 'Tab')
  50. await enterNextBlock(page)
  51. await page.keyboard.type('continue editing test')
  52. await page.keyboard.press('Shift+Enter')
  53. await page.keyboard.type('continue')
  54. await enterNextBlock(page)
  55. await page.keyboard.press('Shift+Tab')
  56. await page.keyboard.press('Shift+Tab')
  57. await page.keyboard.type('test ok')
  58. await page.keyboard.press('Escape')
  59. // NOTE: nth= counts from 0, so here're 5 blocks
  60. await page.waitForSelector('.ls-block >> nth=4')
  61. // active edit
  62. await page.click('.ls-block >> nth=-1')
  63. await enterNextBlock(page)
  64. await page.fill('textarea >> nth=0', 'test')
  65. for (let i = 0; i < 5; i++) {
  66. await page.keyboard.press('Backspace')
  67. }
  68. await page.keyboard.press('Escape')
  69. await page.waitForSelector('.ls-block >> nth=4') // 5 blocks
  70. await page.waitForTimeout(2000) // wait for saving to disk
  71. const contentOnDisk = fs.readFileSync(
  72. path.join(graphDir, `pages/${pageTitle}.md`),
  73. 'utf8'
  74. )
  75. expect(contentOnDisk.trim()).toEqual(`
  76. - this is my first bullet
  77. - this is my second bullet
  78. \t- this is my third bullet
  79. \t- continue editing test
  80. \tcontinue
  81. - test ok`.trim())
  82. })
  83. test('delete and backspace', async ({ page }) => {
  84. await createRandomPage(page)
  85. await page.fill('textarea >> nth=0', 'test')
  86. expect(await page.inputValue('textarea >> nth=0')).toBe('test')
  87. // backspace
  88. await page.keyboard.press('Backspace')
  89. await page.keyboard.press('Backspace')
  90. expect(await page.inputValue('textarea >> nth=0')).toBe('te')
  91. // refill
  92. await enterNextBlock(page)
  93. await page.type('textarea >> nth=0', 'test')
  94. await page.keyboard.press('ArrowLeft')
  95. await page.keyboard.press('ArrowLeft')
  96. // delete
  97. await page.keyboard.press('Delete')
  98. expect(await page.inputValue('textarea >> nth=0')).toBe('tet')
  99. await page.keyboard.press('Delete')
  100. expect(await page.inputValue('textarea >> nth=0')).toBe('te')
  101. await page.keyboard.press('Delete')
  102. expect(await page.inputValue('textarea >> nth=0')).toBe('te')
  103. // TODO: test delete & backspace across blocks
  104. })
  105. test('selection', async ({ page }) => {
  106. await createRandomPage(page)
  107. // add 5 blocks
  108. await page.fill('textarea >> nth=0', 'line 1')
  109. await enterNextBlock(page)
  110. await page.fill('textarea >> nth=0', 'line 2')
  111. await enterNextBlock(page)
  112. await page.press('textarea >> nth=0', 'Tab')
  113. await page.fill('textarea >> nth=0', 'line 3')
  114. await enterNextBlock(page)
  115. await page.fill('textarea >> nth=0', 'line 4')
  116. await page.press('textarea >> nth=0', 'Tab')
  117. await enterNextBlock(page)
  118. await page.fill('textarea >> nth=0', 'line 5')
  119. // shift+up select 3 blocks
  120. await page.keyboard.down('Shift')
  121. await page.keyboard.press('ArrowUp')
  122. await page.keyboard.press('ArrowUp')
  123. await page.keyboard.press('ArrowUp')
  124. await page.keyboard.up('Shift')
  125. await page.waitForSelector('.ls-block.selected >> nth=2') // 3 selected
  126. await page.keyboard.press('Backspace')
  127. await page.waitForSelector('.ls-block >> nth=1') // 2 blocks
  128. })
  129. test('template', async ({ page }) => {
  130. const randomTemplate = randomString(10)
  131. await createRandomPage(page)
  132. await page.fill('textarea >> nth=0', 'template')
  133. await page.press('textarea >> nth=0', 'Shift+Enter')
  134. await page.type('textarea >> nth=0', 'template:: ' + randomTemplate)
  135. // Enter twice to exit from property block
  136. await page.press('textarea >> nth=0', 'Enter')
  137. await enterNextBlock(page)
  138. await page.press('textarea >> nth=0', 'Tab')
  139. await page.fill('textarea >> nth=0', 'line1')
  140. await enterNextBlock(page)
  141. await page.fill('textarea >> nth=0', 'line2')
  142. await enterNextBlock(page)
  143. await page.press('textarea >> nth=0', 'Tab')
  144. await page.fill('textarea >> nth=0', 'line3')
  145. await enterNextBlock(page)
  146. await page.press('textarea >> nth=0', 'Shift+Tab')
  147. await page.press('textarea >> nth=0', 'Shift+Tab')
  148. await page.press('textarea >> nth=0', 'Shift+Tab')
  149. await page.waitForSelector('.ls-block >> nth=3') // total 4 blocks
  150. // NOTE: use delay to type slower, to trigger auto-completion UI.
  151. await page.type('textarea >> nth=0', '/template', { delay: 100 })
  152. await page.click('[title="Insert a created template here"]')
  153. // type to search template name
  154. await page.keyboard.type(randomTemplate.substring(0, 3), { delay: 100 })
  155. await page.waitForTimeout(500) // wait for template search
  156. await page.click('.absolute >> text=' + randomTemplate)
  157. await page.waitForSelector('.ls-block >> nth=7') // 8 blocks
  158. })
  159. test('auto completion square brackets', async ({ page }) => {
  160. await createRandomPage(page)
  161. // [[]]
  162. await page.type('textarea >> nth=0', 'This is a [')
  163. await page.inputValue('textarea >> nth=0').then(text => {
  164. expect(text).toBe('This is a []')
  165. })
  166. await page.waitForTimeout(100)
  167. await page.type('textarea >> nth=0', '[')
  168. // wait for search popup
  169. await page.waitForSelector('text="Search for a page"')
  170. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]')
  171. // re-enter edit mode
  172. await page.press('textarea >> nth=0', 'Escape')
  173. await page.click('.ls-block >> nth=-1')
  174. await page.waitForSelector('textarea >> nth=0', { state: 'visible' })
  175. // #3253
  176. await page.press('textarea >> nth=0', 'ArrowLeft')
  177. await page.press('textarea >> nth=0', 'ArrowLeft')
  178. await page.press('textarea >> nth=0', 'Enter')
  179. await page.waitForSelector('text="Search for a page"', { state: 'visible' })
  180. // type more `]`s
  181. await page.type('textarea >> nth=0', ']')
  182. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]')
  183. await page.type('textarea >> nth=0', ']')
  184. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]')
  185. await page.type('textarea >> nth=0', ']')
  186. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]]')
  187. })
  188. test('auto completion and auto pair', async ({ page }) => {
  189. await createRandomPage(page)
  190. await page.fill('textarea >> nth=0', 'Auto-completion test')
  191. await enterNextBlock(page)
  192. // {{
  193. await page.type('textarea >> nth=0', 'type {{')
  194. expect(await page.inputValue('textarea >> nth=0')).toBe('type {{}}')
  195. // ((
  196. await newBlock(page)
  197. await page.type('textarea >> nth=0', 'type (')
  198. expect(await page.inputValue('textarea >> nth=0')).toBe('type ()')
  199. await page.type('textarea >> nth=0', '(')
  200. expect(await page.inputValue('textarea >> nth=0')).toBe('type (())')
  201. // 99 #3444
  202. // TODO: Test under different keyboard layout when Playwright supports it
  203. // await newBlock(page)
  204. // await page.type('textarea >> nth=0', 'type 9')
  205. // expect(await page.inputValue('textarea >> nth=0')).toBe('type 9')
  206. // await page.type('textarea >> nth=0', '9')
  207. // expect(await page.inputValue('textarea >> nth=0')).toBe('type 99')
  208. // [[ #3251
  209. await newBlock(page)
  210. await page.type('textarea >> nth=0', 'type [')
  211. expect(await page.inputValue('textarea >> nth=0')).toBe('type []')
  212. await page.type('textarea >> nth=0', '[')
  213. expect(await page.inputValue('textarea >> nth=0')).toBe('type [[]]')
  214. // ``
  215. await newBlock(page)
  216. await page.type('textarea >> nth=0', 'type `')
  217. expect(await page.inputValue('textarea >> nth=0')).toBe('type ``')
  218. await page.type('textarea >> nth=0', 'code here')
  219. expect(await page.inputValue('textarea >> nth=0')).toBe('type `code here`')
  220. })
  221. test('invalid page props #3944', async ({ page }) => {
  222. await createRandomPage(page)
  223. await page.fill('textarea >> nth=0', 'public:: true\nsize:: 65535')
  224. await page.press('textarea >> nth=0', 'Enter')
  225. await enterNextBlock(page)
  226. })