@atlaskit/editor-plugin-table 0.0.5 → 0.0.7

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 (63) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/plugins/table/commands-with-analytics.js +6 -0
  3. package/dist/cjs/plugins/table/event-handlers.js +7 -6
  4. package/dist/cjs/plugins/table/nodeviews/tableCell.js +4 -4
  5. package/dist/cjs/plugins/table/pm-plugins/table-resizing/utils/column-state.js +1 -1
  6. package/dist/cjs/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +8 -3
  7. package/dist/cjs/plugins/table/utils/column-controls.js +1 -1
  8. package/dist/cjs/version.json +1 -1
  9. package/dist/es2019/plugins/table/commands-with-analytics.js +6 -0
  10. package/dist/es2019/plugins/table/event-handlers.js +8 -7
  11. package/dist/es2019/plugins/table/nodeviews/tableCell.js +3 -4
  12. package/dist/es2019/plugins/table/pm-plugins/table-resizing/utils/column-state.js +1 -1
  13. package/dist/es2019/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +8 -3
  14. package/dist/es2019/plugins/table/utils/column-controls.js +1 -1
  15. package/dist/es2019/version.json +1 -1
  16. package/dist/esm/plugins/table/commands-with-analytics.js +6 -0
  17. package/dist/esm/plugins/table/event-handlers.js +8 -7
  18. package/dist/esm/plugins/table/nodeviews/tableCell.js +3 -4
  19. package/dist/esm/plugins/table/pm-plugins/table-resizing/utils/column-state.js +1 -1
  20. package/dist/esm/plugins/table/pm-plugins/table-resizing/utils/resize-logic.js +8 -3
  21. package/dist/esm/plugins/table/utils/column-controls.js +1 -1
  22. package/dist/esm/version.json +1 -1
  23. package/package.json +9 -7
  24. package/report.api.md +13 -6
  25. package/src/__tests__/unit/analytics.ts +737 -0
  26. package/src/__tests__/unit/collab.ts +76 -0
  27. package/src/__tests__/unit/commands/sort.ts +230 -0
  28. package/src/__tests__/unit/copy-paste.ts +686 -0
  29. package/src/__tests__/unit/event-handlers/index.ts +106 -0
  30. package/src/__tests__/unit/event-handlers.ts +202 -0
  31. package/src/__tests__/unit/fix-tables.ts +156 -0
  32. package/src/__tests__/unit/floating-toolbar.ts +95 -0
  33. package/src/__tests__/unit/handlers.ts +81 -0
  34. package/src/__tests__/unit/hover-selection.ts +277 -0
  35. package/src/__tests__/unit/index-with-fake-timers.ts +106 -0
  36. package/src/__tests__/unit/index.ts +986 -0
  37. package/src/__tests__/unit/keymap.ts +602 -0
  38. package/src/__tests__/unit/layout.ts +196 -0
  39. package/src/__tests__/unit/nodeviews/cell.ts +167 -0
  40. package/src/__tests__/unit/pm-plugins/table-resizing/utils/resize-state.ts +33 -0
  41. package/src/__tests__/unit/sort-column.ts +512 -0
  42. package/src/__tests__/unit/transforms/delete-columns.ts +499 -0
  43. package/src/__tests__/unit/transforms/delete-rows.ts +557 -0
  44. package/src/__tests__/unit/transforms/merging.ts +374 -0
  45. package/src/__tests__/unit/ui/CornerControls.tsx +80 -0
  46. package/src/__tests__/unit/ui/FloatingContextualButton.tsx +95 -0
  47. package/src/__tests__/unit/ui/FloatingDeleteButton.tsx +175 -0
  48. package/src/__tests__/unit/ui/FloatingInsertButton.tsx +266 -0
  49. package/src/__tests__/unit/ui/RowControls.tsx +301 -0
  50. package/src/__tests__/unit/ui/TableFloatingControls.tsx +93 -0
  51. package/src/__tests__/unit/undo-redo.ts +202 -0
  52. package/src/__tests__/unit/utils/dom.ts +286 -0
  53. package/src/__tests__/unit/utils/nodes.ts +59 -0
  54. package/src/__tests__/unit/utils/row-controls.ts +176 -0
  55. package/src/__tests__/unit/utils/table.ts +93 -0
  56. package/src/__tests__/unit/utils.ts +652 -0
  57. package/src/plugins/table/commands-with-analytics.ts +3 -0
  58. package/src/plugins/table/event-handlers.ts +5 -6
  59. package/src/plugins/table/nodeviews/tableCell.tsx +5 -4
  60. package/src/plugins/table/pm-plugins/table-resizing/utils/column-state.ts +1 -1
  61. package/src/plugins/table/pm-plugins/table-resizing/utils/resize-logic.ts +6 -2
  62. package/src/plugins/table/utils/column-controls.ts +1 -1
  63. package/tmp/api-report-tmp.d.ts +91 -0
