Skip to content

Commit d04bdfd

Browse files
authored
test(v3): vitest browser mode (#605)
* test: Replace jsdom by browser mode with playwright * fix(ci): Install playwright browser before launching tests * chore: rename browser test *.browser.spec.tsx * chore(ci): update actions versions * fix: sync playwright and @playwright/test versions
1 parent 78dcdb5 commit d04bdfd

17 files changed

+405
-416
lines changed

.github/workflows/code-quality.yml

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ jobs:
1111
timeout-minutes: 10
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@v3
14+
- uses: actions/checkout@v4
1515

1616
- name: Install pnpm
17-
uses: pnpm/action-setup@v2
17+
uses: pnpm/action-setup@v4
1818
with:
1919
version: 10
2020

@@ -38,10 +38,10 @@ jobs:
3838
matrix:
3939
node: [20, 22, 24, 'lts/*']
4040
steps:
41-
- uses: actions/checkout@v3
41+
- uses: actions/checkout@v4
4242

4343
- name: Install pnpm
44-
uses: pnpm/action-setup@v2
44+
uses: pnpm/action-setup@v4
4545
with:
4646
version: 10
4747

@@ -61,25 +61,47 @@ jobs:
6161
name: 🔬 Tests
6262
timeout-minutes: 10
6363
runs-on: ubuntu-latest
64+
env:
65+
VITE_BASE_URL: http://localhost:3000
6466
strategy:
6567
matrix:
6668
node: [20, 22, 24, 'lts/*']
6769
steps:
68-
- uses: actions/checkout@v3
70+
- uses: actions/checkout@v4
6971

7072
- name: Install pnpm
71-
uses: pnpm/action-setup@v2
73+
uses: pnpm/action-setup@v4
7274
with:
7375
version: 10
7476

77+
- name: Get pnpm store directory
78+
shell: bash
79+
run: |
80+
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
81+
7582
- name: Setup Node.js
7683
uses: actions/setup-node@v4
7784
with:
7885
node-version: ${{ matrix.node }}
7986
cache: 'pnpm'
8087

88+
- name: Cache node modules
89+
uses: actions/cache@v4
90+
env:
91+
cache-name: cache-node-modules
92+
with:
93+
path: ${{ env.STORE_PATH }}
94+
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
95+
restore-keys: |
96+
${{ runner.os }}-pnpm-store-${{ env.cache-name }}-
97+
${{ runner.os }}-pnpm-store-
98+
${{ runner.os }}-
99+
81100
- name: Install deps
82101
run: pnpm install
83102

103+
- name: Install Playwright Chromium
104+
run: pnpm exec playwright install chromium --with-deps
105+
84106
- name: Run tests
85107
run: SKIP_ENV_VALIDATION=true pnpm run test:ci

.github/workflows/e2e-tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ jobs:
4040
- 5432:5432
4141

4242
steps:
43-
- uses: actions/checkout@v3
43+
- uses: actions/checkout@v4
4444

45-
- uses: actions/setup-node@v3
45+
- uses: actions/setup-node@v4
4646
with:
4747
node-version: 20
4848

@@ -73,7 +73,7 @@ jobs:
7373
run: pnpm install
7474

7575
- name: Install Playwright Browsers
76-
run: pnpm playwright install --with-deps
76+
run: pnpm exec playwright install --with-deps
7777

7878
- name: Migrate database
7979
run: pnpm db:push

app/components/form/field-checkbox/field-checkbox.spec.tsx renamed to app/components/form/field-checkbox/field-checkbox.browser.spec.tsx

Lines changed: 32 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { expect, test, vi } from 'vitest';
2-
import { axe } from 'vitest-axe';
32
import { z } from 'zod';
43

5-
import { render, screen, setupUser } from '@/tests/utils';
4+
import {
5+
FAILED_CLICK_TIMEOUT_MS,
6+
page,
7+
render,
8+
setupUser,
9+
} from '@/tests/utils';
610

711
import { FormField, FormFieldController } from '..';
812
import { FormMocked } from '../form-test-utils';
@@ -14,36 +18,6 @@ const zFormSchema = () =>
1418
}),
1519
});
1620

