Skip to content

Commit

Permalink
Vitest: use browser mode (adazzle#3222)
Browse files Browse the repository at this point in the history
Using the new browser mode to run test in a real browser
  • Loading branch information
amanmahajan7 authored and adityatoshniwal committed Jul 31, 2024
1 parent f2f8068 commit bf07ded
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 203 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ jobs:
node --run build:types
- name: Build website
run: node --run build:website
- name: Install Playwright Browsers
run: npx playwright install chromium
- name: Test
run: npm --run test
timeout-minutes: 4
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@
"@typescript-eslint/eslint-plugin": "^7.0.1",
"@typescript-eslint/parser": "^7.0.1",
"@vitejs/plugin-react": "^4.3.1",
"@vitest/coverage-v8": "^2.0.1",
"@vitest/browser": "^2.0.3",
"@vitest/coverage-istanbul": "^2.0.3",
"@wyw-in-js/rollup": "^0.5.0",
"@wyw-in-js/vite": "^0.5.0",
"babel-plugin-optimize-clsx": "^2.6.2",
Expand All @@ -92,10 +93,10 @@
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-sonarjs": "^1.0.3",
"eslint-plugin-testing-library": "^6.2.0",
"jsdom": "^24.1.0",
"jspdf": "^2.5.1",
"jspdf-autotable": "^3.5.23",
"lodash-es": "^4.17.21",
"playwright": "^1.45.1",
"postcss": "^8.4.25",
"prettier": "3.3.3",
"react": "^18.3.1",
Expand All @@ -107,7 +108,7 @@
"rollup-plugin-postcss": "^4.0.2",
"typescript": "~5.5.2",
"vite": "^5.3.3",
"vitest": "^2.0.1"
"vitest": "^2.0.3"
},
"peerDependencies": {
"react": "^18.0 || ^19.0",
Expand Down
40 changes: 15 additions & 25 deletions test/column/draggable.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { fireEvent } from '@testing-library/react';
import { act } from 'react';
import { userEvent } from '@vitest/browser/context';

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

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

expect(onColumnsReorder).not.toHaveBeenCalled();

let data: unknown;
let type: unknown;
const event = {
dataTransfer: {
get types() {
return [type];
},
setData(_type: unknown, _data: unknown) {
type = _type;
data = _data;
},
getData() {
return data;
}
}
} as const;

fireEvent.dragStart(cell2, event);
fireEvent.drop(cell4, event);
// eslint-disable-next-line testing-library/no-unnecessary-act
await act(async () => {
await userEvent.dragAndDrop(cell2, cell4);
});

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

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

// should not drag a column if it is not specified as draggable
fireEvent.dragStart(cell1, event);
fireEvent.drop(cell2, event);
// eslint-disable-next-line testing-library/no-unnecessary-act
await act(async () => {
await userEvent.dragAndDrop(cell1, cell2);
});
expect(onColumnsReorder).not.toHaveBeenCalled();
});
9 changes: 4 additions & 5 deletions test/column/renderEditCell.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event';

import DataGrid from '../../src';
import type { Column, DataGridProps } from '../../src';
import { getCellsAtRowIndex, getSelectedCell, scrollGrid } from '../utils';
import { getCellsAtRowIndex, getGrid, getSelectedCell, scrollGrid } from '../utils';

