basic.spec.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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, modKey } from './utils'
  6. test('create page and blocks, save to disk', async ({ page, block, graphDir }) => {
  7. const pageTitle = await createRandomPage(page)
  8. // do editing
  9. await page.keyboard.type('first bullet')
  10. await block.enterNext()
  11. await block.waitForBlocks(2)
  12. await page.keyboard.type('second bullet')
  13. await block.enterNext()
  14. await page.keyboard.type('third bullet')
  15. expect(await block.indent()).toBe(true)
  16. await block.enterNext()
  17. await page.keyboard.type('continue editing')
  18. await page.keyboard.press('Shift+Enter')
  19. await page.keyboard.type('second line')
  20. await block.enterNext()
  21. expect(await block.unindent()).toBe(true)
  22. expect(await block.unindent()).toBe(false)
  23. await page.keyboard.type('test ok')
  24. await page.keyboard.press('Escape')
  25. await block.waitForBlocks(5)
  26. // active edit, and create next block
  27. await block.clickNext()
  28. await page.keyboard.type('test')
  29. for (let i = 0; i < 5; i++) {
  30. await page.keyboard.press('Backspace', { delay: 100 })
  31. }
  32. await page.keyboard.press('Escape')
  33. await block.waitForBlocks(5)
  34. await page.waitForTimeout(2000) // wait for saving to disk
  35. const contentOnDisk = await fs.readFile(
  36. path.join(graphDir, `pages/${pageTitle}.md`),
  37. 'utf8'
  38. )
  39. expect(contentOnDisk.trim()).toEqual(`
  40. - first bullet
  41. - second bullet
  42. - third bullet
  43. - continue editing
  44. second line
  45. - test ok`.trim())
  46. })
  47. test('delete and backspace', async ({ page, block }) => {
  48. await createRandomPage(page)
  49. await block.mustFill('test')
  50. // backspace
  51. await page.keyboard.press('Backspace')
  52. await page.keyboard.press('Backspace')
  53. expect(await page.inputValue('textarea >> nth=0')).toBe('te')
  54. // refill
  55. await block.enterNext()
  56. await block.mustType('test')
  57. await page.keyboard.press('ArrowLeft', { delay: 50 })
  58. await page.keyboard.press('ArrowLeft', { delay: 50 })
  59. // delete
  60. await page.keyboard.press('Delete', { delay: 50 })
  61. expect(await page.inputValue('textarea >> nth=0')).toBe('tet')
  62. await page.keyboard.press('Delete', { delay: 50 })
  63. expect(await page.inputValue('textarea >> nth=0')).toBe('te')
  64. await page.keyboard.press('Delete', { delay: 50 })
  65. expect(await page.inputValue('textarea >> nth=0')).toBe('te')
  66. })
  67. test('block selection', async ({ page, block }) => {
  68. await createRandomPage(page)
  69. await block.mustFill('1')
  70. await block.enterNext()
  71. await block.mustFill('2')
  72. expect(await block.indent()).toBe(true)
  73. await block.enterNext()
  74. await block.mustFill('3')
  75. await block.enterNext()
  76. await block.mustFill('4')
  77. expect(await block.unindent()).toBe(true)
  78. await block.enterNext()
  79. await block.mustFill('5')
  80. expect(await block.indent()).toBe(true)
  81. await block.enterNext()
  82. await block.mustFill('6')
  83. await block.enterNext()
  84. await block.mustFill('7')
  85. expect(await block.unindent()).toBe(true)
  86. await block.enterNext()
  87. await block.mustFill('8')
  88. expect(await block.indent()).toBe(true)
  89. await block.enterNext()
  90. await block.mustFill('9')
  91. expect(await block.unindent()).toBe(true)
  92. // shift+up/down
  93. await page.keyboard.down('Shift')
  94. await page.keyboard.press('ArrowUp')
  95. await block.waitForSelectedBlocks(1)
  96. var locator = page.locator('.ls-block >> nth=8')
  97. await expect(locator).toHaveAttribute('level', '1')
  98. await expect(locator).toHaveCSS('border-radius', '2px')
  99. await page.keyboard.press('ArrowUp')
  100. await block.waitForSelectedBlocks(2)
  101. locator = page.locator('.ls-block >> nth=7')
  102. await expect(locator).toHaveAttribute('level', '2')
  103. await expect(locator).toHaveCSS('border-radius', '2px')
  104. await page.keyboard.press('ArrowUp')
  105. await block.waitForSelectedBlocks(3)
  106. locator = page.locator('.ls-block >> nth=6')
  107. await expect(locator).toHaveAttribute('level', '1')
  108. locator = page.locator('.block-main-container >> nth=6')
  109. await expect(locator).toHaveCSS('border-radius', '2px')
  110. await page.keyboard.press('ArrowDown')
  111. await block.waitForSelectedBlocks(2)
  112. locator = page.locator('.block-main-container >> nth=6')
  113. await expect(locator).toHaveCSS('border-radius', '0px')
  114. await page.keyboard.up('Shift')
  115. // mod+click select or deselect
  116. await page.keyboard.down(modKey)
  117. await page.click('.ls-block >> nth=7')
  118. await block.waitForSelectedBlocks(1)
  119. locator = page.locator('.ls-block >> nth=7')
  120. await expect(locator).toHaveCSS('border-radius', '0px')
  121. await page.click('.block-main-container >> nth=6')
  122. await block.waitForSelectedBlocks(2)
  123. locator = page.locator('.block-main-container >> nth=6')
  124. await expect(locator).toHaveCSS('border-radius', '2px')
  125. // mod+shift+click
  126. await page.click('.ls-block >> nth=4')
  127. await block.waitForSelectedBlocks(3)
  128. locator = page.locator('.ls-block >> nth=4')
  129. await expect(locator).toHaveAttribute('level', '2')
  130. await expect(locator).toHaveCSS('border-radius', '2px')
  131. await page.keyboard.down('Shift')
  132. await page.click('.ls-block >> nth=1')
  133. await block.waitForSelectedBlocks(6)
  134. locator = page.locator('.ls-block >> nth=3')
  135. await expect(locator).toHaveAttribute('level', '1')
  136. locator = page.locator('.block-main-container >> nth=3')
  137. await expect(locator).toHaveCSS('border-radius', '2px')
  138. locator = page.locator('.ls-block >> nth=2')
  139. await expect(locator).toHaveAttribute('level', '2')
  140. await expect(locator).toHaveCSS('border-radius', '2px')
  141. locator = page.locator('.ls-block >> nth=1')
  142. await expect(locator).toHaveAttribute('level', '2')
  143. await expect(locator).toHaveCSS('border-radius', '2px')
  144. await page.keyboard.up('Shift')
  145. await page.keyboard.up(modKey)
  146. await page.keyboard.press('Escape')
  147. // shift+click
  148. await page.keyboard.down('Shift')
  149. await page.click('.block-main-container >> nth=0')
  150. await expect(page.locator('.block-main-container >> nth=0')).toHaveCSS('border-radius', '0px')
  151. await page.click('.block-main-container >> nth=3')
  152. await block.waitForSelectedBlocks(4)
  153. await expect(page.locator('.block-main-container >> nth=0')).toHaveCSS('border-radius', '2px')
  154. await expect(page.locator('.ls-block >> nth=1')).toHaveCSS('border-radius', '2px')
  155. await expect(page.locator('.ls-block >> nth=2')).toHaveCSS('border-radius', '2px')
  156. await expect(page.locator('.block-main-container >> nth=3')).toHaveCSS('border-radius', '2px')
  157. await page.click('.ls-block >> nth=8')
  158. await block.waitForSelectedBlocks(9)
  159. await expect(page.locator('.ls-block >> nth=4')).toHaveCSS('border-radius', '2px')
  160. await expect(page.locator('.ls-block >> nth=5')).toHaveCSS('border-radius', '2px')
  161. await expect(page.locator('.block-main-container >> nth=6')).toHaveCSS('border-radius', '2px')
  162. await expect(page.locator('.ls-block >> nth=7')).toHaveCSS('border-radius', '2px')
  163. await expect(page.locator('.ls-block >> nth=8')).toHaveCSS('border-radius', '2px')
  164. await page.click('.ls-block >> nth=5')
  165. await block.waitForSelectedBlocks(6)
  166. await expect(page.locator('.block-main-container >> nth=6')).toHaveCSS('border-radius', '0px')
  167. await expect(page.locator('.ls-block >> nth=7')).toHaveCSS('border-radius', '0px')
  168. await expect(page.locator('.ls-block >> nth=8')).toHaveCSS('border-radius', '0px')
  169. await page.keyboard.up('Shift')
  170. })
  171. test('template', async ({ page, block }) => {
  172. const randomTemplate = randomString(6)
  173. await createRandomPage(page)
  174. await block.mustFill('template test\ntemplate:: ')
  175. await page.keyboard.type(randomTemplate, {delay: 100})
  176. await page.keyboard.press('Enter')
  177. await block.clickNext()
  178. expect(await block.indent()).toBe(true)
  179. await block.mustFill('line1')
  180. await block.enterNext()
  181. await block.mustFill('line2')
  182. await block.enterNext()
  183. expect(await block.indent()).toBe(true)
  184. await block.mustFill('line3')
  185. await block.enterNext()
  186. expect(await block.unindent()).toBe(true)
  187. expect(await block.unindent()).toBe(true)
  188. expect(await block.unindent()).toBe(false) // already at the first level
  189. await block.waitForBlocks(5)
  190. // See-also: #9354
  191. await block.enterNext()
  192. await block.mustType('/template')
  193. await page.click('[title="Insert a created template here"]')
  194. // type to search template name
  195. await page.keyboard.type(randomTemplate.substring(0, 3), { delay: 100 })
  196. const popupMenuItem = page.locator('.absolute >> text=' + randomTemplate)
  197. await popupMenuItem.waitFor({ timeout: 2000 }) // wait for template search
  198. await popupMenuItem.click()
  199. await block.waitForBlocks(9)
  200. await block.clickNext()
  201. await block.mustType('/template')
  202. await page.click('[title="Insert a created template here"]')
  203. // type to search template name
  204. await page.keyboard.type(randomTemplate.substring(0, 3), { delay: 100 })
  205. await popupMenuItem.waitFor({ timeout: 2000 }) // wait for template search
  206. await popupMenuItem.click()
  207. await block.waitForBlocks(13) // 9 + 4
  208. })
  209. test('auto completion square brackets', async ({ page, block }) => {
  210. await createRandomPage(page)
  211. // In this test, `type` is unused instead of `fill`, to allow for auto-completion.
  212. // [[]]
  213. await block.mustType('This is a [', { toBe: 'This is a []' })
  214. await block.mustType('[', { toBe: 'This is a [[]]' })
  215. // wait for search popup
  216. await page.waitForSelector('text="Search for a page"')
  217. // re-enter edit mode
  218. await page.press('textarea >> nth=0', 'Escape')
  219. await page.click('.ls-block >> nth=-1')
  220. await page.waitForSelector('textarea >> nth=0', { state: 'visible' })
  221. // #3253
  222. await page.press('textarea >> nth=0', 'ArrowLeft')
  223. await page.press('textarea >> nth=0', 'ArrowLeft')
  224. await page.press('textarea >> nth=0', 'Enter')
  225. await page.waitForSelector('text="Search for a page"', { state: 'visible' })
  226. // type more `]`s
  227. await page.type('textarea >> nth=0', ']')
  228. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]')
  229. await page.type('textarea >> nth=0', ']')
  230. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]')
  231. await page.type('textarea >> nth=0', ']')
  232. expect(await page.inputValue('textarea >> nth=0')).toBe('This is a [[]]]')
  233. })
  234. test('auto completion and auto pair', async ({ page, block }) => {
  235. await createRandomPage(page)
  236. await block.mustFill('Auto-completion test')
  237. await block.enterNext()
  238. // {{
  239. await block.mustType('type {{', { toBe: 'type {{}}' })
  240. await page.waitForTimeout(100);
  241. // ((
  242. await block.clickNext()
  243. await block.mustType('type (', { toBe: 'type ()' })
  244. await block.mustType('(', { toBe: 'type (())' })
  245. await block.escapeEditing() // escape any popup from `(())`
  246. // [[ #3251
  247. await block.clickNext()
  248. await block.mustType('type [', { toBe: 'type []' })
  249. await block.mustType('[', { toBe: 'type [[]]' })
  250. await block.escapeEditing() // escape any popup from `[[]]`
  251. // ``
  252. await block.clickNext()
  253. await block.mustType('type `', { toBe: 'type ``' })
  254. await block.mustType('code here', { toBe: 'type `code here`' })
  255. })
  256. test('invalid page props #3944', async ({ page, block }) => {
  257. await createRandomPage(page)
  258. await block.mustFill('public:: true\nsize:: 65535')
  259. await page.press('textarea >> nth=0', 'Enter')
  260. // Force rendering property block
  261. await block.enterNext()
  262. })
  263. test('Scheduled date picker should point to the already specified Date #6985', async({page,block})=>{
  264. await createRandomPage(page)
  265. await block.mustFill('testTask \n SCHEDULED: <2000-05-06 Sat>')
  266. await block.enterNext()
  267. await page.waitForTimeout(500)
  268. await block.escapeEditing()
  269. // Open date picker
  270. await page.click('a.opacity-80')
  271. await page.waitForTimeout(500)
  272. expect(page.locator('text=May 2000')).toBeVisible()
  273. expect(page.locator('td:has-text("6").active')).toBeVisible()
  274. // Close date picker
  275. await page.click('a.opacity-80')
  276. await page.waitForTimeout(500)
  277. })
  278. test('Opening a second datepicker should close the first one #7341', async({page,block})=>{
  279. await createRandomPage(page)
  280. await block.mustFill('testTask \n SCHEDULED: <2000-05-06 Sat>')
  281. await block.enterNext();
  282. await block.mustFill('testTask \n SCHEDULED: <2000-06-07 Wed>')
  283. await block.enterNext();
  284. await page.click('#main-content-container')
  285. // Open date picker
  286. await page.waitForTimeout(500)
  287. await page.click('#main-content-container')
  288. await page.waitForTimeout(500)
  289. await page.click('a:has-text("2000-06-07 Wed").opacity-80')
  290. await page.waitForTimeout(50)
  291. await page.click('a:has-text("2000-05-06 Sat").opacity-80')
  292. await page.waitForTimeout(50)
  293. expect(page.locator('text=May 2000')).toBeVisible()
  294. expect(page.locator('td:has-text("6").active')).toBeVisible()
  295. expect(page.locator('text=June 2000')).not.toBeVisible()
  296. expect(page.locator('td:has-text("7").active')).not.toBeVisible()
  297. // Close date picker
  298. await page.click('a:has-text("2000-05-06 Sat").opacity-80')
  299. })