17-
test('should have no a11y violations', async () => {
18-
const mockedSubmit = vi.fn();
19-
20-
HTMLCanvasElement.prototype.getContext = vi.fn();
21-
22-
const { container } = render(
23-
<FormMocked
24-
schema={zFormSchema()}
25-
useFormOptions={{ defaultValues: { lovesBears: false } }}
26-
onSubmit={mockedSubmit}
27-
>
28-
{({ form }) => (
29-
<FormField>
30-
<FormFieldController
31-
type="checkbox"
32-
control={form.control}
33-
name="lovesBears"
34-
>
35-
I love bears
36-
</FormFieldController>
37-
</FormField>
38-
)}
39-
</FormMocked>
40-
);
41-
42-
const results = await axe(container);
43-
44-
expect(results).toHaveNoViolations();
45-
});
46-
4721
test('should select checkbox on button click', async () => {
4822
const user = setupUser();
4923
const mockedSubmit = vi.fn();
@@ -68,13 +42,14 @@ test('should select checkbox on button click', async () => {
6842
</FormMocked>
6943
);
7044

71-
const checkbox = screen.getByRole('checkbox', { name: 'I love bears' });
72-
expect(checkbox).not.toBeChecked();
45+
const checkbox = page.getByRole('checkbox', { name: 'I love bears' });
46+
47+
await expect.element(checkbox).not.toBeChecked();
7348

7449
await user.click(checkbox);
75-
expect(checkbox).toBeChecked();
50+
await expect.element(checkbox).toBeChecked();
7651

77-
await user.click(screen.getByRole('button', { name: 'Submit' }));
52+
await user.click(page.getByRole('button', { name: 'Submit' }));
7853
expect(mockedSubmit).toHaveBeenCalledWith({ lovesBears: true });
7954
});
8055

@@ -102,16 +77,16 @@ test('should select checkbox on label click', async () => {
10277
</FormMocked>
10378
);
10479

105-
const checkbox = screen.getByRole('checkbox', { name: 'I love bears' });
106-
const label = screen.getByText('I love bears');
80+
const checkbox = page.getByRole('checkbox', { name: 'I love bears' });
81+
const label = page.getByText('I love bears');
10782

108-
expect(checkbox).not.toBeChecked();
83+
await expect.element(checkbox).not.toBeChecked();
10984

11085
// Test clicking the label specifically
11186
await user.click(label);
112-
expect(checkbox).toBeChecked();
87+
await expect.element(checkbox).toBeChecked();
11388

114-
await user.click(screen.getByRole('button', { name: 'Submit' }));
89+
await user.click(page.getByRole('button', { name: 'Submit' }));
11590
expect(mockedSubmit).toHaveBeenCalledWith({ lovesBears: true });
11691
});
11792

@@ -138,10 +113,10 @@ test('default value', async () => {
138113
</FormMocked>
139114
);
140115

141-
const checkbox = screen.getByRole('checkbox', { name: 'I love bears' });
142-
expect(checkbox).toBeChecked();
116+
const checkbox = page.getByRole('checkbox', { name: 'I love bears' });
117+
await expect.element(checkbox).toBeChecked();
143118

144-
await user.click(screen.getByRole('button', { name: 'Submit' }));
119+
await user.click(page.getByRole('button', { name: 'Submit' }));
145120
expect(mockedSubmit).toHaveBeenCalledWith({ lovesBears: true });
146121
});
147122

