Skip to content

Commit 874562c

Browse files
authored
Vitest: use browser mode (adazzle#3222)
Using the new browser mode to run test in a real browser
1 parent 8f2d179 commit 874562c

12 files changed

+172
-203
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ jobs:
4848
node --run build:types
4949
- name: Build website
5050
run: node --run build:website
51+
- name: Install Playwright Browsers
52+
run: npx playwright install chromium
5153
- name: Test
5254
run: npm --run test
5355
timeout-minutes: 4

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@
7979
"@typescript-eslint/eslint-plugin": "^7.0.1",
8080
"@typescript-eslint/parser": "^7.0.1",
8181
"@vitejs/plugin-react": "^4.3.1",
82-
"@vitest/coverage-v8": "^2.0.1",
82+
"@vitest/browser": "^2.0.3",
83+
"@vitest/coverage-istanbul": "^2.0.3",
8384
"@wyw-in-js/rollup": "^0.5.0",
8485
"@wyw-in-js/vite": "^0.5.0",
8586
"babel-plugin-optimize-clsx": "^2.6.2",
@@ -92,10 +93,10 @@
9293
"eslint-plugin-react-hooks": "^4.6.2",
9394
"eslint-plugin-sonarjs": "^1.0.3",
9495
"eslint-plugin-testing-library": "^6.2.0",
95-
"jsdom": "^24.1.0",
9696
"jspdf": "^2.5.1",
9797
"jspdf-autotable": "^3.5.23",
9898
"lodash-es": "^4.17.21",
99+
"playwright": "^1.45.1",
99100
"postcss": "^8.4.25",
100101
"prettier": "3.3.3",
101102
"react": "^18.3.1",
@@ -107,7 +108,7 @@
107108
"rollup-plugin-postcss": "^4.0.2",
108109
"typescript": "~5.5.2",
109110
"vite": "^5.3.3",
110-
"vitest": "^2.0.1"
111+
"vitest": "^2.0.3"
111112
},
112113
"peerDependencies": {
113114
"react": "^18.0 || ^19.0",

test/column/draggable.test.ts

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { fireEvent } from '@testing-library/react';
1+
import { act } from 'react';
2+
import { userEvent } from '@vitest/browser/context';
23

34
import type { Column } from '../../src';
45
import { getHeaderCells, setup } from '../utils';
@@ -25,7 +26,7 @@ const columns: readonly Column<never>[] = [
2526
}
2627
];
2728