@@ -0,0 +1,301 @@
1
+ import { createEditorFactory } from '@atlaskit/editor-test-helpers/create-editor';
2
+ import { mountWithIntl } from '@atlaskit/editor-test-helpers/enzyme';
3
+ import {
4
+ doc,
5
+ p,
6
+ table,
7
+ td,
8
+ tdCursor,
9
+ tdEmpty,
10
+ thEmpty,
11
+ tr,
12
+ DocBuilder,
13
+ } from '@atlaskit/editor-test-helpers/doc-builder';
14
+ import { selectRows } from '@atlaskit/editor-test-helpers/table';
15
+ import { getSelectionRect, selectRow } from '@atlaskit/editor-tables/utils';
16
+ import React from 'react';
17
+ import type { EditorProps } from '@atlaskit/editor-core';
18
+ import { setTextSelection } from '@atlaskit/editor-common/utils';
19
+ import { hoverRows } from '../../../plugins/table/commands';
20
+ import {
21
+ TableCssClassName as ClassName,
22
+ TablePluginState,
23
+ } from '../../../plugins/table/types';
24
+ import TableFloatingControls from '../../../plugins/table/ui/TableFloatingControls';
25
+ import RowControls from '../../../plugins/table/ui/TableFloatingControls/RowControls';
26
+ import { pluginKey } from '../../../plugins/table/pm-plugins/plugin-key';
27
+ import { ReactWrapper } from 'enzyme';
28
+ import tablePlugin from '../../../plugins/table-plugin';
29
+
30
+ const ControlsButton = `.${ClassName.CONTROLS_BUTTON}`;
31
+ const RowControlsButtonWrap = `.${ClassName.ROW_CONTROLS_BUTTON_WRAP}`;
32
+
33
+ describe('RowControls', () => {
34
+ const createEditor = createEditorFactory<TablePluginState>();
35
+ const fakeGetEditorFeatureFlags = jest.fn(() => ({}));
36
+ let floatingControls: ReactWrapper;
37
+ let originalResizeObserver: any;
38
+
39
+ let triggerElementResize = (element: HTMLElement, height: number) => {
40
+ const entries = [
41
+ {
42
+ target: element,
43
+ contentRect: { height },
44
+ },
45
+ ];
46
+ resizeCallback(entries);
47
+ };
48
+ let resizeCallback: (entries: any[]) => {};
49
+
50
+ beforeAll(() => {
51
+ originalResizeObserver = (window as any).ResizeObserver;
52
+ (window as any).ResizeObserver = function resizeObserverMock(
53
+ callback: () => {},
54
+ ) {
55
+ this.disconnect = jest.fn();
56
+ this.observe = jest.fn();
57
+ resizeCallback = callback;
58
+ };
59
+ });
60
+
61
+ afterAll(() => {
62
+ (window as any).ResizeObserver = originalResizeObserver;
63
+ });
64
+
65
+ afterEach(() => {
66
+ if (floatingControls && floatingControls.length) {
67
+ floatingControls.unmount();
68
+ }
69
+ jest.clearAllMocks();
70
+ });
71
+
72
+ const editor = (doc: DocBuilder, props?: EditorProps) => {
73
+ const { featureFlags } = props || {};
74
+ fakeGetEditorFeatureFlags.mockReturnValue(featureFlags || {});
75
+
76
+ return createEditor({
77
+ doc,
78
+ editorProps: {
79
+ allowTables: false,
80
+ dangerouslyAppendPlugins: { __plugins: [tablePlugin()] },
81
+ ...props,
82
+ },
83
+ pluginKey,
84
+ });
85
+ };
86
+
87
+ [1, 2, 3].forEach((row) => {
88
+ describe(`when table has ${row} rows`, () => {
89
+ it(`should render ${row} row header buttons`, () => {
90
+ const rows = [tr(tdCursor)];
91
+ for (let i = 1; i < row; i++) {
92
+ rows.push(tr(tdEmpty));
93
+ }
94
+ const { editorView } = editor(doc(p('text'), table()(...rows)));
95
+ floatingControls = mountWithIntl(
96
+ <TableFloatingControls
97
+ tableRef={document.querySelector('table')!}
98
+ tableActive={true}
99
+ editorView={editorView}
100
+ getEditorFeatureFlags={fakeGetEditorFeatureFlags}
101
+ />,
102
+ );
103
+ expect(floatingControls.find(RowControlsButtonWrap)).toHaveLength(row);
104
+ });
105
+ });
106
+ });
107
+
108
+ it('does not render rowControls if table is not active', () => {
109
+ const { editorView } = editor(doc(p('text'), table()(tr(tdCursor))));
110
+ floatingControls = mountWithIntl(
111
+ <TableFloatingControls
112
+ tableRef={document.querySelector('table')!}
113
+ tableActive={false}
114
+ editorView={editorView}
115
+ getEditorFeatureFlags={fakeGetEditorFeatureFlags}
116
+ />,
117
+ );
118
+ expect(floatingControls.find(RowControlsButtonWrap)).toHaveLength(0);
119
+ });
120
+
121
+ describe('with tableRenderOptimization enabled', () => {
122
+ it('updates rowControls if table height changes', () => {
123
+ const { editorView } = editor(doc(table()(tr(tdCursor))), {
124
+ featureFlags: { tableRenderOptimization: true },
125
+ });
126
+ floatingControls = mountWithIntl(
127
+ <TableFloatingControls
128
+ tableRef={document.querySelector('table')!}
129
+ tableActive={true}
130
+ editorView={editorView}
131
+ getEditorFeatureFlags={fakeGetEditorFeatureFlags}
132
+ />,
133
+ );
134
+ const tableElement = editorView.domAtPos(1).node as HTMLElement;
135
+ triggerElementResize(tableElement, 10);
136
+ expect(floatingControls.state('tableHeight')).toBe(10);
137
+ tableElement.style.height = '100px';
138
+ triggerElementResize(tableElement, 100);
139
+ expect(floatingControls.state('tableHeight')).toBe(100);
140
+ });
141
+ });
142
+
143
+ [0, 1, 2].forEach((row) => {
144
+ describe(`when HeaderButton in row ${row + 1} is clicked`, () => {
145
+ it('should not move the cursor when hovering controls', () => {
146
+ const { editorView, refs } = editor(
147
+ doc(
148
+ table()(
149
+ tr(thEmpty, td({})(p('{nextPos}')), thEmpty),
150
+ tr(tdCursor, tdEmpty, tdEmpty),
151
+ tr(tdEmpty, tdEmpty, tdEmpty),
152
+ ),
153
+ ),
154
+ );
155
+
156
+ floatingControls = mountWithIntl(
157
+ <TableFloatingControls
158
+ tableRef={document.querySelector('table')!}
159
+ tableActive={true}
160
+ editorView={editorView}
161
+ getEditorFeatureFlags={fakeGetEditorFeatureFlags}
162
+ />,
163
+ );
164
+
165
+ // move to header row
166
+ const { nextPos } = refs;
167
+ setTextSelection(editorView, nextPos);
168
+
169
+ // now hover the row
170
+ floatingControls
171
+ .find(RowControlsButtonWrap)
172
+ .at(row)
173
+ .find('button')
174
+ .first()
175
+ .simulate('mouseover');
176
+
177
+ // assert the cursor is still in same position
178
+ expect(editorView.state.selection.$from.pos).toBe(nextPos);
179
+ expect(editorView.state.selection.$to.pos).toBe(nextPos);
180
+
181
+ // release the hover
182
+ floatingControls
183
+ .find(RowControlsButtonWrap)
184
+ .at(row)
185
+ .find('button')
186
+ .first()
187
+ .simulate('mouseout');
188
+
189
+ // assert the cursor is still in same position
190
+ expect(editorView.state.selection.$from.pos).toBe(nextPos);
191
+ expect(editorView.state.selection.$to.pos).toBe(nextPos);
192
+ });
193
+ });
194
+ });
195
+
196
+ it('applies the danger class to the row buttons', () => {
197
+ const { editorView } = editor(
198
+ doc(
199
+ table()(
200
+ tr(thEmpty, td({})(p()), thEmpty),
201
+ tr(tdCursor, tdEmpty, tdEmpty),
202
+ tr(tdEmpty, tdEmpty, tdEmpty),
203
+ ),
204
+ ),
205
+ );
206
+
207
+ floatingControls = mountWithIntl(
208
+ <RowControls
209
+ tableRef={document.querySelector('table')!}
210
+ editorView={editorView}
211
+ hoverRows={(rows, danger) => {
212
+ hoverRows(rows, danger)(editorView.state, editorView.dispatch);
213
+ }}
214
+ hoveredRows={[0, 1]}
215
+ isInDanger={true}
216
+ selectRow={(row) => {
217
+ editorView.dispatch(selectRow(row)(editorView.state.tr));
218
+ }}
219
+ />,
220
+ );
221
+
222
+ floatingControls
223
+ .find(RowControlsButtonWrap)
224
+ .slice(0, 2)
225
+ .forEach((buttonWrap) => {
226
+ expect(buttonWrap.hasClass('danger')).toBe(true);
227
+ });
228
+ });
229
+
230
+ describe('row shift selection', () => {
231
+ it('should shift select rows after the currently selected row', () => {
232
+ const { editorView } = editor(
233
+ doc(
234
+ table()(
235
+ tr(thEmpty, thEmpty, thEmpty),
236
+ tr(tdEmpty, tdEmpty, tdEmpty),
237
+ tr(tdEmpty, tdEmpty, tdEmpty),
238
+ tr(tdEmpty, tdEmpty, tdEmpty),
239
+ ),
240
+ ),
241
+ );
242
+
243
+ selectRows([0])(editorView.state, editorView.dispatch);
244
+ floatingControls = mountWithIntl(
245
+ <RowControls
246
+ tableRef={document.querySelector('table')!}
247
+ editorView={editorView}
248
+ hoverRows={(rows, danger) => {
249
+ hoverRows(rows, danger)(editorView.state, editorView.dispatch);
250
+ }}
251
+ selectRow={(row, expand) => {
252
+ editorView.dispatch(selectRow(row, expand)(editorView.state.tr));
253
+ }}
254
+ />,
255
+ );
256
+
257
+ floatingControls
258
+ .find(ControlsButton)
259
+ .at(2)
260
+ .simulate('click', { shiftKey: true });
261
+
262
+ const rect = getSelectionRect(editorView.state.selection);
263
+ expect(rect).toEqual({ left: 0, top: 0, right: 3, bottom: 3 });
264
+ });
265
+
266
+ it('should shift select row before the currently selected row', () => {
267
+ const { editorView } = editor(
268
+ doc(
269
+ table()(
270
+ tr(thEmpty, thEmpty, thEmpty),
271
+ tr(tdEmpty, tdEmpty, tdEmpty),
272
+ tr(tdEmpty, tdEmpty, tdEmpty),
273
+ tr(tdEmpty, tdEmpty, tdEmpty),
274
+ ),
275
+ ),
276
+ );
277
+
278
+ selectRows([2])(editorView.state, editorView.dispatch);
279
+ floatingControls = mountWithIntl(
280
+ <RowControls
281
+ tableRef={document.querySelector('table')!}
282
+ editorView={editorView}
283
+ hoverRows={(rows, danger) => {
284
+ hoverRows(rows, danger)(editorView.state, editorView.dispatch);
285
+ }}
286
+ selectRow={(row, expand) => {
287
+ editorView.dispatch(selectRow(row, expand)(editorView.state.tr));
288
+ }}
289
+ />,
290
+ );
291
+
292
+ floatingControls
293
+ .find(ControlsButton)
294
+ .first()
295
+ .simulate('click', { shiftKey: true });
296
+
297
+ const rect = getSelectionRect(editorView.state.selection);
298
+ expect(rect).toEqual({ left: 0, top: 0, right: 3, bottom: 3 });
299
+ });
300
+ });
301
+ });
@@ -0,0 +1,93 @@
1
+ import { shallow, mount } from 'enzyme';
2
+ import React from 'react';
3
+
4
+ import {
5
+ createProsemirrorEditorFactory,
6
+ Preset,
7
+ LightEditorPlugin,
8
+ } from '@atlaskit/editor-test-helpers/create-prosemirror-editor';
9
+ import {
10
+ doc,
11
+ p,
12
+ table,
13
+ tr,
14
+ tdEmpty,
15
+ tdCursor,
16
+ DocBuilder,
17
+ } from '@atlaskit/editor-test-helpers/doc-builder';
18
+
19
+ import { TablePluginState } from '../../../plugins/table/types';
20
+ import { hoverTable } from '../../../plugins/table/commands';
21
+ import TableFloatingControls from '../../../plugins/table/ui/TableFloatingControls';
22
+ import CornerControls from '../../../plugins/table/ui/TableFloatingControls/CornerControls';
23
+ import RowControls from '../../../plugins/table/ui/TableFloatingControls/RowControls';
24
+ import { pluginKey } from '../../../plugins/table/pm-plugins/plugin-key';
25
+ import { getDecorations } from '../../../plugins/table/pm-plugins/decorations/plugin';
26
+ import tablePlugin from '../../../plugins/table-plugin';
27
+ import { PluginKey } from 'prosemirror-state';
28
+
29
+ describe('TableFloatingControls', () => {
30
+ const createEditor = createProsemirrorEditorFactory();
31
+ const fakeGetEditorFeatureFlags = () => ({});
32
+ const preset = new Preset<LightEditorPlugin>().add(tablePlugin);
33
+
34
+ const editor = (doc: DocBuilder) =>
35
+ createEditor<TablePluginState, PluginKey>({
36
+ doc,
37
+ preset,
38
+ pluginKey: pluginKey,
39
+ });
40
+
41
+ describe('when tableRef is undefined', () => {
42
+ it('should not render table header', () => {
43
+ const { editorView } = editor(
44
+ doc(p('text'), table()(tr(tdEmpty, tdEmpty, tdEmpty))),
45
+ );
46
+ const floatingControls = mount(
47
+ <TableFloatingControls
48
+ editorView={editorView}
49
+ getEditorFeatureFlags={fakeGetEditorFeatureFlags}
50
+ />,
51
+ );
52
+ expect(floatingControls.html()).toEqual(null);
53
+ floatingControls.unmount();
54
+ });
55
+ });
56
+
57
+ describe('when tableRef is defined', () => {
58
+ it('should render CornerControls and RowControls', () => {
59
+ const { editorView } = editor(
60
+ doc(p('text'), table()(tr(tdEmpty, tdEmpty, tdEmpty))),
61
+ );
62
+ const floatingControls = shallow(
63
+ <TableFloatingControls
64
+ tableRef={document.createElement('table')}
65
+ tableActive={true}
66
+ editorView={editorView}
67
+ getEditorFeatureFlags={fakeGetEditorFeatureFlags}
68
+ />,
69
+ );
70
+ expect(floatingControls.find(CornerControls).length).toEqual(1);
71
+ expect(floatingControls.find(RowControls).length).toEqual(1);
72
+ });
73
+ });
74
+
75
+ describe('when delete icon is hovered', () => {
76
+ it('should add a node decoration to table nodeView with class="danger"', () => {
77
+ const { editorView } = editor(
78
+ doc(
79
+ p('text'),
80
+ table()(
81
+ tr(tdCursor, tdEmpty),
82
+ tr(tdEmpty, tdEmpty),
83
+ tr(tdEmpty, tdEmpty),
84
+ ),
85
+ ),
86
+ );
87
+ hoverTable(true)(editorView.state, editorView.dispatch);
88
+ const decorationSet = getDecorations(editorView.state);
89
+ const decoration = decorationSet.find()[0] as any;
90
+ expect(decoration.type.attrs.class.indexOf('danger')).toBeGreaterThan(-1);
91
+ });
92
+ });
93
+ });
@@ -0,0 +1,202 @@
1
+ import { createEditorFactory } from '@atlaskit/editor-test-helpers/create-editor';
2
+ import {
3
+ doc,
4
+ p,
5
+ table,
6
+ tr,
7
+ th,
8
+ DocBuilder,
9
+ thEmpty,
10
+ td,
11
+ tdCursor,
12
+ tdEmpty,
13
+ } from '@atlaskit/editor-test-helpers/doc-builder';
14
+ import { EditorView } from 'prosemirror-view';
15
+ import { TablePluginState } from '../../plugins/table/types';
16
+ import { pluginKey as tablePluginKey } from '../../plugins/table/pm-plugins/plugin-key';
17
+ import { redo, undo } from 'prosemirror-history';
18
+ import { insertColumn } from '../../plugins/table/commands';
19
+ import { deleteColumns } from '../../plugins/table/transforms';
20
+ import { colsToRect } from '../../plugins/table/utils/table';
21
+ import sendKeyToPm from '@atlaskit/editor-test-helpers/send-key-to-pm';
22
+ import clone from 'lodash/clone';
23
+ import tablePlugin from '../../plugins/table';
24
+
25
+ const TABLE_LOCAL_ID = 'test-table-local-id';
26
+
27
+ const getEditorContainerWidth = () => {
28
+ return {
29
+ width: 500,
30
+ };
31
+ };
32
+ // HELPERS
33
+ const INSERT_COLUMN = (editorView: EditorView) =>
34
+ insertColumn(getEditorContainerWidth)(1)(
35
+ editorView.state,
36
+ editorView.dispatch,
37
+ editorView,
38
+ );
39
+ const DELETE_COLUMN = (editorView: EditorView) => {
40
+ const { state, dispatch } = editorView;
41
+ dispatch(deleteColumns(colsToRect([0], 1))(state.tr));
42
+ };
43
+ const SHORTCUT_ADD_COLUMN_BEFORE = (editorView: EditorView) =>
44
+ sendKeyToPm(editorView, 'Ctrl-Alt-ArrowLeft');
45
+ const SHORTCUT_ADD_COLUMN_AFTER = (editorView: EditorView) =>
46
+ sendKeyToPm(editorView, 'Ctrl-Alt-ArrowRight');
47
+
48
+ describe('undo/redo with tables', () => {
49
+ const createEditor = createEditorFactory<TablePluginState>();
50
+ const editor = (doc: DocBuilder) => {
51
+ const tableOptions = {
52
+ advanced: true,
53
+ allowColumnSorting: true,
54
+ };
55
+ return createEditor({
56
+ doc,
57
+ editorProps: {
58
+ allowTables: false,
59
+ dangerouslyAppendPlugins: {
60
+ __plugins: [tablePlugin({ tableOptions })],
61
+ },
62
+ },
63
+ pluginKey: tablePluginKey,
64
+ });
65
+ };
66
+ type TestCase = [
67
+ string,
68
+ {
69
+ before: DocBuilder;
70
+ action: Function;
71
+ },
72
+ ];
73
+
74
+ const case01: TestCase = [
75
+ 'when table has colwidth attribute and new col has been inserted',
76
+ {
77
+ before: doc(
78
+ table({
79
+ localId: TABLE_LOCAL_ID,
80
+ })(tr(th({ colwidth: [285] })(p('')), th({ colwidth: [1310] })(p('')))),
81
+ ),
82
+ action: INSERT_COLUMN,
83
+ },
84
+ ];
85
+
86
+ const case02: TestCase = [
87
+ 'when table has colwidth attribute and deleting a col',
88
+ {
89
+ before: doc(
90
+ table({
91
+ localId: TABLE_LOCAL_ID,
92
+ })(tr(th({ colwidth: [285] })(p('')), th({ colwidth: [1310] })(p('')))),
93
+ ),
94
+ action: DELETE_COLUMN,
95
+ },
96
+ ];
97
+
98
+ const case03: TestCase = [
99
+ 'when table has no colwidth attribute and new col is inserted',
100
+ {
101
+ before: doc(
102
+ table({
103
+ localId: TABLE_LOCAL_ID,
104
+ })(tr(thEmpty, thEmpty)),
105
+ ),
106
+ action: INSERT_COLUMN,
107
+ },
108
+ ];
109
+
110
+ const case04: TestCase = [
111
+ 'when table has no colwidth attribute and col is deleted',
112
+ {
113
+ before: doc(
114
+ table({
115
+ localId: TABLE_LOCAL_ID,
116
+ })(tr(thEmpty, thEmpty)),
117
+ ),
118
+ action: DELETE_COLUMN,
119
+ },
120
+ ];
121
+
122
+ const case05: TestCase = [
123
+ 'when table has colwidth attribute and col is inserted after selection via shortcuts',
124
+ {
125
+ before: doc(
126
+ table({
127
+ localId: TABLE_LOCAL_ID,
128
+ })(
129
+ tr(
130
+ td({ colwidth: [194] })(p('{<>}')),
131
+ td({ colwidth: [564] })(p('')),
132
+ ),
133
+ ),
134
+ ),
135
+ action: SHORTCUT_ADD_COLUMN_AFTER,
136
+ },
137
+ ];
138
+
139
+ const case06: TestCase = [
140
+ 'when table has colwidth attribute and col is inserted before selection via shortcuts',
141
+ {
142
+ before: doc(
143
+ table({
144
+ localId: TABLE_LOCAL_ID,
145
+ })(
146
+ tr(
147
+ td({ colwidth: [194] })(p('{<>}')),
148
+ td({ colwidth: [564] })(p('')),
149
+ ),
150
+ ),
151
+ ),
152
+ action: SHORTCUT_ADD_COLUMN_BEFORE,
153
+ },
154
+ ];
155
+
156
+ const case07: TestCase = [
157
+ 'when table has no colwidth attribute and col is inserted before selection via shortcuts',
158
+ {
159
+ before: doc(
160
+ table({
161
+ localId: TABLE_LOCAL_ID,
162
+ })(tr(tdCursor, tdEmpty)),
163
+ ),
164
+ action: SHORTCUT_ADD_COLUMN_BEFORE,
165
+ },
166
+ ];
167
+
168
+ const case08: TestCase = [
169
+ 'when table has no colwidth attribute and col is inserted after selection via shortcuts',
170
+ {
171
+ before: doc(
172
+ table({
173
+ localId: TABLE_LOCAL_ID,
174
+ })(tr(tdCursor, tdEmpty)),
175
+ ),
176
+ action: SHORTCUT_ADD_COLUMN_BEFORE,
177
+ },
178
+ ];
179
+
180
+ describe.each<TestCase>([
181
+ case01,
182
+ case02,
183
+ case03,
184
+ case04,
185
+ case05,
186
+ case06,
187
+ case07,
188
+ case08,
189
+ ])('[case%#] %s', (_description, testCase) => {
190
+ it('should be able to undo/redo', () => {
191
+ const { editorView } = editor(testCase.before);
192
+ const docAtStart = clone(editorView.state.doc);
193
+ testCase.action(editorView);
194
+ expect(editorView.state.doc).not.toEqualDocument(docAtStart);
195
+ const docAfterAction = clone(editorView.state.doc);
196
+ undo(editorView.state, editorView.dispatch);
197
+ expect(editorView.state.doc).toEqualDocument(docAtStart);
198
+ redo(editorView.state, editorView.dispatch);
199
+ expect(editorView.state.doc).toEqualDocument(docAfterAction);
200
+ });
201
+ });
202
+ });