@@ -169,12 +144,18 @@ test('disabled', async () => {
169144
</FormMocked>
170145
);
171146

172-
const checkbox = screen.getByRole('checkbox', { name: 'I love bears' });
173-
expect(checkbox).toBeDisabled();
174-
expect(checkbox).not.toBeChecked();
175-
176-
await user.click(checkbox);
177-
expect(checkbox).not.toBeChecked();
178-
await user.click(screen.getByRole('button', { name: 'Submit' }));
147+
const checkbox = page.getByRole('checkbox', { name: 'I love bears' });
148+
await expect.element(checkbox).toBeDisabled();
149+
await expect.element(checkbox).not.toBeChecked();
150+
151+
try {
152+
await user.click(checkbox, {
153+
trial: true,
154+
timeout: FAILED_CLICK_TIMEOUT_MS,
155+
});
156+
} catch {
157+
await expect.element(checkbox).not.toBeChecked();
158+
}
159+
await user.click(page.getByRole('button', { name: 'Submit' }));
179160
expect(mockedSubmit).toHaveBeenCalledWith({ lovesBears: undefined });
180161
});

app/components/form/field-otp/field-otp.spec.tsx renamed to app/components/form/field-otp/field-otp.browser.spec.tsx

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { expect, test, vi } from 'vitest';
22
import { z } from 'zod';
33

4-
import { render, screen, setupUser } from '@/tests/utils';
4+
import {
5+
FAILED_CLICK_TIMEOUT_MS,
6+
page,
7+
render,
8+
setupUser,
9+
} from '@/tests/utils';
510

611
import { FormField, FormFieldController, FormFieldLabel } from '..';
712
import { FormMocked } from '../form-test-utils';
@@ -29,10 +34,14 @@ test('update value', async () => {
2934
)}
3035
</FormMocked>
3136
);
32-
const input = screen.getByLabelText<HTMLInputElement>('Code');
37+
38+
const input = page.getByLabelText('Code');
3339
await user.click(input);
34-
await user.paste('000000');
35-
await user.click(screen.getByRole('button', { name: 'Submit' }));
40+
// Add the code to the user clipboard
41+
await navigator.clipboard.writeText('000000');
42+
43+
await user.paste();
44+
await user.click(page.getByRole('button', { name: 'Submit' }));
3645
expect(mockedSubmit).toHaveBeenCalledWith({ code: '000000' });
3746
});
3847

@@ -62,7 +71,7 @@ test('default value', async () => {
6271
)}
6372
</FormMocked>
6473
);
65-
await user.click(screen.getByRole('button', { name: 'Submit' }));
74+
await user.click(page.getByRole('button', { name: 'Submit' }));
6675
expect(mockedSubmit).toHaveBeenCalledWith({ code: '000000' });
6776
});
6877

@@ -90,9 +99,11 @@ test('auto submit', async () => {
9099
)}
91100
</FormMocked>
92101
);
93-
const input = screen.getByLabelText<HTMLInputElement>('Code');
102+
const input = page.getByLabelText('Code');
94103
await user.click(input);
95-
await user.paste('000000');
104+
// Add the code to the user clipboard
105+
await navigator.clipboard.writeText('000000');
106+
await user.paste();
96107
expect(mockedSubmit).toHaveBeenCalledWith({ code: '000000' });
97108
});
98109

@@ -120,9 +131,17 @@ test('disabled', async () => {
120131
)}
121132
</FormMocked>
122133
);
123-
const input = screen.getByLabelText<HTMLInputElement>('Code');
124-
await user.click(input);
125-
await user.paste('123456');
126-
await user.click(screen.getByRole('button', { name: 'Submit' }));
134+
const input = page.getByLabelText('Code');
135+
try {
136+
await user.click(input, { timeout: FAILED_CLICK_TIMEOUT_MS });
137+
} catch {
138+
// Click expected to fail since input is disabled
139+
}
140+
// Add the code to the user clipboard
141+
await navigator.clipboard.writeText('123456');
142+
await user.paste();
143+
144+
await user.click(page.getByRole('button', { name: 'Submit' }));
145+
127146
expect(mockedSubmit).toHaveBeenCalledWith({ code: undefined });
128147
});

0 commit comments

Comments
 (0)