Repository navigation
Expand file tree
/
Copy pathvitest.config.mts
More file actions
149 lines (146 loc) · 5.92 KB
/
Copy pathvitest.config.mts
File metadata and controls
149 lines (146 loc) · 5.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import { defaultExclude, defineConfig } from 'vite-plus';
import { playwright } from 'vite-plus/test/browser-playwright';
// Set a stable timezone before any workers start so that Intl (used by
// @primer/react's RelativeTime component) always formats dates in UTC,
// regardless of the local system timezone (e.g. when travelling).
process.env.TZ = 'UTC';
// Mirrors `WindowConfig` in src/main/config.ts, which cannot be imported here
// because it resolves `__dirname` at module scope. src/main/config.test.ts
// asserts these same values.
const MENUBAR_VIEWPORT = { width: 500, height: 400 };
export default defineConfig({
plugins: [react()],
test: {
globals: true,
// happy-dom tests import CSS from @primer/react. The threads and forks pools
// cannot load those .css files (ERR_UNKNOWN_FILE_EXTENSION), so keep vmThreads.
pool: 'vmThreads',
isolate: true,
attachmentsDir: '.vitest-attachments',
testTimeout: 10_000,
clearMocks: true,
unstubEnvs: true,
unstubGlobals: true,
// Pre-bundle @primer/react rather than re-transforming the raw package on every thread load.
// See https://vitest.dev/guide/profiling-test-performance.html#use-the-dependency-optimizer
deps: {
optimizer: {
client: {
include: ['@primer/react'],
},
},
},
experimental: {
importDurations: {
print: true,
},
},
coverage: {
enabled: false,
reportOnFailure: true,
reporter: ['html', 'lcovonly'],
include: ['src/**/*'],
exclude: ['**/*.html', '**/*.md', '**/*.graphql', '**/graphql/generated/**', '**/.DS_Store'],
},
// Projects mirror the runtime boundary: Node for main/shared, happy-dom for
// preload/renderer, and a real browser for pixel tests.
projects: [
{
extends: true,
test: {
name: 'happy-dom [preload, renderer]',
environment: 'happy-dom',
css: true,
include: ['src/preload/**/*.test.{ts,tsx}', 'src/renderer/**/*.test.{ts,tsx}'],
// Visual tests share the `.test.tsx` suffix but need a real browser.
// Spread the defaults; assigning `exclude` replaces them outright.
exclude: [...defaultExclude, '**/*.visual.test.tsx'],
setupFiles: [
'./src/__helpers__/electron-log.setup.ts',
'./src/__helpers__/restore-test-spies.setup.ts',
'./src/__helpers__/fail-on-act-warnings.setup.ts',
'./src/renderer/__helpers__/vitest.setup.ts',
],
},
},
{
// Renderer tests stay in happy-dom even when they look like pure utils:
// many touch window.gitify, localStorage, navigator, document, or Audio,
// and the environment is only ~2% of suite runtime. A third node project
// would still need a renderer setup and would not remove that coupling.
extends: true,
test: {
name: 'node [main, shared]',
environment: 'node',
include: ['src/shared/**/*.test.{ts,tsx}', 'src/main/**/*.test.{ts,tsx}'],
setupFiles: [
'./src/__helpers__/electron-log.setup.ts',
'./src/__helpers__/restore-test-spies.setup.ts',
],
},
},
{
extends: true,
// Tailwind is not in the root plugins because the other two projects never
// resolve `@import 'tailwindcss'`; pixel comparison does.
plugins: [tailwindcss()],
// `src/renderer/constants.ts` reads this, and unlike the other two
// projects there is no Node `process` in the browser to read it from.
define: {
'process.env.OAUTH_CLIENT_ID': JSON.stringify('visual-test-client-id'),
},
test: {
name: 'browser [visual]',
include: ['src/renderer/**/*.visual.test.tsx'],
setupFiles: ['./src/renderer/__helpers__/visual.setup.ts'],
// Hard-stops the run outside Linux, where Vitest would otherwise
// create per-platform baselines and pass against them.
globalSetup: ['./src/renderer/__helpers__/visual.global-setup.ts'],
browser: {
enabled: true,
headless: true,
provider: playwright({
launchOptions: {
// Chromium's default font rendering varies with GPU availability.
// Force the software path so a developer's machine and CI agree.
args: ['--disable-lcd-text', '--font-render-hinting=none'],
},
contextOptions: {
// The renderer formats relative timestamps via Intl; the Node-level
// `process.env.TZ` above does not reach the browser process.
timezoneId: 'UTC',
locale: 'en-US',
// Only reached by Theme.SYSTEM, which resolves via `prefers-color-scheme`.
colorScheme: 'light',
},
}),
instances: [
{
browser: 'chromium',
viewport: MENUBAR_VIEWPORT,
},
],
expect: {
toMatchScreenshot: {
comparatorName: 'pixelmatch',
comparatorOptions: {
// Per-pixel colour tolerance, to absorb antialiasing noise.
threshold: 0.2,
// But zero tolerance for the *number* of differing pixels.
// Rendering is deterministic here (fixed container, arch,
// fonts and clock), so any drift is a real change. A ratio of
// even 0.01 would permit ~2000 pixels on this 500x400
// viewport — larger than a whole icon, which is enough to
// hide a completely swapped glyph.
allowedMismatchedPixels: 0,
},
},
},
},
},
},
],
},
});