28-
test('draggable columns', () => {
29+
test('draggable columns', async () => {
2930
const onColumnsReorder = vi.fn();
3031
setup({ columns, rows: [], onColumnsReorder });
3132
const [cell1, cell2, cell3, cell4] = getHeaderCells();
@@ -37,36 +38,25 @@ test('draggable columns', () => {
3738

3839
expect(onColumnsReorder).not.toHaveBeenCalled();
3940

40-
let data: unknown;
41-
let type: unknown;
42-
const event = {
43-
dataTransfer: {
44-
get types() {
45-
return [type];
46-
},
47-
setData(_type: unknown, _data: unknown) {
48-
type = _type;
49-
data = _data;
50-
},
51-
getData() {
52-
return data;
53-
}
54-
}
55-
} as const;
56-
57-
fireEvent.dragStart(cell2, event);
58-
fireEvent.drop(cell4, event);
41+
// eslint-disable-next-line testing-library/no-unnecessary-act
42+
await act(async () => {
43+
await userEvent.dragAndDrop(cell2, cell4);
44+
});
5945

6046
expect(onColumnsReorder).toHaveBeenCalledWith('col2', 'col4');
6147
onColumnsReorder.mockReset();
6248

6349
// should not call `onColumnsReorder` if drag and drop elements are the same
64-
fireEvent.dragStart(cell2, event);
65-
fireEvent.drop(cell2, event);
50+
// eslint-disable-next-line testing-library/no-unnecessary-act
51+
await act(async () => {
52+
await userEvent.dragAndDrop(cell2, cell2);
53+
});
6654
expect(onColumnsReorder).not.toHaveBeenCalled();
6755

6856
// should not drag a column if it is not specified as draggable
69-
fireEvent.dragStart(cell1, event);
70-
fireEvent.drop(cell2, event);
57+
// eslint-disable-next-line testing-library/no-unnecessary-act
58+
await act(async () => {
59+
await userEvent.dragAndDrop(cell1, cell2);
60+
});
7161
expect(onColumnsReorder).not.toHaveBeenCalled();
7262
});

test/column/renderEditCell.test.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event';
55

66
import DataGrid from '../../src';
77
import type { Column, DataGridProps } from '../../src';
8-
import { getCellsAtRowIndex, getSelectedCell, scrollGrid } from '../utils';
8+
import { getCellsAtRowIndex, getGrid, getSelectedCell, scrollGrid } from '../utils';
99

1010
interface Row {
1111
col1: number;
@@ -100,15 +100,14 @@ describe('Editor', () => {
100100
render(<EditorTest gridRows={rows} />);
101101
await userEvent.click(getCellsAtRowIndex(0)[0]);
102102
expect(getCellsAtRowIndex(0)).toHaveLength(2);
103-
104103
await scrollGrid({ scrollTop: 2000 });
105104
expect(getCellsAtRowIndex(0)).toHaveLength(1);
106105
expect(screen.queryByRole('spinbutton', { name: 'col1-editor' })).not.toBeInTheDocument();
106+
expect(getGrid().scrollTop).toBe(2000);
107107
await userEvent.keyboard('123');
108+
expect(getCellsAtRowIndex(0)).toHaveLength(2);
108109
expect(screen.getByRole('spinbutton', { name: 'col1-editor' })).toHaveValue(1230);
109-
const spy = vi.spyOn(window.HTMLElement.prototype, 'scrollIntoView');
110-
await userEvent.keyboard('{enter}');
111-
expect(spy).toHaveBeenCalled();
110+
expect(getGrid().scrollTop).toBe(0);
112111
});
113112

114113
describe('editable', () => {

test/column/resizable.test.tsx

Lines changed: 87 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,41 @@
1-
import { fireEvent } from '@testing-library/react';
1+
import { act } from 'react';
2+
import { commands, userEvent } from '@vitest/browser/context';
23

34
import type { Column } from '../../src';
45
import { resizeHandleClassname } from '../../src/HeaderCell';
56
import { getGrid, getHeaderCells, setup } from '../utils';
67

7-
const pointerId = 1;
8-
9-
// TODO: https://github.com/jsdom/jsdom/issues/2527
10-
class PointerEvent extends Event {
11-
pointerId: number | undefined;
12-
clientX: number | undefined;
8+
interface Row {
9+
readonly col1: number;
10+
readonly col2: string;
11+
}
1312

14-
constructor(type: string, { pointerId, clientX, ...rest }: PointerEventInit) {
15-
super(type, rest);
16-
this.pointerId = pointerId;
17-
this.clientX = clientX;
18-
}
13+
interface ResizeArgs {
14+
readonly column: HTMLElement;
15+
readonly resizeBy: number;
1916
}
2017

21-
// @ts-expect-error
22-
globalThis.PointerEvent = PointerEvent;
18+
async function resize({ column, resizeBy }: ResizeArgs) {
19+
const resizeHandle = column.querySelector(`.${resizeHandleClassname}`);
20+
if (resizeHandle === null) return;
2321

24-
interface ResizeEvent<K extends keyof DOMRect> {
25-
column: HTMLElement;
26-
clientXStart: number;
27-
clientXEnd: number;
28-
rect: Pick<DOMRect, K>;
22+
await act(async () => {
23+
// @ts-expect-error
24+
await commands.resizeColumn(resizeBy);
25+
});
2926
}
3027

31-
function resize<K extends keyof DOMRect>({
32-
column,
33-
clientXStart,
34-
clientXEnd,
35-
rect
36-
}: ResizeEvent<K>) {
28+
async function autoResize(column: HTMLElement) {
3729
const resizeHandle = column.querySelector(`.${resizeHandleClassname}`);
3830
if (resizeHandle === null) return;
3931

40-
const original = column.getBoundingClientRect.bind(column);
41-
column.getBoundingClientRect = () => ({
42-
...original(),
43-
...rect
32+
// eslint-disable-next-line testing-library/no-unnecessary-act
33+
await act(async () => {
34+
await userEvent.dblClick(resizeHandle);
4435
});
45-
// eslint-disable-next-line testing-library/prefer-user-event
46-
fireEvent.pointerDown(
47-
resizeHandle,
48-
new PointerEvent('pointerdown', { pointerId, clientX: clientXStart })
49-
);
50-
// eslint-disable-next-line testing-library/prefer-user-event
51-
fireEvent.pointerMove(resizeHandle, new PointerEvent('pointermove', { clientX: clientXEnd }));
52-
fireEvent.lostPointerCapture(resizeHandle, new PointerEvent('lostpointercapture', {}));
5336
}
5437

55-
const columns: readonly Column<never>[] = [
38+
const columns: readonly Column<Row>[] = [
5639
{
5740
key: 'col1',
5841
name: 'col1',
@@ -68,34 +51,85 @@ const columns: readonly Column<never>[] = [
6851
}
6952
];
7053

71-
test('should not resize column if resizable is not specified', () => {
72-
setup({ columns, rows: [] });
54+
test('should not resize column if resizable is not specified', async () => {
55+
setup<Row, unknown>({ columns, rows: [] });
7356
const [col1] = getHeaderCells();
7457
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
75-
resize({ column: col1, clientXStart: 95, clientXEnd: 200, rect: { right: 100, left: 0 } });
58+
await resize({ column: col1, resizeBy: 50 });
59+
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
60+
await resize({ column: col1, resizeBy: -50 });
7661
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
7762
});
7863

79-
test('should resize column when dragging the handle', () => {
80-
setup({ columns, rows: [] });
64+
test('should resize column when dragging the handle', async () => {
65+
setup<Row, unknown>({ columns, rows: [] });
8166
const [, col2] = getHeaderCells();
82-
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
83-
resize({ column: col2, clientXStart: 289, clientXEnd: 250, rect: { right: 300, left: 100 } });
84-
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 161px' });
67+
const grid = getGrid();
68+
expect(grid).toHaveStyle({ gridTemplateColumns: '100px 200px' });
69+
await resize({ column: col2, resizeBy: -50 });
70+
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 150px' });
8571
});
8672

87-
test('should use the maxWidth if specified', () => {
88-
setup({ columns, rows: [] });
73+
test('should use the maxWidth if specified', async () => {
74+
setup<Row, unknown>({ columns, rows: [] });
8975
const [, col2] = getHeaderCells();
90-
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
91-
resize({ column: col2, clientXStart: 295, clientXEnd: 1000, rect: { right: 300, left: 100 } });
76+
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px ' });
77+
await resize({ column: col2, resizeBy: 1000 });
9278
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 400px' });
9379
});
9480

95-
test('should use the minWidth if specified', () => {
96-
setup({ columns, rows: [] });
81+
test('should use the minWidth if specified', async () => {
82+
setup<Row, unknown>({ columns, rows: [] });
9783
const [, col2] = getHeaderCells();
9884
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
99-
resize({ column: col2, clientXStart: 295, clientXEnd: 100, rect: { right: 300, left: 100 } });
85+
await resize({ column: col2, resizeBy: -150 });
10086
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 100px' });
10187
});
88+
89+
test('should not auto resize column if resizable is not specified', async () => {
90+
setup<Row, unknown>({
91+
columns,
92+
rows: [
93+
{
94+
col1: 1,
95+
col2: 'a'.repeat(50)
96+
}
97+
]
98+
});
99+
const [col1] = getHeaderCells();
100+
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
101+
await autoResize(col1);
102+
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
103+
});
104+
105+
test('should auto resize column when resize handle is double clicked', async () => {
106+
setup<Row, unknown>({
107+
columns,
108+
rows: [
109+
{
110+
col1: 1,
111+
col2: 'a'.repeat(50)
112+
}
113+
]
114+
});
115+
const [, col2] = getHeaderCells();
116+
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
117+
await autoResize(col2);
118+
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 327.703px' });
119+
});
120+
121+
test('should use the maxWidth if specified on auto resize', async () => {
122+
setup<Row, unknown>({
123+
columns,
124+
rows: [
125+
{
126+
col1: 1,
127+
col2: 'a'.repeat(500)
128+
}
129+
]
130+
});
131+
const [, col2] = getHeaderCells();
132+
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
133+
await autoResize(col2);
134+
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 400px' });
135+
});

test/rowHeight.test.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@ test('rowHeight is number', async () => {
2525
setupGrid(40);
2626

2727
const grid = screen.getByRole('grid');
28-
expect(grid).toHaveStyle({ 'grid-template-rows': 'repeat(1, 40px) repeat(50, 40px)' });
29-
expect(getRows()).toHaveLength(31);
28+
expect(grid).toHaveStyle({
29+
'grid-template-rows':
30+
'40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px 40px'
31+
});
32+
expect(getRows()).toHaveLength(30);
3033

3134
await userEvent.tab();
3235
expect(grid.scrollTop).toBe(0);
33-
34-
// Go to the last cell
35-
const spy = vi.spyOn(window.HTMLElement.prototype, 'scrollIntoView');
3636
await userEvent.keyboard('{Control>}{end}');
37-
expect(spy).toHaveBeenCalled();
37+
expect(grid.scrollTop + grid.clientHeight).toBe(grid.scrollHeight);
3838
});
3939

4040
test('rowHeight is function', async () => {
@@ -43,15 +43,12 @@ test('rowHeight is function', async () => {
4343
const grid = screen.getByRole('grid');
4444
expect(grid).toHaveStyle({
4545
'grid-template-rows':
46-
'repeat(1, 35px) 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px'
46+
'35px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px 80px 40px 60px'
4747
});
4848
expect(getRows()).toHaveLength(22);
4949

5050
await userEvent.tab();
5151
expect(grid.scrollTop).toBe(0);
52-
53-
const spy = vi.spyOn(window.HTMLElement.prototype, 'scrollIntoView');
54-
// Go to the last cell
5552
await userEvent.keyboard('{Control>}{end}');
56-
expect(spy).toHaveBeenCalled();
53+
expect(grid.scrollTop + grid.clientHeight).toBe(grid.scrollHeight);
5754
});

0 commit comments

Comments
 (0)