quill-table-up 3.1.2 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +7 -0
  2. package/dist/index.css +1 -1
  3. package/dist/index.d.ts +168 -146
  4. package/dist/index.js +47 -47
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.umd.js +52 -52
  7. package/dist/index.umd.js.map +1 -1
  8. package/package.json +22 -24
  9. package/src/__tests__/e2e/custom-creator.test.ts +44 -44
  10. package/src/__tests__/e2e/editor-page.ts +77 -77
  11. package/src/__tests__/e2e/table-align.test.ts +104 -104
  12. package/src/__tests__/e2e/table-blots.test.ts +169 -169
  13. package/src/__tests__/e2e/table-caption.test.ts +134 -134
  14. package/src/__tests__/e2e/table-clipboard.test.ts +20 -20
  15. package/src/__tests__/e2e/table-hack.test.ts +151 -151
  16. package/src/__tests__/e2e/table-keyboard-handler.test.ts +12 -3
  17. package/src/__tests__/e2e/table-menu.test.ts +172 -172
  18. package/src/__tests__/e2e/table-resize.test.ts +654 -9
  19. package/src/__tests__/e2e/table-scrollbar.test.ts +144 -144
  20. package/src/__tests__/e2e/table-selection.test.ts +563 -563
  21. package/src/__tests__/e2e/types.d.ts +7 -7
  22. package/src/__tests__/e2e/utils.ts +52 -52
  23. package/src/__tests__/unit/table-blots.test.ts +720 -720
  24. package/src/__tests__/unit/table-caption.test.ts +234 -234
  25. package/src/__tests__/unit/table-cell-merge.test.ts +724 -724
  26. package/src/__tests__/unit/table-clipboard.test.ts +2176 -2176
  27. package/src/__tests__/unit/table-hack.test.ts +1014 -1014
  28. package/src/__tests__/unit/table-insert.test.ts +926 -926
  29. package/src/__tests__/unit/table-redo-undo.test.ts +2429 -2429
  30. package/src/__tests__/unit/table-remove.test.ts +343 -343
  31. package/src/__tests__/unit/utils.test-d.ts +49 -49
  32. package/src/__tests__/unit/utils.test.ts +711 -711
  33. package/src/__tests__/unit/utils.ts +307 -307
  34. package/src/__tests__/unit/vitest.d.ts +14 -14
  35. package/src/formats/container-format.ts +107 -107
  36. package/src/formats/overrides/block-embed.ts +72 -72
  37. package/src/formats/overrides/block.ts +95 -95
  38. package/src/formats/overrides/index.ts +3 -3
  39. package/src/formats/overrides/scroll.ts +70 -70
  40. package/src/formats/table-body-format.ts +52 -52
  41. package/src/formats/table-caption-format.ts +116 -116
  42. package/src/formats/table-cell-format.ts +304 -304
  43. package/src/formats/table-cell-inner-format.ts +403 -398
  44. package/src/formats/table-colgroup-format.ts +136 -136
  45. package/src/formats/table-foot-format.ts +7 -7
  46. package/src/formats/table-head-format.ts +7 -7
  47. package/src/formats/table-main-format.ts +1 -1
  48. package/src/formats/table-row-format.ts +218 -210
  49. package/src/formats/utils.ts +6 -6
  50. package/src/index.ts +19 -19
  51. package/src/modules/index.ts +7 -7
  52. package/src/modules/table-align.ts +131 -131
  53. package/src/modules/table-clipboard/table-clipboard.ts +6 -8
  54. package/src/modules/table-dom-selector.ts +33 -33
  55. package/src/modules/table-menu/constants.ts +223 -223
  56. package/src/modules/table-menu/index.ts +4 -4
  57. package/src/modules/table-menu/table-menu-common.ts +330 -329
  58. package/src/modules/table-menu/table-menu-contextmenu.ts +111 -118
  59. package/src/modules/table-menu/table-menu-select.ts +96 -94
  60. package/src/modules/table-resize/index.ts +5 -5
  61. package/src/modules/table-resize/table-resize-box.ts +714 -363
  62. package/src/modules/table-resize/table-resize-common.ts +246 -382
  63. package/src/modules/table-resize/table-resize-drag.ts +241 -0
  64. package/src/modules/table-resize/table-resize-line.ts +244 -182
  65. package/src/modules/table-resize/table-resize-scale.ts +174 -173
  66. package/src/modules/table-resize/utils.ts +84 -3
  67. package/src/modules/table-scrollbar.ts +292 -292
  68. package/src/modules/table-selection.ts +613 -669
  69. package/src/style/button.less +45 -45
  70. package/src/style/color-picker.less +136 -136
  71. package/src/style/dialog.less +53 -53
  72. package/src/style/functions.less +9 -9
  73. package/src/style/index.less +120 -120
  74. package/src/style/input.less +64 -64
  75. package/src/style/select-box.less +52 -52
  76. package/src/style/table-creator.less +56 -56
  77. package/src/style/table-menu.less +125 -125
  78. package/src/style/table-resize-scale.less +31 -31
  79. package/src/style/table-resize.less +249 -202
  80. package/src/style/table-scrollbar.less +49 -49
  81. package/src/style/table-selection.less +23 -23
  82. package/src/style/tooltip.less +19 -19
  83. package/src/style/variables.less +1 -1
  84. package/src/svg/arrow-up-down.svg +11 -11
  85. package/src/svg/convert-cell.svg +7 -7
  86. package/src/table-up.ts +1360 -1360
  87. package/src/types.d.ts +4 -4
  88. package/src/utils/bem.ts +23 -23
  89. package/src/utils/blot-helper.ts +101 -105
  90. package/src/utils/color.ts +109 -109
  91. package/src/utils/components/button.ts +22 -22
  92. package/src/utils/components/color-picker.ts +236 -236
  93. package/src/utils/components/dialog.ts +83 -41
  94. package/src/utils/components/index.ts +6 -6
  95. package/src/utils/components/input.ts +74 -74
  96. package/src/utils/components/table/creator.ts +89 -89
  97. package/src/utils/components/table/index.ts +2 -2
  98. package/src/utils/components/table/select-box.ts +78 -78
  99. package/src/utils/components/tooltip.ts +179 -189
  100. package/src/utils/constants.ts +125 -124
  101. package/src/utils/drag-helper.ts +112 -0
  102. package/src/utils/index.ts +15 -14
  103. package/src/utils/is.ts +9 -9
  104. package/src/utils/position.ts +60 -60
  105. package/src/utils/resize-observer-helper.ts +47 -47
  106. package/src/utils/scroll.ts +145 -47
  107. package/src/utils/style-helper.ts +47 -47
  108. package/src/utils/transformer.ts +10 -10
  109. package/src/utils/transition-event-helper.ts +8 -8
  110. package/src/utils/types.ts +156 -157
  111. package/src/utils/utils.ts +12 -12
