table.spec.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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, editFirstBlock, navigateToStartOfBlock, createRandomPage } from '../utils'
  6. test.setTimeout(60000)
  7. const KEY_DELAY = 100
  8. // The following function assumes that the block is currently in edit mode,
  9. // and it just enters a simple table
  10. const inputSimpleTable = async (page) => {
  11. await page.keyboard.type('| Header A | Header B |')
  12. await page.keyboard.press('Shift+Enter')
  13. await page.keyboard.type('| A1 | B1 |')
  14. await page.keyboard.press('Shift+Enter')
  15. await page.keyboard.type('| A2 | B2 |')
  16. await page.keyboard.press('Escape')
  17. await page.waitForTimeout(KEY_DELAY)
  18. }
  19. // The following function does not assume any state, and will prepend the provided lines to the
  20. // first block of the document
  21. const prependPropsToFirstBlock = async (page, block, ...props) => {
  22. await editFirstBlock(page)
  23. await page.waitForTimeout(KEY_DELAY)
  24. await navigateToStartOfBlock(page, block)
  25. await page.waitForTimeout(KEY_DELAY)
  26. for (const prop of props) {
  27. await page.keyboard.type(prop)
  28. await page.waitForTimeout(KEY_DELAY)
  29. await page.keyboard.press('Shift+Enter')
  30. await page.waitForTimeout(KEY_DELAY)
  31. }
  32. await page.keyboard.press('Escape')
  33. await page.waitForTimeout(KEY_DELAY)
  34. }
  35. const setPropInFirstBlock = async (page, block, prop, value) => {
  36. await editFirstBlock(page)
  37. await page.waitForTimeout(KEY_DELAY)
  38. await navigateToStartOfBlock(page, block)
  39. await page.waitForTimeout(KEY_DELAY)
  40. const inputValue = await page.inputValue('textarea >> nth=0')
  41. const match = inputValue.match(new RegExp(`${prop}::(.*)(\n|$)`))
  42. if (!match) {
  43. await page.keyboard.press('Shift+Enter')
  44. await page.waitForTimeout(KEY_DELAY)
  45. await page.keyboard.press('ArrowUp')
  46. await page.waitForTimeout(KEY_DELAY)
  47. await page.keyboard.type(`${prop}:: ${value}`)
  48. // await page.waitForTimeout(1000)
  49. // await page.waitForTimeout(KEY_DELAY)
  50. // await page.keyboard.type(prop + ':: ' + value)
  51. // await page.waitForTimeout(1000)
  52. // await page.keyboard.press('Shift+Enter')
  53. await page.waitForTimeout(KEY_DELAY)
  54. await page.keyboard.press('Escape')
  55. return await page.waitForTimeout(KEY_DELAY)
  56. }
  57. const [propLine, propValue, propTernary] = match
  58. const startIndex = match.index
  59. const endIndex = startIndex + propLine.length - propTernary.length
  60. // Go to the of the prop
  61. for (let i = 0; i < endIndex; i++) {
  62. await page.keyboard.press('ArrowRight')
  63. }
  64. // Delete the value of the prop
  65. for (let i = 0; i < propValue.length; i++) {
  66. await page.keyboard.press('Backspace')
  67. }
  68. // Input the new value of the prop
  69. await page.keyboard.type(" " + value.trim())
  70. await page.waitForTimeout(KEY_DELAY)
  71. await page.keyboard.press('Escape')
  72. return await page.waitForTimeout(KEY_DELAY)
  73. }
  74. test('table can have it\'s version changed via props', async ({ page, block, graphDir }) => {
  75. const pageTitle = await createRandomPage(page)
  76. // create a v1 table
  77. inputSimpleTable(page)
  78. // find and confirm existence of first data cell
  79. await expect(await page.locator('table tbody tr >> nth=0').innerHTML()).toContain('A1</td>')
  80. // change to a version 2 table
  81. await setPropInFirstBlock(page, block, 'logseq.table.version', '2')
  82. // find and confirm existence of first data cell in new format
  83. await expect(await page.getByTestId('v2-table-container').innerHTML()).toContain('A1</div>')
  84. })
  85. test('table can configure logseq.color::', async ({ page, block, graphDir }) => {
  86. const pageTitle = await createRandomPage(page)
  87. // create a v1 table
  88. await page.keyboard.type('logseq.table.version:: 2')
  89. await page.keyboard.press('Shift+Enter')
  90. await inputSimpleTable(page)
  91. // check for default general config
  92. await expect(await page.getByTestId('v2-table-gradient-accent')).not.toBeVisible()
  93. await setPropInFirstBlock(page, block, 'logseq.color', 'red')
  94. // check for gradient accent
  95. await expect(await page.getByTestId('v2-table-gradient-accent')).toBeVisible()
  96. })
  97. test('table can configure logseq.table.hover::', async ({ page, block, graphDir }) => {
  98. const pageTitle = await createRandomPage(page)
  99. // create a v1 table
  100. await page.keyboard.type('logseq.table.version:: 2')
  101. await page.keyboard.press('Shift+Enter')
  102. await inputSimpleTable(page)
  103. await page.waitForTimeout(KEY_DELAY)
  104. await page.getByText('A1', { exact: true }).hover()
  105. await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-quaternary-background-color)]')
  106. await expect(await page.getByText('B1', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  107. await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  108. await expect(await page.getByText('B2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  109. await setPropInFirstBlock(page, block, 'logseq.table.hover', 'row')
  110. await page.waitForTimeout(KEY_DELAY)
  111. await page.getByText('A1', { exact: true }).hover()
  112. await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-quaternary-background-color)]')
  113. await expect(await page.getByText('B1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-tertiary-background-color)]')
  114. await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  115. await expect(await page.getByText('B2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  116. await setPropInFirstBlock(page, block, 'logseq.table.hover', 'col')
  117. await page.waitForTimeout(KEY_DELAY)
  118. await page.getByText('A1', { exact: true }).hover()
  119. await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-quaternary-background-color)]')
  120. await expect(await page.getByText('B1', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  121. await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-tertiary-background-color)]')
  122. await expect(await page.getByText('B2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  123. await setPropInFirstBlock(page, block, 'logseq.table.hover', 'both')
  124. await page.waitForTimeout(KEY_DELAY)
  125. await page.getByText('A1', { exact: true }).hover()
  126. await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-quaternary-background-color)]')
  127. await expect(await page.getByText('B1', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-tertiary-background-color)]')
  128. await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).toContain('bg-[color:var(--ls-tertiary-background-color)]')
  129. await expect(await page.getByText('B2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  130. await setPropInFirstBlock(page, block, 'logseq.table.hover', 'none')
  131. await page.waitForTimeout(KEY_DELAY)
  132. await page.getByText('A1', { exact: true }).hover()
  133. await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-quaternary-background-color)]')
  134. await expect(await page.getByText('B1', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  135. await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  136. await expect(await page.getByText('B2', { exact: true }).getAttribute('class')).not.toContain('bg-[color:var(--ls-tertiary-background-color)]')
  137. })
  138. test('table can configure logseq.table.headers', async ({ page, block, graphDir }) => {
  139. const pageTitle = await createRandomPage(page)
  140. // create a table
  141. await page.keyboard.type('logseq.table.version:: 2')
  142. await page.keyboard.press('Shift+Enter')
  143. await inputSimpleTable(page)
  144. // Check none (default)
  145. await expect(await page.getByText('Header A', { exact: true })).toBeVisible()
  146. await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("Header A")
  147. // Check none (explicit)
  148. await setPropInFirstBlock(page, block, 'logseq.table.headers', 'none')
  149. await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("Header A")
  150. // Check uppercase
  151. await setPropInFirstBlock(page, block, 'logseq.table.headers', 'uppercase')
  152. await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("HEADER A")
  153. // Check lowercase
  154. await setPropInFirstBlock(page, block, 'logseq.table.headers', 'lowercase')
  155. await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("header a")
  156. // Check capitalize
  157. await setPropInFirstBlock(page, block, 'logseq.table.headers', 'capitalize')
  158. await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("Header A")
  159. // Check capitalize-first
  160. await setPropInFirstBlock(page, block, 'logseq.table.headers', 'capitalize-first')
  161. await expect(await page.getByText('Header A', { exact: true }).innerText()).toEqual("Header a")
  162. })
  163. test('table can configure logseq.table.borders', async ({ page, block, graphDir }) => {
  164. const pageTitle = await createRandomPage(page)
  165. // create a table
  166. await page.keyboard.type('logseq.table.version:: 2')
  167. await page.keyboard.press('Shift+Enter')
  168. await inputSimpleTable(page)
  169. // Check true (default)
  170. await expect(await page.getByTestId('v2-table-container')).toHaveCSS("gap", /^[1-9].*/)
  171. // Check true (explicit)
  172. await setPropInFirstBlock(page, block, 'logseq.table.borders', 'true')
  173. await expect(await page.getByTestId('v2-table-container')).toHaveCSS("gap", /^[1-9].*/)
  174. // Check false
  175. await setPropInFirstBlock(page, block, 'logseq.table.borders', 'false')
  176. await expect(await page.getByTestId('v2-table-container')).not.toHaveCSS("gap", /^[1-9].*/)
  177. })
  178. test('table can configure logseq.table.stripes', async ({ page, block, graphDir }) => {
  179. const pageTitle = await createRandomPage(page)
  180. // create a table
  181. await page.keyboard.type('logseq.table.version:: 2')
  182. await page.keyboard.press('Shift+Enter')
  183. await inputSimpleTable(page)
  184. await page.waitForTimeout(KEY_DELAY)
  185. // Check false (default)
  186. await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-primary-background-color)]")
  187. await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-primary-background-color)]")
  188. // Check false (explicit)
  189. await setPropInFirstBlock(page, block, 'logseq.table.stripes', 'false')
  190. await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-primary-background-color)]")
  191. await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-primary-background-color)]")
  192. // Check false
  193. await setPropInFirstBlock(page, block, 'logseq.table.stripes', 'true')
  194. await expect(await page.getByText('A1', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-primary-background-color)]")
  195. await expect(await page.getByText('A2', { exact: true }).getAttribute('class')).toContain("bg-[color:var(--ls-secondary-background-color)]")
  196. })
  197. test('table can configure logseq.table.compact', async ({ page, block, graphDir }) => {
  198. const pageTitle = await createRandomPage(page)
  199. // create a table
  200. await page.keyboard.type('logseq.table.version:: 2')
  201. await page.keyboard.press('Shift+Enter')
  202. await inputSimpleTable(page)
  203. await page.waitForTimeout(KEY_DELAY)
  204. // Check false (default)
  205. const defaultClasses = await page.getByText('A1', { exact: true }).getAttribute('class')
  206. // Check false (explicit)
  207. await setPropInFirstBlock(page, block, 'logseq.table.compact', 'false')
  208. const falseClasses = await page.getByText('A1', { exact: true }).getAttribute('class')
  209. // Check false
  210. await setPropInFirstBlock(page, block, 'logseq.table.compact', 'true')
  211. const trueClasses = await page.getByText('A1', { exact: true }).getAttribute('class')
  212. const getPX = (str) => {
  213. const match = str.match(/px-\[([0-9\.]*)[a-z]*\]/)
  214. return match ? parseFloat(match[1]) : null
  215. }
  216. await expect(getPX(defaultClasses)).toEqual(getPX(falseClasses))
  217. await expect(getPX(defaultClasses)).toBeGreaterThan(getPX(trueClasses))
  218. })
  219. test('table can configure logseq.table.cols::', async ({ page, block, graphDir }) => {
  220. const pageTitle = await createRandomPage(page)
  221. // create a v1 table
  222. await page.keyboard.type('logseq.table.version:: 2')
  223. await page.keyboard.press('Shift+Enter')
  224. await inputSimpleTable(page)
  225. // check for default general config
  226. await expect(await page.getByText('A1', { exact: true })).toBeVisible()
  227. await expect(await page.getByText('B1', { exact: true })).toBeVisible()
  228. await setPropInFirstBlock(page, block, 'logseq.table.cols', 'Header A, Header B')
  229. await expect(await page.getByText('A1', { exact: true })).toBeVisible()
  230. await expect(await page.getByText('B1', { exact: true })).toBeVisible()
  231. await setPropInFirstBlock(page, block, 'logseq.table.cols', 'Header A')
  232. await expect(await page.getByText('A1', { exact: true })).toBeVisible()
  233. await expect(await page.getByText('B1', { exact: true })).not.toBeVisible()
  234. await setPropInFirstBlock(page, block, 'logseq.table.cols', 'Header B')
  235. await expect(await page.getByText('A1', { exact: true })).not.toBeVisible()
  236. await expect(await page.getByText('B1', { exact: true })).toBeVisible()
  237. })