interface Row {
col1: number;
Expand Down Expand Up @@ -100,15 +100,14 @@ describe('Editor', () => {
render(<EditorTest gridRows={rows} />);
await userEvent.click(getCellsAtRowIndex(0)[0]);
expect(getCellsAtRowIndex(0)).toHaveLength(2);

await scrollGrid({ scrollTop: 2000 });
expect(getCellsAtRowIndex(0)).toHaveLength(1);
expect(screen.queryByRole('spinbutton', { name: 'col1-editor' })).not.toBeInTheDocument();
expect(getGrid().scrollTop).toBe(2000);
await userEvent.keyboard('123');
expect(getCellsAtRowIndex(0)).toHaveLength(2);
expect(screen.getByRole('spinbutton', { name: 'col1-editor' })).toHaveValue(1230);
const spy = vi.spyOn(window.HTMLElement.prototype, 'scrollIntoView');
await userEvent.keyboard('{enter}');
expect(spy).toHaveBeenCalled();
expect(getGrid().scrollTop).toBe(0);
});

describe('editable', () => {
Expand Down
140 changes: 87 additions & 53 deletions test/column/resizable.test.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,41 @@
import { fireEvent } from '@testing-library/react';
import { act } from 'react';
import { commands, userEvent } from '@vitest/browser/context';

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

const pointerId = 1;

// TODO: https://github.com/jsdom/jsdom/issues/2527
class PointerEvent extends Event {
pointerId: number | undefined;
clientX: number | undefined;
interface Row {
readonly col1: number;
readonly col2: string;
}

constructor(type: string, { pointerId, clientX, ...rest }: PointerEventInit) {
super(type, rest);
this.pointerId = pointerId;
this.clientX = clientX;
}
interface ResizeArgs {
readonly column: HTMLElement;
readonly resizeBy: number;
}

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

interface ResizeEvent<K extends keyof DOMRect> {
column: HTMLElement;
clientXStart: number;
clientXEnd: number;
rect: Pick<DOMRect, K>;
await act(async () => {
// @ts-expect-error
await commands.resizeColumn(resizeBy);
});
}

function resize<K extends keyof DOMRect>({
column,
clientXStart,
clientXEnd,
rect
}: ResizeEvent<K>) {
async function autoResize(column: HTMLElement) {
const resizeHandle = column.querySelector(`.${resizeHandleClassname}`);
if (resizeHandle === null) return;

const original = column.getBoundingClientRect.bind(column);
column.getBoundingClientRect = () => ({
...original(),
...rect
// eslint-disable-next-line testing-library/no-unnecessary-act
await act(async () => {
await userEvent.dblClick(resizeHandle);
});
// eslint-disable-next-line testing-library/prefer-user-event
fireEvent.pointerDown(
resizeHandle,
new PointerEvent('pointerdown', { pointerId, clientX: clientXStart })
);
// eslint-disable-next-line testing-library/prefer-user-event
fireEvent.pointerMove(resizeHandle, new PointerEvent('pointermove', { clientX: clientXEnd }));
fireEvent.lostPointerCapture(resizeHandle, new PointerEvent('lostpointercapture', {}));
}

const columns: readonly Column<never>[] = [
const columns: readonly Column<Row>[] = [
{
key: 'col1',
name: 'col1',
Expand All @@ -68,34 +51,85 @@ const columns: readonly Column<never>[] = [
}
];

test('should not resize column if resizable is not specified', () => {
setup({ columns, rows: [] });
test('should not resize column if resizable is not specified', async () => {
setup<Row, unknown>({ columns, rows: [] });
const [col1] = getHeaderCells();
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
resize({ column: col1, clientXStart: 95, clientXEnd: 200, rect: { right: 100, left: 0 } });
await resize({ column: col1, resizeBy: 50 });
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
await resize({ column: col1, resizeBy: -50 });
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
});

test('should resize column when dragging the handle', () => {
setup({ columns, rows: [] });
test('should resize column when dragging the handle', async () => {
setup<Row, unknown>({ columns, rows: [] });
const [, col2] = getHeaderCells();
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
resize({ column: col2, clientXStart: 289, clientXEnd: 250, rect: { right: 300, left: 100 } });
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 161px' });
const grid = getGrid();
expect(grid).toHaveStyle({ gridTemplateColumns: '100px 200px' });
await resize({ column: col2, resizeBy: -50 });
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 150px' });
});

test('should use the maxWidth if specified', () => {
setup({ columns, rows: [] });
test('should use the maxWidth if specified', async () => {
setup<Row, unknown>({ columns, rows: [] });
const [, col2] = getHeaderCells();
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
resize({ column: col2, clientXStart: 295, clientXEnd: 1000, rect: { right: 300, left: 100 } });
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px ' });
await resize({ column: col2, resizeBy: 1000 });
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 400px' });
});

test('should use the minWidth if specified', () => {
setup({ columns, rows: [] });
test('should use the minWidth if specified', async () => {
setup<Row, unknown>({ columns, rows: [] });
const [, col2] = getHeaderCells();
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
resize({ column: col2, clientXStart: 295, clientXEnd: 100, rect: { right: 300, left: 100 } });
await resize({ column: col2, resizeBy: -150 });
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 100px' });
});

test('should not auto resize column if resizable is not specified', async () => {
setup<Row, unknown>({
columns,
rows: [
{
col1: 1,
col2: 'a'.repeat(50)
}
]
});
const [col1] = getHeaderCells();
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
await autoResize(col1);
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
});

test('should auto resize column when resize handle is double clicked', async () => {
setup<Row, unknown>({
columns,
rows: [
{
col1: 1,
col2: 'a'.repeat(50)
}
]
});
const [, col2] = getHeaderCells();
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
await autoResize(col2);
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 327.703px' });
});

test('should use the maxWidth if specified on auto resize', async () => {
setup<Row, unknown>({
columns,
rows: [
{
col1: 1,
col2: 'a'.repeat(500)
}
]
});
const [, col2] = getHeaderCells();
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 200px' });
await autoResize(col2);
expect(getGrid()).toHaveStyle({ gridTemplateColumns: '100px 400px' });
});
19 changes: 8 additions & 11 deletions test/rowHeight.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@ test('rowHeight is number', async () => {
setupGrid(40);

const grid = screen.getByRole('grid');
expect(grid).toHaveStyle({ 'grid-template-rows': 'repeat(1, 40px) repeat(50, 40px)' });
expect(getRows()).toHaveLength(31);
expect(grid).toHaveStyle({
'grid-template-rows':
'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'
});
expect(getRows()).toHaveLength(30);

await userEvent.tab();
expect(grid.scrollTop).toBe(0);

// Go to the last cell
const spy = vi.spyOn(window.HTMLElement.prototype, 'scrollIntoView');
await userEvent.keyboard('{Control>}{end}');
expect(spy).toHaveBeenCalled();
expect(grid.scrollTop + grid.clientHeight).toBe(grid.scrollHeight);
});

test('rowHeight is function', async () => {
Expand All @@ -43,15 +43,12 @@ test('rowHeight is function', async () => {
const grid = screen.getByRole('grid');
expect(grid).toHaveStyle({
'grid-template-rows':
'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'
'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'
});
expect(getRows()).toHaveLength(22);

await userEvent.tab();
expect(grid.scrollTop).toBe(0);

const spy = vi.spyOn(window.HTMLElement.prototype, 'scrollIntoView');
// Go to the last cell
await userEvent.keyboard('{Control>}{end}');
expect(spy).toHaveBeenCalled();
expect(grid.scrollTop + grid.clientHeight).toBe(grid.scrollHeight);
});
Loading

0 comments on commit bf07ded

Please sign in to comment.