@@ -1,134 +1,134 @@
1
- import { expect, test } from '@playwright/test';
2
- import { extendTest } from './utils';
3
-
4
- test.beforeEach(async ({ page }) => {
5
- await page.goto('http://127.0.0.1:5500/docs/test.html');
6
- page.locator('.ql-container.ql-snow');
7
- });
8
-
9
- extendTest('tableCaption switch visiable', async ({ page, editorPage }) => {
10
- editorPage.index = 0;
11
- await editorPage.setContents([
12
- { insert: '\nTable Caption' },
13
- { attributes: { 'table-up-caption': { tableId: '1', side: 'top' } }, insert: '\n' },
14
- { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
15
- { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
16
- { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
17
- { insert: '1' },
18
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
19
- { insert: '2' },
20
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
21
- { insert: '3' },
22
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
23
- { insert: '4' },
24
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
25
- { insert: '5' },
26
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
27
- { insert: '6' },
28
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
29
- { insert: '7' },
30
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
31
- { insert: '8' },
32
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
33
- { insert: '9' },
34
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
35
- { insert: '\n' },
36
- ]);
37
- await page.waitForTimeout(1000);
38
-
39
- const captionSwitch = page.locator('#editor1 .ql-editor .ql-table caption.ql-table-caption .ql-table-caption--switch').nth(0);
40
- await expect(captionSwitch).not.toBeVisible();
41
-
42
- const boundingBox = (await page.locator('#editor1 .ql-editor .ql-table caption.ql-table-caption').boundingBox())!;
43
- expect(boundingBox).not.toBeNull();
44
- await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2);
45
- await expect(captionSwitch).toBeVisible();
46
- await page.mouse.move(0, 0);
47
- await expect(captionSwitch).not.toBeVisible();
48
- });
49
-
50
- extendTest('text tableCaption insert', async ({ page, editorPage }) => {
51
- editorPage.index = 0;
52
- await editorPage.setContents([
53
- { insert: '\n' },
54
- { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
55
- { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
56
- { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
57
- { insert: { 'table-up-col': { tableId: '1', colId: '4', full: false, width: 100 } } },
58
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
59
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
60
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
61
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
62
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
63
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
64
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
65
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
66
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
67
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
68
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
69
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
70
- { insert: '\n' },
71
- ]);
72
- await page.waitForTimeout(1000);
73
-
74
- const cell = page.locator('#editor1 .ql-editor .ql-table td').nth(0);
75
- await cell.click();
76
- await expect(page.locator('#container1 .table-up-toolbox .table-up-selection .table-up-selection__line')).toBeVisible();
77
- await cell.click({ button: 'right' });
78
- await page.locator('.table-up-menu.is-contextmenu .table-up-menu__item').filter({ hasText: 'Insert table caption' }).first().click();
79
-
80
- const caption = page.locator('#container1 .ql-table caption');
81
- const tbody = page.locator('#container1 .ql-table tbody');
82
- await expect(caption).toBeVisible();
83
- expect(await caption.textContent()).toContain('Table Caption');
84
- const captionBox = (await caption.boundingBox())!;
85
- const tbodyBox = (await tbody.boundingBox())!;
86
- expect(captionBox).not.toBeNull();
87
- expect(tbodyBox).not.toBeNull();
88
- expect(captionBox.y).toBeLessThan(tbodyBox.y);
89
- });
90
-
91
- extendTest('tableCaption side switch', async ({ page, editorPage }) => {
92
- editorPage.index = 0;
93
- await editorPage.setContents([
94
- { insert: '\nTable Caption' },
95
- { attributes: { 'table-up-caption': { tableId: '1', side: 'top' } }, insert: '\n' },
96
- { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
97
- { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
98
- { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
99
- { insert: '1' },
100
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
101
- { insert: '2' },
102
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
103
- { insert: '3' },
104
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
105
- { insert: '4' },
106
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
107
- { insert: '5' },
108
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
109
- { insert: '6' },
110
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
111
- { insert: '7' },
112
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
113
- { insert: '8' },
114
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
115
- { insert: '9' },
116
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
117
- { insert: '\n' },
118
- ]);
119
-
120
- const captionUINode = page.locator('#container1 .ql-table caption .ql-ui');
121
- expect(captionUINode).not.toBeNull();
122
-
123
- const caption = page.locator('#container1 .ql-table caption');
124
- const boundingBox = (await caption.boundingBox())!;
125
- expect(caption).not.toBeNull();
126
- await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2);
127
- await expect(captionUINode).toBeVisible();
128
- await page.mouse.move(0, 0);
129
- await expect(captionUINode).not.toBeVisible();
130
-
131
- editorPage.enable(false);
132
- await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2);
133
- await expect(captionUINode).not.toBeVisible();
134
- });
1
+ import { expect, test } from '@playwright/test';
2
+ import { extendTest } from './utils';
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await page.goto('http://127.0.0.1:5500/docs/test.html');
6
+ page.locator('.ql-container.ql-snow');
7
+ });
8
+
9
+ extendTest('tableCaption switch visiable', async ({ page, editorPage }) => {
10
+ editorPage.index = 0;
11
+ await editorPage.setContents([
12
+ { insert: '\nTable Caption' },
13
+ { attributes: { 'table-up-caption': { tableId: '1', side: 'top' } }, insert: '\n' },
14
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
15
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
16
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
17
+ { insert: '1' },
18
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
19
+ { insert: '2' },
20
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
21
+ { insert: '3' },
22
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
23
+ { insert: '4' },
24
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
25
+ { insert: '5' },
26
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
27
+ { insert: '6' },
28
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
29
+ { insert: '7' },
30
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
31
+ { insert: '8' },
32
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
33
+ { insert: '9' },
34
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
35
+ { insert: '\n' },
36
+ ]);
37
+ await page.waitForTimeout(1000);
38
+
39
+ const captionSwitch = page.locator('#editor1 .ql-editor .ql-table caption.ql-table-caption .ql-table-caption--switch').nth(0);
40
+ await expect(captionSwitch).not.toBeVisible();
41
+
42
+ const boundingBox = (await page.locator('#editor1 .ql-editor .ql-table caption.ql-table-caption').boundingBox())!;
43
+ expect(boundingBox).not.toBeNull();
44
+ await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2);
45
+ await expect(captionSwitch).toBeVisible();
46
+ await page.mouse.move(0, 0);
47
+ await expect(captionSwitch).not.toBeVisible();
48
+ });
49
+
50
+ extendTest('text tableCaption insert', async ({ page, editorPage }) => {
51
+ editorPage.index = 0;
52
+ await editorPage.setContents([
53
+ { insert: '\n' },
54
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
55
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
56
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
57
+ { insert: { 'table-up-col': { tableId: '1', colId: '4', full: false, width: 100 } } },
58
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
59
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
60
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
61
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
62
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
63
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
64
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
65
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
66
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
67
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
68
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
69
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '4', rowspan: 1, colspan: 1 } }, insert: '\n' },
70
+ { insert: '\n' },
71
+ ]);
72
+ await page.waitForTimeout(1000);
73
+
74
+ const cell = page.locator('#editor1 .ql-editor .ql-table td').nth(0);
75
+ await cell.click();
76
+ await expect(page.locator('#container1 .table-up-toolbox .table-up-selection .table-up-selection__line')).toBeVisible();
77
+ await cell.click({ button: 'right' });
78
+ await page.locator('.table-up-menu.is-contextmenu .table-up-menu__item').filter({ hasText: 'Insert table caption' }).first().click();
79
+
80
+ const caption = page.locator('#container1 .ql-table caption');
81
+ const tbody = page.locator('#container1 .ql-table tbody');
82
+ await expect(caption).toBeVisible();
83
+ expect(await caption.textContent()).toContain('Table Caption');
84
+ const captionBox = (await caption.boundingBox())!;
85
+ const tbodyBox = (await tbody.boundingBox())!;
86
+ expect(captionBox).not.toBeNull();
87
+ expect(tbodyBox).not.toBeNull();
88
+ expect(captionBox.y).toBeLessThan(tbodyBox.y);
89
+ });
90
+
91
+ extendTest('tableCaption side switch', async ({ page, editorPage }) => {
92
+ editorPage.index = 0;
93
+ await editorPage.setContents([
94
+ { insert: '\nTable Caption' },
95
+ { attributes: { 'table-up-caption': { tableId: '1', side: 'top' } }, insert: '\n' },
96
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
97
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
98
+ { insert: { 'table-up-col': { tableId: '1', colId: '3', full: false, width: 100 } } },
99
+ { insert: '1' },
100
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
101
+ { insert: '2' },
102
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
103
+ { insert: '3' },
104
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
105
+ { insert: '4' },
106
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
107
+ { insert: '5' },
108
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
109
+ { insert: '6' },
110
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
111
+ { insert: '7' },
112
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
113
+ { insert: '8' },
114
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
115
+ { insert: '9' },
116
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '3', colId: '3', rowspan: 1, colspan: 1 } }, insert: '\n' },
117
+ { insert: '\n' },
118
+ ]);
119
+
120
+ const captionUINode = page.locator('#container1 .ql-table caption .ql-ui');
121
+ expect(captionUINode).not.toBeNull();
122
+
123
+ const caption = page.locator('#container1 .ql-table caption');
124
+ const boundingBox = (await caption.boundingBox())!;
125
+ expect(caption).not.toBeNull();
126
+ await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2);
127
+ await expect(captionUINode).toBeVisible();
128
+ await page.mouse.move(0, 0);
129
+ await expect(captionUINode).not.toBeVisible();
130
+
131
+ editorPage.enable(false);
132
+ await page.mouse.move(boundingBox.x + boundingBox.width / 2, boundingBox.y + boundingBox.height / 2);
133
+ await expect(captionUINode).not.toBeVisible();
134
+ });
@@ -1,20 +1,20 @@
1
- import { expect, test } from '@playwright/test';
2
- import { extendTest } from './utils';
3
-
4
- test.beforeEach(async ({ page }) => {
5
- await page.goto('http://127.0.0.1:5500/docs/test.html');
6
- page.locator('.ql-container.ql-snow');
7
- });
8
-
9
- extendTest('clipboard convert cell border style with css properties', async ({ page, editorPage }) => {
10
- editorPage.index = 0;
11
- await editorPage.html(`<table><tbody><tr><td style="border-color: rgb(var(--color-red));">123</td></tr></tbody></table>`);
12
-
13
- const tdBorderCssText = await page.locator('#container1 .ql-table-wrapper td').nth(0).evaluate(el => el.style.cssText);
14
- expect(tdBorderCssText).toBe('border-color: rgb(var(--color-red));');
15
-
16
- await editorPage.html(`<table><tbody><tr><td style="background-color: rgb(var(--color-red));">123</td></tr></tbody></table>`);
17
-
18
- const tdBgCssText = await page.locator('#container1 .ql-table-wrapper td').nth(0).evaluate(el => el.style.cssText);
19
- expect(tdBgCssText).toBe('background-color: rgb(var(--color-red));');
20
- });
1
+ import { expect, test } from '@playwright/test';
2
+ import { extendTest } from './utils';
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await page.goto('http://127.0.0.1:5500/docs/test.html');
6
+ page.locator('.ql-container.ql-snow');
7
+ });
8
+
9
+ extendTest('clipboard convert cell border style with css properties', async ({ page, editorPage }) => {
10
+ editorPage.index = 0;
11
+ await editorPage.html(`<table><tbody><tr><td style="border-color: rgb(var(--color-red));">123</td></tr></tbody></table>`);
12
+
13
+ const tdBorderCssText = await page.locator('#container1 .ql-table-wrapper td').nth(0).evaluate(el => el.style.cssText);
14
+ expect(tdBorderCssText).toBe('border-color: rgb(var(--color-red));');
15
+
16
+ await editorPage.html(`<table><tbody><tr><td style="background-color: rgb(var(--color-red));">123</td></tr></tbody></table>`);
17
+
18
+ const tdBgCssText = await page.locator('#container1 .ql-table-wrapper td').nth(0).evaluate(el => el.style.cssText);
19
+ expect(tdBgCssText).toBe('background-color: rgb(var(--color-red));');
20
+ });
@@ -1,151 +1,151 @@
1
- import { expect, test } from '@playwright/test';
2
- import { extendTest } from './utils';
3
-
4
- test.beforeEach(async ({ page }) => {
5
- await page.goto('http://127.0.0.1:5500/docs/test.html');
6
- page.locator('.ql-container.ql-snow');
7
- });
8
-
9
- extendTest('clean handler should not clean insert text format', async ({ page, editorPage }) => {
10
- editorPage.index = 0;
11
- await editorPage.setContents([
12
- { insert: '\n' },
13
- { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
14
- { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
15
- { insert: '12345', attributes: { bold: true } },
16
- { attributes: { 'list': 'bullet', 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
17
- { insert: '12345', attributes: { bold: true } },
18
- { attributes: { 'list': 'bullet', 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
19
- { insert: '22345', attributes: { bold: true } },
20
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
21
- { insert: '3' },
22
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
23
- { insert: '4' },
24
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
25
- { insert: '\n' },
26
- ]);
27
- await editorPage.setSelection(8, 0);
28
-
29
- await page.locator('#container1 .ql-toolbar .ql-clean').click();
30
- await editorPage.focus();
31
- await page.keyboard.type('text');
32
-
33
- const delta = await editorPage.getContents();
34
- const contents = [
35
- { insert: '\n' },
36
- { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
37
- { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
38
- { insert: '12345', attributes: { bold: true } },
39
- { insert: 'text' },
40
- { attributes: { 'list': 'bullet', 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
41
- { insert: '12345', attributes: { bold: true } },
42
- { attributes: { 'list': 'bullet', 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
43
- { insert: '22345', attributes: { bold: true } },
44
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
45
- { insert: '3' },
46
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
47
- { insert: '4' },
48
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
49
- { insert: '\n' },
50
- ];
51
- for (const [i, op] of delta.ops.entries()) {
52
- expect(op).toStrictEqual(contents[i]);
53
- }
54
- });
55
-
56
- extendTest('clean handler should not keep table format when have two empty line after block format(like header)', async ({ page, editorPage }) => {
57
- editorPage.index = 0;
58
- await editorPage.setContents([
59
- { insert: '\n' },
60
- { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
61
- { insert: 'header' },
62
- { attributes: { 'header': 1, 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
63
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n\n' },
64
- { insert: '\n' },
65
- ]);
66
-
67
- await editorPage.setSelection(0, 11);
68
- await page.locator('#container1 .ql-toolbar .ql-clean').click();
69
- const delta = await editorPage.getContents();
70
- const contents = [{ insert: '\nheader\n\n\n\n' }];
71
- for (const [i, op] of delta.ops.entries()) {
72
- expect(op).toStrictEqual(contents[i]);
73
- }
74
- expect(await editorPage.getSelection()).toEqual({ index: 0, length: 10 });
75
- });
76
-
77
- extendTest('toolbar item handler should trigger source USER', async ({ page, editorPage }) => {
78
- editorPage.index = 0;
79
- await editorPage.setContents([
80
- { insert: '\n' },
81
- { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
82
- { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
83
- { insert: '1' },
84
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
85
- { insert: '2' },
86
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
87
- { insert: '3' },
88
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
89
- { insert: '4' },
90
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
91
- { insert: '\n' },
92
- ]);
93
-
94
- const textChangePromise = page.evaluate(() => {
95
- return new Promise<string>((resolve) => {
96
- window.quills[0].on('text-change', (delta, oldDelta, source) => {
97
- if (source === 'user') {
98
- resolve(source);
99
- }
100
- });
101
- });
102
- });
103
-
104
- await editorPage.setSelection(3, 1);
105
- await page.locator('#container1 .ql-toolbar .ql-bold').click();
106
- const result = await textChangePromise;
107
- expect(result).toBe('user');
108
- });
109
-
110
- extendTest('getSemanticHTML should not effect editable when manual copy or cut', async ({ page, editorPage }) => {
111
- editorPage.index = 0;
112
- await editorPage.setContents([
113
- { insert: '\nTable Caption' },
114
- { attributes: { 'table-up-caption': { tableId: '1', side: 'top' } }, insert: '\n' },
115
- { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
116
- { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
117
- { insert: '1' },
118
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
119
- { insert: '2' },
120
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
121
- { insert: '3' },
122
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
123
- { insert: '4' },
124
- { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
125
- { insert: '\n' },
126
- ]);
127
- const tableCaption = page.locator('#container1 .ql-table .ql-table-caption');
128
- const td = page.locator('#container1 .ql-table td .ql-table-cell-inner').nth(0);
129
- await expect(tableCaption).toHaveAttribute('contenteditable', 'true');
130
- await expect(td).toHaveAttribute('contenteditable', 'true');
131
-
132
- await editorPage.setSelection(2, 4);
133
- await page.keyboard.press('Control+C');
134
- await expect(tableCaption).toHaveAttribute('contenteditable', 'true');
135
- await expect(tableCaption).toContainText('Table Caption');
136
-
137
- await editorPage.setSelection(2, 4);
138
- await page.keyboard.press('Control+X');
139
- await expect(tableCaption).toHaveAttribute('contenteditable', 'true');
140
- await expect(tableCaption).toContainText('T Caption');
141
-
142
- await editorPage.setSelection(14, 1);
143
- await page.keyboard.press('Control+C');
144
- await expect(td).toHaveAttribute('contenteditable', 'true');
145
- await expect(td).toContainText('1');
146
-
147
- await editorPage.setSelection(14, 1);
148
- await page.keyboard.press('Control+X');
149
- await expect(td).toHaveAttribute('contenteditable', 'true');
150
- await expect(td).toContainText('');
151
- });
1
+ import { expect, test } from '@playwright/test';
2
+ import { extendTest } from './utils';
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await page.goto('http://127.0.0.1:5500/docs/test.html');
6
+ page.locator('.ql-container.ql-snow');
7
+ });
8
+
9
+ extendTest('clean handler should not clean insert text format', async ({ page, editorPage }) => {
10
+ editorPage.index = 0;
11
+ await editorPage.setContents([
12
+ { insert: '\n' },
13
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
14
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
15
+ { insert: '12345', attributes: { bold: true } },
16
+ { attributes: { 'list': 'bullet', 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
17
+ { insert: '12345', attributes: { bold: true } },
18
+ { attributes: { 'list': 'bullet', 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
19
+ { insert: '22345', attributes: { bold: true } },
20
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
21
+ { insert: '3' },
22
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
23
+ { insert: '4' },
24
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
25
+ { insert: '\n' },
26
+ ]);
27
+ await editorPage.setSelection(8, 0);
28
+
29
+ await page.locator('#container1 .ql-toolbar .ql-clean').click();
30
+ await editorPage.focus();
31
+ await page.keyboard.type('text');
32
+
33
+ const delta = await editorPage.getContents();
34
+ const contents = [
35
+ { insert: '\n' },
36
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
37
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
38
+ { insert: '12345', attributes: { bold: true } },
39
+ { insert: 'text' },
40
+ { attributes: { 'list': 'bullet', 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
41
+ { insert: '12345', attributes: { bold: true } },
42
+ { attributes: { 'list': 'bullet', 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
43
+ { insert: '22345', attributes: { bold: true } },
44
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
45
+ { insert: '3' },
46
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
47
+ { insert: '4' },
48
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1, tag: 'td', wrapTag: 'tbody' } }, insert: '\n' },
49
+ { insert: '\n' },
50
+ ];
51
+ for (const [i, op] of delta.ops.entries()) {
52
+ expect(op).toStrictEqual(contents[i]);
53
+ }
54
+ });
55
+
56
+ extendTest('clean handler should not keep table format when have two empty line after block format(like header)', async ({ page, editorPage }) => {
57
+ editorPage.index = 0;
58
+ await editorPage.setContents([
59
+ { insert: '\n' },
60
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
61
+ { insert: 'header' },
62
+ { attributes: { 'header': 1, 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
63
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n\n' },
64
+ { insert: '\n' },
65
+ ]);
66
+
67
+ await editorPage.setSelection(0, 11);
68
+ await page.locator('#container1 .ql-toolbar .ql-clean').click();
69
+ const delta = await editorPage.getContents();
70
+ const contents = [{ insert: '\nheader\n\n\n\n' }];
71
+ for (const [i, op] of delta.ops.entries()) {
72
+ expect(op).toStrictEqual(contents[i]);
73
+ }
74
+ expect(await editorPage.getSelection()).toEqual({ index: 0, length: 10 });
75
+ });
76
+
77
+ extendTest('toolbar item handler should trigger source USER', async ({ page, editorPage }) => {
78
+ editorPage.index = 0;
79
+ await editorPage.setContents([
80
+ { insert: '\n' },
81
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
82
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
83
+ { insert: '1' },
84
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
85
+ { insert: '2' },
86
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
87
+ { insert: '3' },
88
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
89
+ { insert: '4' },
90
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
91
+ { insert: '\n' },
92
+ ]);
93
+
94
+ const textChangePromise = page.evaluate(() => {
95
+ return new Promise<string>((resolve) => {
96
+ window.quills[0].on('text-change', (delta, oldDelta, source) => {
97
+ if (source === 'user') {
98
+ resolve(source);
99
+ }
100
+ });
101
+ });
102
+ });
103
+
104
+ await editorPage.setSelection(3, 1);
105
+ await page.locator('#container1 .ql-toolbar .ql-bold').click();
106
+ const result = await textChangePromise;
107
+ expect(result).toBe('user');
108
+ });
109
+
110
+ extendTest('getSemanticHTML should not effect editable when manual copy or cut', async ({ page, editorPage }) => {
111
+ editorPage.index = 0;
112
+ await editorPage.setContents([
113
+ { insert: '\nTable Caption' },
114
+ { attributes: { 'table-up-caption': { tableId: '1', side: 'top' } }, insert: '\n' },
115
+ { insert: { 'table-up-col': { tableId: '1', colId: '1', full: false, width: 100 } } },
116
+ { insert: { 'table-up-col': { tableId: '1', colId: '2', full: false, width: 100 } } },
117
+ { insert: '1' },
118
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
119
+ { insert: '2' },
120
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '1', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
121
+ { insert: '3' },
122
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '1', rowspan: 1, colspan: 1 } }, insert: '\n' },
123
+ { insert: '4' },
124
+ { attributes: { 'table-up-cell-inner': { tableId: '1', rowId: '2', colId: '2', rowspan: 1, colspan: 1 } }, insert: '\n' },
125
+ { insert: '\n' },
126
+ ]);
127
+ const tableCaption = page.locator('#container1 .ql-table .ql-table-caption');
128
+ const td = page.locator('#container1 .ql-table td .ql-table-cell-inner').nth(0);
129
+ await expect(tableCaption).toHaveAttribute('contenteditable', 'true');
130
+ await expect(td).toHaveAttribute('contenteditable', 'true');
131
+
132
+ await editorPage.setSelection(2, 4);
133
+ await page.keyboard.press('Control+C');
134
+ await expect(tableCaption).toHaveAttribute('contenteditable', 'true');
135
+ await expect(tableCaption).toContainText('Table Caption');
136
+
137
+ await editorPage.setSelection(2, 4);
138
+ await page.keyboard.press('Control+X');
139
+ await expect(tableCaption).toHaveAttribute('contenteditable', 'true');
140
+ await expect(tableCaption).toContainText('T Caption');
141
+
142
+ await editorPage.setSelection(14, 1);
143
+ await page.keyboard.press('Control+C');
144
+ await expect(td).toHaveAttribute('contenteditable', 'true');
145
+ await expect(td).toContainText('1');
146
+
147
+ await editorPage.setSelection(14, 1);
148
+ await page.keyboard.press('Control+X');
149
+ await expect(td).toHaveAttribute('contenteditable', 'true');
150
+ await expect(td).toContainText('');
151
+ });