basic.spec.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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, 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, block, graphDir }) => {
  40. const pageTitle = await createRandomPage(page)
  41. // do editing
  42. await block.mustFill('this is my first bullet')
  43. await block.enterNext()
  44. await block.waitForBlocks(1)
  45. await block.mustFill('this is my second bullet')
  46. await block.clickNext()
  47. await block.mustFill('this is my third bullet')
  48. await block.indent()
  49. await block.enterNext()
  50. await page.keyboard.type('continue editing test')
  51. await page.keyboard.press('Shift+Enter')
  52. await page.keyboard.type('continue')
  53. await block.enterNext()
  54. expect(await block.unindent()).toBe(true)
  55. expect(await block.unindent()).toBe(false)
  56. await block.mustFill('test ok')
  57. await page.keyboard.press('Escape')
  58. await block.waitForBlocks(5)
  59. // active edit, and create next block
  60. await block.clickNext()
  61. await page.fill('textarea >> nth=0', 'test')
  62. for (let i = 0; i < 5; i++) {
  63. await page.keyboard.press('Backspace', { delay: 100 })
  64. }
  65. await page.keyboard.press('Escape')
  66. await block.waitForBlocks(5)
  67. await page.waitForTimeout(2000) // wait for saving to disk
  68. const contentOnDisk = await fs.readFile(
  69. path.join(graphDir, `pages/${pageTitle}.md`),
  70. 'utf8'
  71. )
  72. expect(contentOnDisk.trim()).toEqual(`
  73. - this is my first bullet
  74. - this is my second bullet
  75. - this is my third bullet
  76. - continue editing test
  77. continue
  78. - test ok`.trim())
  79. })
  80. test('delete and backspace', async ({ page, block }) => {
  81. await createRandomPage(page)
  82. await block.mustFill('test')
  83. // backspace
  84. await page.keyboard.press('Backspace')
  85. await page.keyboard.press('Backspace')
  86. expect(await page.inputValue('textarea >> nth=0')).toBe('te')
  87. // refill
  88. await block.enterNext()
  89. await page.type('textarea >> nth=0', 'test', { delay: 50 })
  90. await page.keyboard.press('ArrowLeft', { delay: 50 })
  91. await page.keyboard.press('ArrowLeft', { delay: 50 })
  92. // delete
  93. await page.keyboard.press('Delete', { delay: 50 })
  94. expect(await page.inputValue('textarea >> nth=0')).toBe('tet')
  95. await page.keyboard.press('Delete', { delay: 50 })
  96. expect(await page.inputValue('textarea >> nth=0')).toBe('te')
  97. await page.keyboard.press('Delete', { delay: 50 })
  98. expect(await page.inputValue('textarea >> nth=0')).toBe('te')
  99. // TODO: test delete & backspace across blocks
  100. })
  101. test('selection', async ({ page, block }) => {
  102. await createRandomPage(page)
  103. // add 5 blocks
  104. await block.mustFill('line 1')
  105. await block.enterNext()
  106. await block.mustFill('line 2')
  107. await block.enterNext()
  108. expect(await block.indent()).toBe(true)
  109. await block.mustFill('line 3')
  110. await block.enterNext()
  111. await block.mustFill('line 4')
  112. expect(await block.indent()).toBe(true)
  113. await block.enterNext()
  114. await block.mustFill('line 5')
  115. // shift+up select 3 blocks
  116. await page.keyboard.down('Shift')
  117. await page.keyboard.press('ArrowUp')
  118. await page.keyboard.press('ArrowUp')
  119. await page.keyboard.press('ArrowUp')
  120. await page.keyboard.up('Shift')
  121. await block.waitForSelectedBlocks(3)
  122. await page.keyboard.press('Backspace')
  123. await block.waitForBlocks(2)
  124. })
  125. test('template', async ({ page, block }) => {
  126. const randomTemplate = randomString(10)
  127. await createRandomPage(page)
  128. await block.mustFill('template test\ntemplate:: ' + randomTemplate)
  129. await block.clickNext()
  130. expect(await block.indent()).toBe(true)
  131. await block.mustFill('line1')
  132. await block.enterNext()
  133. await block.mustFill('line2')
  134. await block.enterNext()
  135. expect(await block.indent()).toBe(true)
  136. await block.mustFill('line3')
  137. await block.enterNext()
  138. expect(await block.unindent()).toBe(true)
  139. expect(await block.unindent()).toBe(true)
  140. expect(await block.unindent()).toBe(false) // already at the first level
  141. await block.waitForBlocks(4)
  142. // NOTE: use delay to type slower, to trigger auto-completion UI.
  143. await block.mustType('/template')
  144. await page.click('[title="Insert a created template here"]')
  145. // type to search template name
  146. await page.keyboard.type(randomTemplate.substring(0, 3), { delay: 100 })
  147. const popupMenuItem = page.locator('.absolute >> text=' + randomTemplate)
  148. await popupMenuItem.waitFor({ timeout: 2000 }) // wait for template search
  149. await popupMenuItem.click()
  150. await block.waitForBlocks(8)
  151. })
  152. test('auto completion square brackets', async ({ page }) => {
  153. await createRandomPage(page)
  154. // In this test, `type` is unsed instead of `fill`, to allow for auto-completion.
  155. // [[]]
  156. await page.type('textarea >> nth=0', 'This is a [')
  157. await expect(page.locator('textarea >> nth=0')).toHaveText('This is a []')
  158. await page.waitForTimeout(100)
  159. await page.type('textarea >> nth=0', '[')
  160. // wait for search popup
  161. await page.waitForSelector('text="Search for a page"')
  162. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]')
  163. // re-enter edit mode
  164. await page.press('textarea >> nth=0', 'Escape')
  165. await page.click('.ls-block >> nth=-1')
  166. await page.waitForSelector('textarea >> nth=0', { state: 'visible' })
  167. // #3253
  168. await page.press('textarea >> nth=0', 'ArrowLeft')
  169. await page.press('textarea >> nth=0', 'ArrowLeft')
  170. await page.press('textarea >> nth=0', 'Enter')
  171. await page.waitForSelector('text="Search for a page"', { state: 'visible' })
  172. // type more `]`s
  173. await page.type('textarea >> nth=0', ']')
  174. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]')
  175. await page.type('textarea >> nth=0', ']')
  176. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]')
  177. await page.type('textarea >> nth=0', ']')
  178. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]]')
  179. })
  180. test('auto completion and auto pair', async ({ page, block }) => {
  181. await createRandomPage(page)
  182. await block.mustFill('Auto-completion test')
  183. await block.enterNext()
  184. // {{
  185. await page.type('textarea >> nth=0', 'type {{')
  186. expect(await page.inputValue('textarea >> nth=0')).toBe('type {{}}')
  187. // ((
  188. await block.clickNext()
  189. await page.type('textarea >> nth=0', 'type (')
  190. expect(await page.inputValue('textarea >> nth=0')).toBe('type ()')
  191. await page.type('textarea >> nth=0', '(')
  192. expect(await page.inputValue('textarea >> nth=0')).toBe('type (())')
  193. // 99 #3444
  194. // TODO: Test under different keyboard layout when Playwright supports it
  195. // await block.clickNext()
  196. // await page.type('textarea >> nth=0', 'type 9')
  197. // expect(await page.inputValue('textarea >> nth=0')).toBe('type 9')
  198. // await page.type('textarea >> nth=0', '9')
  199. // expect(await page.inputValue('textarea >> nth=0')).toBe('type 99')
  200. // [[ #3251
  201. await block.clickNext()
  202. await page.type('textarea >> nth=0', 'type [')
  203. expect(await page.inputValue('textarea >> nth=0')).toBe('type []')
  204. await page.type('textarea >> nth=0', '[')
  205. expect(await page.inputValue('textarea >> nth=0')).toBe('type [[]]')
  206. await page.press('textarea >> nth=0', 'Escape') // escape any popup from `[[]]`
  207. // ``
  208. await block.clickNext()
  209. await page.type('textarea >> nth=0', 'type `')
  210. expect(await page.inputValue('textarea >> nth=0')).toBe('type ``')
  211. await page.type('textarea >> nth=0', 'code here')
  212. expect(await page.inputValue('textarea >> nth=0')).toBe('type `code here`')
  213. })
  214. test('invalid page props #3944', async ({ page, block }) => {
  215. await createRandomPage(page)
  216. await block.mustFill('public:: true\nsize:: 65535')
  217. await page.press('textarea >> nth=0', 'Enter')
  218. await block.clickNext()
  219. })