@nice2dev/testing 1.0.10
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.
- package/README.md +36 -0
- package/dist/index.cjs +243 -0
- package/dist/index.d.ts +1618 -0
- package/dist/index.mjs +19016 -0
- package/dist/magic-string.es-B81Zo59j.cjs +10 -0
- package/dist/magic-string.es-uPKorP4O.js +663 -0
- package/package.json +57 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1618 @@
|
|
|
1
|
+
import { BrowserContext } from '@playwright/test';
|
|
2
|
+
import { default as default_2 } from 'react';
|
|
3
|
+
import { expect } from 'vitest';
|
|
4
|
+
import * as fc from 'fast-check';
|
|
5
|
+
import { JSX as JSX_2 } from 'react/jsx-runtime';
|
|
6
|
+
import { Page } from '@playwright/test';
|
|
7
|
+
import * as React_2 from 'react';
|
|
8
|
+
import { ReactElement } from 'react';
|
|
9
|
+
import { ReactNode } from 'react';
|
|
10
|
+
import { StorybookConfig } from '@storybook/react-vite';
|
|
11
|
+
|
|
12
|
+
export declare interface A11yAuditResult {
|
|
13
|
+
passes: number;
|
|
14
|
+
violations: A11yViolation[];
|
|
15
|
+
incomplete: number;
|
|
16
|
+
inapplicable: number;
|
|
17
|
+
/** WCAG compliance score (%) */
|
|
18
|
+
complianceScore: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export declare interface A11yViolation {
|
|
22
|
+
ruleId: string;
|
|
23
|
+
impact: 'critical' | 'serious' | 'moderate' | 'minor';
|
|
24
|
+
description: string;
|
|
25
|
+
helpUrl: string;
|
|
26
|
+
nodes: Array<{
|
|
27
|
+
selector: string;
|
|
28
|
+
html: string;
|
|
29
|
+
failureSummary: string;
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export declare interface AccessibilityAuditConfig {
|
|
34
|
+
/** WCAG level */
|
|
35
|
+
level: WcagLevel;
|
|
36
|
+
/** Rules to include/exclude */
|
|
37
|
+
includeRules?: string[];
|
|
38
|
+
excludeRules?: string[];
|
|
39
|
+
/** Components to audit */
|
|
40
|
+
componentSelectors: string[];
|
|
41
|
+
/** Axe-core configuration */
|
|
42
|
+
axeConfig?: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export declare const arbitraries: {
|
|
46
|
+
/** Non-empty string */
|
|
47
|
+
nonEmptyString: () => fc.Arbitrary<string>;
|
|
48
|
+
/** Non-empty array */
|
|
49
|
+
nonEmptyArray: <T>(arb: fc.Arbitrary<T>) => fc.Arbitrary<T[]>;
|
|
50
|
+
/** Unique array (no duplicates) */
|
|
51
|
+
uniqueArray: <T>(arb: fc.Arbitrary<T>) => fc.Arbitrary<T[]>;
|
|
52
|
+
/** Valid CSS color hex (#RGB or #RRGGBB) */
|
|
53
|
+
hexColor: () => fc.Arbitrary<string>;
|
|
54
|
+
/** RGB color */
|
|
55
|
+
rgbColor: () => fc.Arbitrary<{
|
|
56
|
+
r: number;
|
|
57
|
+
g: number;
|
|
58
|
+
b: number;
|
|
59
|
+
}>;
|
|
60
|
+
/** HSL color */
|
|
61
|
+
hslColor: () => fc.Arbitrary<{
|
|
62
|
+
h: number;
|
|
63
|
+
s: number;
|
|
64
|
+
l: number;
|
|
65
|
+
}>;
|
|
66
|
+
/** CSS size value (e.g., '10px', '2rem') */
|
|
67
|
+
cssSize: () => fc.Arbitrary<string>;
|
|
68
|
+
/** CSS spacing (positive values only) */
|
|
69
|
+
cssSpacing: () => fc.Arbitrary<string>;
|
|
70
|
+
/** CSS border-radius */
|
|
71
|
+
borderRadius: () => fc.Arbitrary<string>;
|
|
72
|
+
/** CSS z-index */
|
|
73
|
+
zIndex: () => fc.Arbitrary<number>;
|
|
74
|
+
/** Viewport dimensions */
|
|
75
|
+
viewport: () => fc.Arbitrary<{
|
|
76
|
+
width: number;
|
|
77
|
+
height: number;
|
|
78
|
+
}>;
|
|
79
|
+
/** Grid columns (1-12) */
|
|
80
|
+
gridColumns: () => fc.Arbitrary<number>;
|
|
81
|
+
/** Flex direction */
|
|
82
|
+
flexDirection: () => fc.Arbitrary<string>;
|
|
83
|
+
/** Flex justify content */
|
|
84
|
+
justifyContent: () => fc.Arbitrary<string>;
|
|
85
|
+
/** Flex align items */
|
|
86
|
+
alignItems: () => fc.Arbitrary<string>;
|
|
87
|
+
/** Valid HTML element tag */
|
|
88
|
+
htmlTag: () => fc.Arbitrary<string>;
|
|
89
|
+
/** Valid ARIA role */
|
|
90
|
+
ariaRole: () => fc.Arbitrary<string>;
|
|
91
|
+
/** Event handler name */
|
|
92
|
+
eventHandler: () => fc.Arbitrary<string>;
|
|
93
|
+
/** Email address */
|
|
94
|
+
email: () => fc.Arbitrary<string>;
|
|
95
|
+
/** UUID */
|
|
96
|
+
uuid: () => fc.Arbitrary<string>;
|
|
97
|
+
/** URL */
|
|
98
|
+
url: () => fc.Arbitrary<string>;
|
|
99
|
+
/** ISO date string */
|
|
100
|
+
isoDate: () => fc.Arbitrary<string>;
|
|
101
|
+
/** Timestamp (milliseconds) */
|
|
102
|
+
timestamp: () => fc.Arbitrary<number>;
|
|
103
|
+
/** Phone number (simple format) */
|
|
104
|
+
phone: () => fc.Arbitrary<string>;
|
|
105
|
+
/** Form field value (string, number, or boolean) */
|
|
106
|
+
fieldValue: () => fc.Arbitrary<string | number | boolean>;
|
|
107
|
+
/** Form validation state */
|
|
108
|
+
validationState: () => fc.Arbitrary<{
|
|
109
|
+
valid: boolean;
|
|
110
|
+
error: string | undefined;
|
|
111
|
+
touched: boolean;
|
|
112
|
+
dirty: boolean;
|
|
113
|
+
}>;
|
|
114
|
+
/** Table row */
|
|
115
|
+
tableRow: <T extends Record<string, fc.Arbitrary<unknown>>>(schema: T) => fc.Arbitrary<{
|
|
116
|
+
[x: string]: unknown;
|
|
117
|
+
id: string;
|
|
118
|
+
}>;
|
|
119
|
+
/** Table data */
|
|
120
|
+
tableData: <T extends Record<string, unknown>>(rowArb: fc.Arbitrary<T>, size?: {
|
|
121
|
+
minLength?: number;
|
|
122
|
+
maxLength?: number;
|
|
123
|
+
}) => fc.Arbitrary<T[]>;
|
|
124
|
+
/** Animation duration (ms) */
|
|
125
|
+
duration: () => fc.Arbitrary<number>;
|
|
126
|
+
/** Animation easing */
|
|
127
|
+
easing: () => fc.Arbitrary<string>;
|
|
128
|
+
/** Animation delay (ms) */
|
|
129
|
+
delay: () => fc.Arbitrary<number>;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Run axe-core accessibility check
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* test('accessibility', async ({ page }) => {
|
|
138
|
+
* await page.goto('/');
|
|
139
|
+
* const results = await axeCheck(page);
|
|
140
|
+
* expect(results.violations).toHaveLength(0);
|
|
141
|
+
* });
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export declare function axeCheck(page: Page, options?: {
|
|
145
|
+
include?: string[];
|
|
146
|
+
exclude?: string[];
|
|
147
|
+
rules?: Record<string, {
|
|
148
|
+
enabled: boolean;
|
|
149
|
+
}>;
|
|
150
|
+
tags?: string[];
|
|
151
|
+
}): Promise<{
|
|
152
|
+
violations: AxeViolation[];
|
|
153
|
+
passes: number;
|
|
154
|
+
incomplete: number;
|
|
155
|
+
}>;
|
|
156
|
+
|
|
157
|
+
export declare interface AxeViolation {
|
|
158
|
+
id: string;
|
|
159
|
+
impact: string;
|
|
160
|
+
description: string;
|
|
161
|
+
help: string;
|
|
162
|
+
helpUrl: string;
|
|
163
|
+
nodes: Array<{
|
|
164
|
+
html: string;
|
|
165
|
+
target: string[];
|
|
166
|
+
failureSummary: string;
|
|
167
|
+
}>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export declare interface BenchmarkResult {
|
|
171
|
+
component: string;
|
|
172
|
+
metric: string;
|
|
173
|
+
mean: number;
|
|
174
|
+
median: number;
|
|
175
|
+
p95: number;
|
|
176
|
+
p99: number;
|
|
177
|
+
min: number;
|
|
178
|
+
max: number;
|
|
179
|
+
stdDev: number;
|
|
180
|
+
regressionDetected: boolean;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Browser configurations for cross-browser testing
|
|
185
|
+
*/
|
|
186
|
+
export declare const BROWSER_CONFIGS: {
|
|
187
|
+
readonly chromium: {
|
|
188
|
+
readonly name: "chromium";
|
|
189
|
+
readonly channel: undefined;
|
|
190
|
+
};
|
|
191
|
+
readonly chrome: {
|
|
192
|
+
readonly name: "chromium";
|
|
193
|
+
readonly channel: "chrome";
|
|
194
|
+
};
|
|
195
|
+
readonly firefox: {
|
|
196
|
+
readonly name: "firefox";
|
|
197
|
+
};
|
|
198
|
+
readonly webkit: {
|
|
199
|
+
readonly name: "webkit";
|
|
200
|
+
};
|
|
201
|
+
readonly edge: {
|
|
202
|
+
readonly name: "chromium";
|
|
203
|
+
readonly channel: "msedge";
|
|
204
|
+
};
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Check if element has proper ARIA attributes for a11y compliance.
|
|
209
|
+
* Returns an array of violations (empty = passed).
|
|
210
|
+
*/
|
|
211
|
+
export declare function checkAriaCompliance(element: HTMLElement): string[];
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Run property test and collect statistics
|
|
215
|
+
*/
|
|
216
|
+
export declare function checkWithStats<T extends unknown[]>(arbitraries: {
|
|
217
|
+
[K in keyof T]: fc.Arbitrary<T[K]>;
|
|
218
|
+
}, predicate: (...args: T) => void, config?: PropertyTestConfig): fc.RunDetails<T>;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Chromatic CI script configuration
|
|
222
|
+
*/
|
|
223
|
+
export declare const chromaticCIConfig: {
|
|
224
|
+
projectToken: string | undefined;
|
|
225
|
+
buildScriptName: string;
|
|
226
|
+
exitZeroOnChanges: boolean;
|
|
227
|
+
exitOnceUploaded: boolean;
|
|
228
|
+
onlyChanged: boolean;
|
|
229
|
+
externals: string[];
|
|
230
|
+
skip: string;
|
|
231
|
+
traceChanged: string;
|
|
232
|
+
modes: {
|
|
233
|
+
light: {
|
|
234
|
+
theme: string;
|
|
235
|
+
};
|
|
236
|
+
dark: {
|
|
237
|
+
theme: string;
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Default Chromatic parameters for stories
|
|
244
|
+
*/
|
|
245
|
+
export declare const chromaticDefaults: {
|
|
246
|
+
viewports: number[];
|
|
247
|
+
diffThreshold: number;
|
|
248
|
+
delay: number;
|
|
249
|
+
pauseAnimationAtEnd: boolean;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Chromatic modes configuration for Storybook
|
|
254
|
+
* Add this to .storybook/preview.tsx
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```tsx
|
|
258
|
+
* // .storybook/preview.tsx
|
|
259
|
+
* import { chromaticModes } from '@nice2dev/testing';
|
|
260
|
+
*
|
|
261
|
+
* export const parameters = {
|
|
262
|
+
* chromatic: {
|
|
263
|
+
* modes: chromaticModes,
|
|
264
|
+
* },
|
|
265
|
+
* };
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
export declare const chromaticModes: {
|
|
269
|
+
mobile: {
|
|
270
|
+
viewport: {
|
|
271
|
+
width: number;
|
|
272
|
+
height: number;
|
|
273
|
+
};
|
|
274
|
+
};
|
|
275
|
+
tablet: {
|
|
276
|
+
viewport: {
|
|
277
|
+
width: number;
|
|
278
|
+
height: number;
|
|
279
|
+
};
|
|
280
|
+
};
|
|
281
|
+
desktop: {
|
|
282
|
+
viewport: {
|
|
283
|
+
width: number;
|
|
284
|
+
height: number;
|
|
285
|
+
};
|
|
286
|
+
};
|
|
287
|
+
wide: {
|
|
288
|
+
viewport: {
|
|
289
|
+
width: number;
|
|
290
|
+
height: number;
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
light: {
|
|
294
|
+
theme: string;
|
|
295
|
+
backgrounds: {
|
|
296
|
+
value: string;
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
dark: {
|
|
300
|
+
theme: string;
|
|
301
|
+
backgrounds: {
|
|
302
|
+
value: string;
|
|
303
|
+
};
|
|
304
|
+
};
|
|
305
|
+
highContrast: {
|
|
306
|
+
theme: string;
|
|
307
|
+
backgrounds: {
|
|
308
|
+
value: string;
|
|
309
|
+
};
|
|
310
|
+
};
|
|
311
|
+
rtl: {
|
|
312
|
+
globals: {
|
|
313
|
+
direction: string;
|
|
314
|
+
};
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Clean up HTML for snapshot testing by removing dynamic attributes.
|
|
320
|
+
*/
|
|
321
|
+
export declare function cleanHtmlForSnapshot(html: string): string;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Command type for model-based testing
|
|
325
|
+
*/
|
|
326
|
+
export declare interface Command<Model, Real> {
|
|
327
|
+
check(model: Readonly<Model>): boolean;
|
|
328
|
+
run(model: Model, real: Real): void | Promise<void>;
|
|
329
|
+
toString(): string;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export declare interface CrashReportingConfig {
|
|
333
|
+
/** DSN / endpoint */
|
|
334
|
+
dsn: string;
|
|
335
|
+
/** Environment */
|
|
336
|
+
environment: 'development' | 'staging' | 'production';
|
|
337
|
+
/** Release tag */
|
|
338
|
+
release: string;
|
|
339
|
+
/** Source maps */
|
|
340
|
+
enableSourceMaps: boolean;
|
|
341
|
+
/** Breadcrumbs */
|
|
342
|
+
maxBreadcrumbs: number;
|
|
343
|
+
/** User context */
|
|
344
|
+
includeUserContext: boolean;
|
|
345
|
+
/** Attachments (screenshots, logs) */
|
|
346
|
+
includeScreenshot: boolean;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Create a mock data source for testing data-bound components.
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* const ds = createMockDataSource({
|
|
354
|
+
* data: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }],
|
|
355
|
+
* });
|
|
356
|
+
* render(<NiceDataGrid dataSource={ds} columns={[...]} />);
|
|
357
|
+
*/
|
|
358
|
+
export declare function createMockDataSource<T extends Record<string, unknown>>(options: MockDataSourceOptions<T>): MockDataSource<T>;
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* RTL decorator for Storybook
|
|
362
|
+
*/
|
|
363
|
+
export declare function createRTLDecorator(): (Story: React_2.ComponentType, context: {
|
|
364
|
+
globals: {
|
|
365
|
+
direction?: string;
|
|
366
|
+
};
|
|
367
|
+
}) => JSX_2.Element;
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Create test context with common utilities
|
|
371
|
+
*/
|
|
372
|
+
export declare function createTestContext(page: Page, context: BrowserContext): {
|
|
373
|
+
page: Page;
|
|
374
|
+
context: BrowserContext;
|
|
375
|
+
helpers: NiceTestHelpers;
|
|
376
|
+
axe: () => Promise<{
|
|
377
|
+
violations: AxeViolation[];
|
|
378
|
+
passes: number;
|
|
379
|
+
incomplete: number;
|
|
380
|
+
}>;
|
|
381
|
+
mockAPI: (mocks: Parameters<typeof mockAPI>[1]) => Promise<void>;
|
|
382
|
+
mockGraphQL: (endpoint: string, mocks: Record<string, unknown>) => Promise<void>;
|
|
383
|
+
performance: () => Promise<{
|
|
384
|
+
fcp: number;
|
|
385
|
+
lcp: number;
|
|
386
|
+
cls: number;
|
|
387
|
+
ttfb: number;
|
|
388
|
+
tti: number;
|
|
389
|
+
}>;
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Theme decorator for Storybook
|
|
394
|
+
* Apply themes via globals
|
|
395
|
+
*/
|
|
396
|
+
export declare function createThemeDecorator(): (Story: React_2.ComponentType, context: {
|
|
397
|
+
globals: {
|
|
398
|
+
theme?: string;
|
|
399
|
+
};
|
|
400
|
+
}) => JSX_2.Element;
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Helper to create .storybook/preview.ts content
|
|
404
|
+
*/
|
|
405
|
+
export declare function createVisualPreviewConfig(): string;
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Combined decorator for visual testing
|
|
409
|
+
*/
|
|
410
|
+
export declare function createVisualTestDecorator(): (Story: React_2.ComponentType, context: {
|
|
411
|
+
globals: {
|
|
412
|
+
theme?: string;
|
|
413
|
+
direction?: string;
|
|
414
|
+
reducedMotion?: boolean;
|
|
415
|
+
};
|
|
416
|
+
}) => JSX_2.Element;
|
|
417
|
+
|
|
418
|
+
export declare const DEFAULT_BREAKPOINTS: [string, number][];
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Default CSS properties to capture in style snapshots
|
|
422
|
+
*/
|
|
423
|
+
export declare const DEFAULT_STYLE_PROPERTIES: string[];
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Device configurations for mobile testing
|
|
427
|
+
*/
|
|
428
|
+
export declare const DEVICE_CONFIGS: {
|
|
429
|
+
readonly 'iPhone 13': {
|
|
430
|
+
readonly viewport: {
|
|
431
|
+
readonly width: 390;
|
|
432
|
+
readonly height: 844;
|
|
433
|
+
};
|
|
434
|
+
readonly userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1";
|
|
435
|
+
readonly deviceScaleFactor: 3;
|
|
436
|
+
readonly isMobile: true;
|
|
437
|
+
readonly hasTouch: true;
|
|
438
|
+
};
|
|
439
|
+
readonly 'iPhone 14 Pro Max': {
|
|
440
|
+
readonly viewport: {
|
|
441
|
+
readonly width: 430;
|
|
442
|
+
readonly height: 932;
|
|
443
|
+
};
|
|
444
|
+
readonly userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1";
|
|
445
|
+
readonly deviceScaleFactor: 3;
|
|
446
|
+
readonly isMobile: true;
|
|
447
|
+
readonly hasTouch: true;
|
|
448
|
+
};
|
|
449
|
+
readonly 'iPad Pro': {
|
|
450
|
+
readonly viewport: {
|
|
451
|
+
readonly width: 1024;
|
|
452
|
+
readonly height: 1366;
|
|
453
|
+
};
|
|
454
|
+
readonly userAgent: "Mozilla/5.0 (iPad; CPU OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1";
|
|
455
|
+
readonly deviceScaleFactor: 2;
|
|
456
|
+
readonly isMobile: true;
|
|
457
|
+
readonly hasTouch: true;
|
|
458
|
+
};
|
|
459
|
+
readonly 'Pixel 7': {
|
|
460
|
+
readonly viewport: {
|
|
461
|
+
readonly width: 412;
|
|
462
|
+
readonly height: 915;
|
|
463
|
+
};
|
|
464
|
+
readonly userAgent: "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36";
|
|
465
|
+
readonly deviceScaleFactor: 2.625;
|
|
466
|
+
readonly isMobile: true;
|
|
467
|
+
readonly hasTouch: true;
|
|
468
|
+
};
|
|
469
|
+
readonly 'Samsung Galaxy S23': {
|
|
470
|
+
readonly viewport: {
|
|
471
|
+
readonly width: 360;
|
|
472
|
+
readonly height: 780;
|
|
473
|
+
};
|
|
474
|
+
readonly userAgent: "Mozilla/5.0 (Linux; Android 13; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Mobile Safari/537.36";
|
|
475
|
+
readonly deviceScaleFactor: 3;
|
|
476
|
+
readonly isMobile: true;
|
|
477
|
+
readonly hasTouch: true;
|
|
478
|
+
};
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Quality & Reliability types (PRO-6.1)
|
|
483
|
+
*
|
|
484
|
+
* E2E tests, visual regression, performance benchmarks, a11y audit,
|
|
485
|
+
* i18n, error boundaries, telemetry, crash reporting, stress/fuzz/load
|
|
486
|
+
* testing, and security scanning configurations.
|
|
487
|
+
*
|
|
488
|
+
* @module @nice2dev/testing/quality
|
|
489
|
+
*/
|
|
490
|
+
export declare interface E2eTestConfig {
|
|
491
|
+
/** Test runner */
|
|
492
|
+
runner: 'playwright' | 'cypress' | 'puppeteer';
|
|
493
|
+
/** Base URL */
|
|
494
|
+
baseUrl: string;
|
|
495
|
+
/** Browsers to test */
|
|
496
|
+
browsers: Array<'chromium' | 'firefox' | 'webkit'>;
|
|
497
|
+
/** Coverage target (%) */
|
|
498
|
+
coverageTarget: number;
|
|
499
|
+
/** Parallel workers */
|
|
500
|
+
workers: number;
|
|
501
|
+
/** Timeout per test (ms) */
|
|
502
|
+
testTimeout: number;
|
|
503
|
+
/** Retry count on failure */
|
|
504
|
+
retries: number;
|
|
505
|
+
/** Output directory */
|
|
506
|
+
outputDir: string;
|
|
507
|
+
/** Sharding */
|
|
508
|
+
sharding?: {
|
|
509
|
+
total: number;
|
|
510
|
+
current: number;
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export declare interface E2eTestResult {
|
|
515
|
+
suiteName: string;
|
|
516
|
+
passed: number;
|
|
517
|
+
failed: number;
|
|
518
|
+
skipped: number;
|
|
519
|
+
duration: number;
|
|
520
|
+
coveragePercent: number;
|
|
521
|
+
failures: Array<{
|
|
522
|
+
testName: string;
|
|
523
|
+
error: string;
|
|
524
|
+
screenshot?: string;
|
|
525
|
+
trace?: string;
|
|
526
|
+
}>;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
export declare interface ErrorBoundaryConfig {
|
|
530
|
+
/** Fallback UI component key */
|
|
531
|
+
fallbackComponent: string;
|
|
532
|
+
/** Enable recovery */
|
|
533
|
+
enableRecovery: boolean;
|
|
534
|
+
/** Max retries */
|
|
535
|
+
maxRetries: number;
|
|
536
|
+
/** Error reporting endpoint */
|
|
537
|
+
reportingEndpoint?: string;
|
|
538
|
+
/** Ignored errors */
|
|
539
|
+
ignoredErrors: string[];
|
|
540
|
+
/** Scope: per-component or per-page */
|
|
541
|
+
scope: 'component' | 'page' | 'application';
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
export { expect }
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Assert no accessibility violations
|
|
548
|
+
*/
|
|
549
|
+
export declare function expectNoA11yViolations(page: Page): Promise<void>;
|
|
550
|
+
|
|
551
|
+
export { fc }
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Assert that a property holds for all values
|
|
555
|
+
*/
|
|
556
|
+
export declare function forAll<T extends unknown[]>(arbitraries: {
|
|
557
|
+
[K in keyof T]: fc.Arbitrary<T[K]>;
|
|
558
|
+
}, predicate: (...args: T) => boolean, config?: PropertyTestConfig): void;
|
|
559
|
+
|
|
560
|
+
export declare interface FuzzTestConfig {
|
|
561
|
+
/** Target component */
|
|
562
|
+
component: string;
|
|
563
|
+
/** Props to fuzz */
|
|
564
|
+
propsToFuzz: string[];
|
|
565
|
+
/** Iterations */
|
|
566
|
+
iterations: number;
|
|
567
|
+
/** Seed for reproducibility */
|
|
568
|
+
seed?: number;
|
|
569
|
+
/** Input generators */
|
|
570
|
+
generators: Record<string, 'string' | 'number' | 'boolean' | 'array' | 'object' | 'null'>;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
export declare interface FuzzTestResult {
|
|
574
|
+
component: string;
|
|
575
|
+
iterations: number;
|
|
576
|
+
crashes: Array<{
|
|
577
|
+
input: Record<string, unknown>;
|
|
578
|
+
error: string;
|
|
579
|
+
seed: number;
|
|
580
|
+
}>;
|
|
581
|
+
passed: boolean;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Generate chromatic command for CI
|
|
586
|
+
*/
|
|
587
|
+
export declare function getChromaticCommand(options?: {
|
|
588
|
+
onlyChanged?: boolean;
|
|
589
|
+
exitZeroOnChanges?: boolean;
|
|
590
|
+
}): string;
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Get all focusable elements within a container.
|
|
594
|
+
*/
|
|
595
|
+
export declare function getFocusableElements(container: HTMLElement): HTMLElement[];
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Get computed styles as object for inline snapshot
|
|
599
|
+
*/
|
|
600
|
+
export declare function getStylesSnapshot(element: ReactElement, properties?: string[], options?: SnapshotOptions): Record<string, string>;
|
|
601
|
+
|
|
602
|
+
export declare interface I18nTestConfig {
|
|
603
|
+
/** Locales to test */
|
|
604
|
+
locales: string[];
|
|
605
|
+
/** RTL locales */
|
|
606
|
+
rtlLocales: string[];
|
|
607
|
+
/** Check for missing translation keys */
|
|
608
|
+
checkMissingKeys: boolean;
|
|
609
|
+
/** Check for hardcoded strings */
|
|
610
|
+
checkHardcodedStrings: boolean;
|
|
611
|
+
/** Pseudo-localization mode */
|
|
612
|
+
pseudoLocalization: boolean;
|
|
613
|
+
/** Max string expansion (%) for layout testing */
|
|
614
|
+
maxExpansion: number;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
export declare interface I18nTestResult {
|
|
618
|
+
locale: string;
|
|
619
|
+
missingKeys: string[];
|
|
620
|
+
hardcodedStrings: Array<{
|
|
621
|
+
file: string;
|
|
622
|
+
line: number;
|
|
623
|
+
text: string;
|
|
624
|
+
}>;
|
|
625
|
+
layoutOverflows: Array<{
|
|
626
|
+
component: string;
|
|
627
|
+
text: string;
|
|
628
|
+
}>;
|
|
629
|
+
rtlIssues: string[];
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Check if a checkbox/toggle is checked.
|
|
634
|
+
*/
|
|
635
|
+
export declare function isChecked(element: HTMLElement): boolean;
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Check if a component is disabled.
|
|
639
|
+
*/
|
|
640
|
+
export declare function isDisabled(element: HTMLElement): boolean;
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Check if a component is expanded.
|
|
644
|
+
*/
|
|
645
|
+
export declare function isExpanded(element: HTMLElement): boolean;
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Assert that an element is focusable.
|
|
649
|
+
*/
|
|
650
|
+
export declare function isFocusable(element: HTMLElement): boolean;
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Check if a component is in loading state.
|
|
654
|
+
*/
|
|
655
|
+
export declare function isLoading(element: HTMLElement): boolean;
|
|
656
|
+
|
|
657
|
+
export declare interface LoadTestConfig {
|
|
658
|
+
/** Concurrent users */
|
|
659
|
+
concurrentUsers: number;
|
|
660
|
+
/** Ramp-up time (s) */
|
|
661
|
+
rampUpSeconds: number;
|
|
662
|
+
/** Duration (s) */
|
|
663
|
+
durationSeconds: number;
|
|
664
|
+
/** Target endpoint / component */
|
|
665
|
+
target: string;
|
|
666
|
+
/** Acceptable response time (ms) */
|
|
667
|
+
maxResponseTime: number;
|
|
668
|
+
/** Error rate threshold (%) */
|
|
669
|
+
maxErrorRate: number;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
export declare interface LoadTestResult {
|
|
673
|
+
totalRequests: number;
|
|
674
|
+
successful: number;
|
|
675
|
+
failed: number;
|
|
676
|
+
avgResponseTime: number;
|
|
677
|
+
p95ResponseTime: number;
|
|
678
|
+
p99ResponseTime: number;
|
|
679
|
+
requestsPerSecond: number;
|
|
680
|
+
errorRate: number;
|
|
681
|
+
passed: boolean;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Measure page performance metrics
|
|
686
|
+
*/
|
|
687
|
+
export declare function measurePerformance(page: Page): Promise<{
|
|
688
|
+
fcp: number;
|
|
689
|
+
lcp: number;
|
|
690
|
+
cls: number;
|
|
691
|
+
ttfb: number;
|
|
692
|
+
tti: number;
|
|
693
|
+
}>;
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Mock REST API endpoints
|
|
697
|
+
*/
|
|
698
|
+
export declare function mockAPI(page: Page, mocks: Array<{
|
|
699
|
+
url: string | RegExp;
|
|
700
|
+
method?: string;
|
|
701
|
+
status?: number;
|
|
702
|
+
body?: unknown;
|
|
703
|
+
delay?: number;
|
|
704
|
+
}>): Promise<void>;
|
|
705
|
+
|
|
706
|
+
export declare interface MockDataSource<T> {
|
|
707
|
+
key: string;
|
|
708
|
+
load: () => Promise<{
|
|
709
|
+
data: T[];
|
|
710
|
+
totalCount: number;
|
|
711
|
+
}>;
|
|
712
|
+
insert: (item: T) => Promise<T>;
|
|
713
|
+
update: (key: unknown, values: Partial<T>) => Promise<void>;
|
|
714
|
+
remove: (key: unknown) => Promise<void>;
|
|
715
|
+
getData: () => T[];
|
|
716
|
+
reset: () => void;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
export declare interface MockDataSourceOptions<T> {
|
|
720
|
+
data: T[];
|
|
721
|
+
delay?: number;
|
|
722
|
+
keyField?: string;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Mock GraphQL operations
|
|
727
|
+
*/
|
|
728
|
+
export declare function mockGraphQL(page: Page, endpoint: string, mocks: Record<string, unknown>): Promise<void>;
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Mock SignalR connection
|
|
732
|
+
*/
|
|
733
|
+
export declare function mockSignalR(page: Page, hubUrl: string, handlers: Record<string, (...args: unknown[]) => void>): Promise<{
|
|
734
|
+
send: (method: string, ...args: unknown[]) => Promise<void>;
|
|
735
|
+
}>;
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Selectors for querying Nice2Dev components in tests.
|
|
739
|
+
* Every nice component renders a data-testid by convention.
|
|
740
|
+
*
|
|
741
|
+
* @example
|
|
742
|
+
* import { niceSelectors } from '@nice2dev/testing';
|
|
743
|
+
* const btn = screen.getByTestId(niceSelectors.button('submit'));
|
|
744
|
+
* const grid = screen.getByTestId(niceSelectors.dataGrid());
|
|
745
|
+
*/
|
|
746
|
+
export declare const niceSelectors: {
|
|
747
|
+
button: (id?: string) => string;
|
|
748
|
+
textInput: (id?: string) => string;
|
|
749
|
+
numberInput: (id?: string) => string;
|
|
750
|
+
select: (id?: string) => string;
|
|
751
|
+
checkbox: (id?: string) => string;
|
|
752
|
+
toggle: (id?: string) => string;
|
|
753
|
+
datePicker: (id?: string) => string;
|
|
754
|
+
dataGrid: (id?: string) => string;
|
|
755
|
+
table: (id?: string) => string;
|
|
756
|
+
list: (id?: string) => string;
|
|
757
|
+
treeView: (id?: string) => string;
|
|
758
|
+
modal: (id?: string) => string;
|
|
759
|
+
drawer: (id?: string) => string;
|
|
760
|
+
form: (id?: string) => string;
|
|
761
|
+
tabs: (id?: string) => string;
|
|
762
|
+
menu: (id?: string) => string;
|
|
763
|
+
chart: (id?: string) => string;
|
|
764
|
+
scheduler: (id?: string) => string;
|
|
765
|
+
gantt: (id?: string) => string;
|
|
766
|
+
diagram: (id?: string) => string;
|
|
767
|
+
toast: (id?: string) => string;
|
|
768
|
+
alert: (id?: string) => string;
|
|
769
|
+
badge: (id?: string) => string;
|
|
770
|
+
avatar: (id?: string) => string;
|
|
771
|
+
progress: (id?: string) => string;
|
|
772
|
+
skeleton: (id?: string) => string;
|
|
773
|
+
spinner: (id?: string) => string;
|
|
774
|
+
card: (id?: string) => string;
|
|
775
|
+
accordion: (id?: string) => string;
|
|
776
|
+
breadcrumb: (id?: string) => string;
|
|
777
|
+
pagination: (id?: string) => string;
|
|
778
|
+
toolbar: (id?: string) => string;
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Helper class for testing Nice2Dev components
|
|
783
|
+
*/
|
|
784
|
+
export declare class NiceTestHelpers {
|
|
785
|
+
private page;
|
|
786
|
+
constructor(page: Page);
|
|
787
|
+
dataGrid: {
|
|
788
|
+
/**
|
|
789
|
+
* Wait for DataGrid to fully load
|
|
790
|
+
*/
|
|
791
|
+
waitForLoad: (selector?: string) => Promise<void>;
|
|
792
|
+
/**
|
|
793
|
+
* Select a row by index
|
|
794
|
+
*/
|
|
795
|
+
selectRow: (index: number, selector?: string) => Promise<void>;
|
|
796
|
+
/**
|
|
797
|
+
* Sort by column
|
|
798
|
+
*/
|
|
799
|
+
sortByColumn: (columnId: string, selector?: string) => Promise<void>;
|
|
800
|
+
/**
|
|
801
|
+
* Filter by column
|
|
802
|
+
*/
|
|
803
|
+
filterColumn: (columnId: string, value: string, selector?: string) => Promise<void>;
|
|
804
|
+
/**
|
|
805
|
+
* Get row count
|
|
806
|
+
*/
|
|
807
|
+
getRowCount: (selector?: string) => Promise<number>;
|
|
808
|
+
/**
|
|
809
|
+
* Get cell value
|
|
810
|
+
*/
|
|
811
|
+
getCellValue: (rowIndex: number, columnId: string, selector?: string) => Promise<string | null>;
|
|
812
|
+
};
|
|
813
|
+
form: {
|
|
814
|
+
/**
|
|
815
|
+
* Fill form field
|
|
816
|
+
*/
|
|
817
|
+
fillField: (fieldName: string, value: string) => Promise<void>;
|
|
818
|
+
/**
|
|
819
|
+
* Submit form
|
|
820
|
+
*/
|
|
821
|
+
submit: (selector?: string) => Promise<void>;
|
|
822
|
+
/**
|
|
823
|
+
* Check validation errors
|
|
824
|
+
*/
|
|
825
|
+
getErrors: (selector?: string) => Promise<string[]>;
|
|
826
|
+
/**
|
|
827
|
+
* Wait for form to be ready
|
|
828
|
+
*/
|
|
829
|
+
waitForReady: (selector?: string) => Promise<void>;
|
|
830
|
+
};
|
|
831
|
+
modal: {
|
|
832
|
+
/**
|
|
833
|
+
* Wait for modal to open
|
|
834
|
+
*/
|
|
835
|
+
waitForOpen: (selector?: string) => Promise<void>;
|
|
836
|
+
/**
|
|
837
|
+
* Wait for modal to close
|
|
838
|
+
*/
|
|
839
|
+
waitForClose: (selector?: string) => Promise<void>;
|
|
840
|
+
/**
|
|
841
|
+
* Close modal
|
|
842
|
+
*/
|
|
843
|
+
close: (selector?: string) => Promise<void>;
|
|
844
|
+
/**
|
|
845
|
+
* Click modal action button
|
|
846
|
+
*/
|
|
847
|
+
clickAction: (action: "confirm" | "cancel", selector?: string) => Promise<void>;
|
|
848
|
+
};
|
|
849
|
+
navigation: {
|
|
850
|
+
/**
|
|
851
|
+
* Navigate via sidebar
|
|
852
|
+
*/
|
|
853
|
+
navigateToRoute: (route: string) => Promise<void>;
|
|
854
|
+
/**
|
|
855
|
+
* Open navigation menu (mobile)
|
|
856
|
+
*/
|
|
857
|
+
openMenu: () => Promise<void>;
|
|
858
|
+
/**
|
|
859
|
+
* Check active route
|
|
860
|
+
*/
|
|
861
|
+
getActiveRoute: () => Promise<string | null>;
|
|
862
|
+
};
|
|
863
|
+
keyboard: {
|
|
864
|
+
/**
|
|
865
|
+
* Tab through focusable elements
|
|
866
|
+
*/
|
|
867
|
+
tabThrough: (count: number) => Promise<void>;
|
|
868
|
+
/**
|
|
869
|
+
* Shift+Tab through focusable elements
|
|
870
|
+
*/
|
|
871
|
+
shiftTabThrough: (count: number) => Promise<void>;
|
|
872
|
+
/**
|
|
873
|
+
* Press Enter on focused element
|
|
874
|
+
*/
|
|
875
|
+
activate: () => Promise<void>;
|
|
876
|
+
/**
|
|
877
|
+
* Press Escape
|
|
878
|
+
*/
|
|
879
|
+
escape: () => Promise<void>;
|
|
880
|
+
/**
|
|
881
|
+
* Navigate with arrow keys
|
|
882
|
+
*/
|
|
883
|
+
arrow: (direction: "Up" | "Down" | "Left" | "Right") => Promise<void>;
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Wraps components with all necessary providers for testing.
|
|
889
|
+
* Creates a clean environment with i18n, theme, and a11y contexts.
|
|
890
|
+
*
|
|
891
|
+
* @example
|
|
892
|
+
* render(<NiceButton>Click</NiceButton>, { wrapper: NiceTestWrapper });
|
|
893
|
+
*
|
|
894
|
+
* // Or with options:
|
|
895
|
+
* const Wrapper = ({ children }) => (
|
|
896
|
+
* <NiceTestWrapper direction="rtl">{children}</NiceTestWrapper>
|
|
897
|
+
* );
|
|
898
|
+
* render(<NiceButton>Click</NiceButton>, { wrapper: Wrapper });
|
|
899
|
+
*/
|
|
900
|
+
export declare const NiceTestWrapper: default_2.FC<NiceTestWrapperProps>;
|
|
901
|
+
|
|
902
|
+
export declare interface NiceTestWrapperProps {
|
|
903
|
+
children: default_2.ReactNode;
|
|
904
|
+
/** Optional theme to apply */
|
|
905
|
+
theme?: Record<string, unknown>;
|
|
906
|
+
/** Direction for RTL testing */
|
|
907
|
+
direction?: 'ltr' | 'rtl';
|
|
908
|
+
/** Custom translation function */
|
|
909
|
+
t?: (key: string, defaultValue: string) => string;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Percy configuration for CI
|
|
914
|
+
* Use with @percy/cli
|
|
915
|
+
*
|
|
916
|
+
* @example
|
|
917
|
+
* ```yaml
|
|
918
|
+
* # .percy.yml
|
|
919
|
+
* version: 2
|
|
920
|
+
* snapshot:
|
|
921
|
+
* widths: [375, 768, 1280, 1920]
|
|
922
|
+
* min-height: 1024
|
|
923
|
+
* ```
|
|
924
|
+
*/
|
|
925
|
+
export declare const percyConfig: {
|
|
926
|
+
version: number;
|
|
927
|
+
snapshot: {
|
|
928
|
+
widths: number[];
|
|
929
|
+
minHeight: number;
|
|
930
|
+
percyCSS: string;
|
|
931
|
+
};
|
|
932
|
+
discovery: {
|
|
933
|
+
networkIdleTimeout: number;
|
|
934
|
+
allowedHostnames: string[];
|
|
935
|
+
};
|
|
936
|
+
};
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Percy snapshot helper
|
|
940
|
+
*/
|
|
941
|
+
export declare function percySnapshot(name: string, options?: {
|
|
942
|
+
widths?: number[];
|
|
943
|
+
minHeight?: number;
|
|
944
|
+
scope?: string;
|
|
945
|
+
enableJavaScript?: boolean;
|
|
946
|
+
}): {
|
|
947
|
+
widths?: number[];
|
|
948
|
+
minHeight?: number;
|
|
949
|
+
scope?: string;
|
|
950
|
+
enableJavaScript?: boolean;
|
|
951
|
+
name: string;
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
export declare interface PerformanceBenchmarkConfig {
|
|
955
|
+
/** Components to benchmark */
|
|
956
|
+
components: string[];
|
|
957
|
+
/** Metrics to track */
|
|
958
|
+
metrics: Array<'render-time' | 'rerender-time' | 'memory' | 'layout-shift' | 'interaction-delay'>;
|
|
959
|
+
/** Iterations per benchmark */
|
|
960
|
+
iterations: number;
|
|
961
|
+
/** Warm-up runs */
|
|
962
|
+
warmUp: number;
|
|
963
|
+
/** Threshold for regression (%) */
|
|
964
|
+
regressionThreshold: number;
|
|
965
|
+
/** Budget (ms) */
|
|
966
|
+
budgets: Record<string, number>;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
export declare interface PropertyTestConfig {
|
|
970
|
+
/** Number of test runs (default: 100) */
|
|
971
|
+
numRuns?: number;
|
|
972
|
+
/** Seed for reproducibility */
|
|
973
|
+
seed?: number;
|
|
974
|
+
/** Timeout per run in ms */
|
|
975
|
+
timeout?: number;
|
|
976
|
+
/** Enable verbose logging */
|
|
977
|
+
verbose?: boolean;
|
|
978
|
+
/** Example values to always test */
|
|
979
|
+
examples?: unknown[][];
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* Render component and return serialized HTML for inline snapshot
|
|
984
|
+
*/
|
|
985
|
+
export declare function renderToSnapshot(element: ReactElement, options?: SnapshotOptions): string;
|
|
986
|
+
|
|
987
|
+
export declare interface ResponsiveSnapshotOptions extends SnapshotOptions {
|
|
988
|
+
/** Breakpoints to test [name, width] */
|
|
989
|
+
breakpoints?: [string, number][];
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
export declare type ScanType = 'sast' | 'dast' | 'sca' | 'secret-scan';
|
|
993
|
+
|
|
994
|
+
export declare interface SecurityFinding {
|
|
995
|
+
id: string;
|
|
996
|
+
type: ScanType;
|
|
997
|
+
severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
998
|
+
title: string;
|
|
999
|
+
description: string;
|
|
1000
|
+
file?: string;
|
|
1001
|
+
line?: number;
|
|
1002
|
+
cve?: string;
|
|
1003
|
+
cwe?: string;
|
|
1004
|
+
recommendation: string;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
export declare interface SecurityScanConfig {
|
|
1008
|
+
/** Scan type */
|
|
1009
|
+
scanType: ScanType;
|
|
1010
|
+
/** Target path / URL */
|
|
1011
|
+
target: string;
|
|
1012
|
+
/** Severity threshold */
|
|
1013
|
+
failOnSeverity: 'critical' | 'high' | 'medium' | 'low';
|
|
1014
|
+
/** Ignored CVEs */
|
|
1015
|
+
ignoredCves: string[];
|
|
1016
|
+
/** Report format */
|
|
1017
|
+
reportFormat: 'sarif' | 'json' | 'html';
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
export declare interface SecurityScanResult {
|
|
1021
|
+
scanType: ScanType;
|
|
1022
|
+
target: string;
|
|
1023
|
+
findings: SecurityFinding[];
|
|
1024
|
+
passed: boolean;
|
|
1025
|
+
scanDuration: number;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* Simulate a click with optional modifier keys.
|
|
1030
|
+
*/
|
|
1031
|
+
export declare function simulateClick(element: HTMLElement, options?: {
|
|
1032
|
+
ctrlKey?: boolean;
|
|
1033
|
+
shiftKey?: boolean;
|
|
1034
|
+
altKey?: boolean;
|
|
1035
|
+
metaKey?: boolean;
|
|
1036
|
+
}): void;
|
|
1037
|
+
|
|
1038
|
+
/**
|
|
1039
|
+
* Simulate keyboard events for testing keyboard navigation.
|
|
1040
|
+
*
|
|
1041
|
+
* @example
|
|
1042
|
+
* const el = screen.getByTestId('nice-select');
|
|
1043
|
+
* simulateKeyboard(el, 'ArrowDown');
|
|
1044
|
+
* simulateKeyboard(el, 'Enter');
|
|
1045
|
+
*/
|
|
1046
|
+
export declare function simulateKeyboard(element: HTMLElement, key: string, options?: Partial<KeyboardEventInit>): void;
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Simulate typing into an input element.
|
|
1050
|
+
* Dispatches input and change events as @testing-library would.
|
|
1051
|
+
*/
|
|
1052
|
+
export declare function simulateType(element: HTMLInputElement | HTMLTextAreaElement, text: string): void;
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Create a snapshot of accessibility-relevant attributes
|
|
1056
|
+
*/
|
|
1057
|
+
export declare function snapshotA11y(element: ReactElement, options?: SnapshotOptions): void;
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Create a snapshot test for a component's rendered structure
|
|
1061
|
+
*
|
|
1062
|
+
* @example
|
|
1063
|
+
* ```tsx
|
|
1064
|
+
* describe('Button', () => {
|
|
1065
|
+
* snapshotComponent(<Button variant="primary">Click</Button>);
|
|
1066
|
+
* snapshotComponent(<Button variant="secondary">Click</Button>);
|
|
1067
|
+
* snapshotComponent(<Button disabled>Disabled</Button>);
|
|
1068
|
+
* });
|
|
1069
|
+
* ```
|
|
1070
|
+
*/
|
|
1071
|
+
export declare function snapshotComponent(element: ReactElement, options?: SnapshotOptions): void;
|
|
1072
|
+
|
|
1073
|
+
export declare interface SnapshotOptions {
|
|
1074
|
+
/** Test description name */
|
|
1075
|
+
name?: string;
|
|
1076
|
+
/** Wrapper component (e.g., ThemeProvider) */
|
|
1077
|
+
wrapper?: React.ComponentType<{
|
|
1078
|
+
children: ReactNode;
|
|
1079
|
+
}>;
|
|
1080
|
+
/** Additional props to apply to wrapper */
|
|
1081
|
+
wrapperProps?: Record<string, unknown>;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
/**
|
|
1085
|
+
* Create snapshots at different viewport sizes
|
|
1086
|
+
*
|
|
1087
|
+
* @example
|
|
1088
|
+
* ```tsx
|
|
1089
|
+
* snapshotResponsive(<Navigation />, {
|
|
1090
|
+
* breakpoints: [
|
|
1091
|
+
* ['mobile', 375],
|
|
1092
|
+
* ['tablet', 768],
|
|
1093
|
+
* ['desktop', 1024],
|
|
1094
|
+
* ],
|
|
1095
|
+
* });
|
|
1096
|
+
* ```
|
|
1097
|
+
*/
|
|
1098
|
+
export declare function snapshotResponsive(element: ReactElement, options?: ResponsiveSnapshotOptions): void;
|
|
1099
|
+
|
|
1100
|
+
/**
|
|
1101
|
+
* Create snapshots for styles in different states
|
|
1102
|
+
*
|
|
1103
|
+
* @example
|
|
1104
|
+
* ```tsx
|
|
1105
|
+
* snapshotStateStyles(
|
|
1106
|
+
* <Button>Click</Button>,
|
|
1107
|
+
* {
|
|
1108
|
+
* default: {},
|
|
1109
|
+
* hover: { pseudo: ':hover' },
|
|
1110
|
+
* focus: { pseudo: ':focus' },
|
|
1111
|
+
* disabled: { props: { disabled: true } },
|
|
1112
|
+
* }
|
|
1113
|
+
* );
|
|
1114
|
+
* ```
|
|
1115
|
+
*/
|
|
1116
|
+
export declare function snapshotStateStyles(Component: React.ComponentType<Record<string, unknown>>, baseProps: Record<string, unknown>, states: Record<string, {
|
|
1117
|
+
props?: Record<string, unknown>;
|
|
1118
|
+
pseudo?: string;
|
|
1119
|
+
}>, options?: StyleSnapshotOptions): void;
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* Create a snapshot of computed styles
|
|
1123
|
+
*
|
|
1124
|
+
* @example
|
|
1125
|
+
* ```tsx
|
|
1126
|
+
* snapshotStyles(<Button>Click</Button>, ['background-color', 'color', 'padding']);
|
|
1127
|
+
* ```
|
|
1128
|
+
*/
|
|
1129
|
+
export declare function snapshotStyles(element: ReactElement, options?: StyleSnapshotOptions): void;
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* Create snapshots for different themes
|
|
1133
|
+
*
|
|
1134
|
+
* @example
|
|
1135
|
+
* ```tsx
|
|
1136
|
+
* snapshotThemes(
|
|
1137
|
+
* <Button>Click</Button>,
|
|
1138
|
+
* ThemeProvider,
|
|
1139
|
+
* [
|
|
1140
|
+
* { name: 'light', theme: lightTheme },
|
|
1141
|
+
* { name: 'dark', theme: darkTheme },
|
|
1142
|
+
* ]
|
|
1143
|
+
* );
|
|
1144
|
+
* ```
|
|
1145
|
+
*/
|
|
1146
|
+
export declare function snapshotThemes<T>(element: ReactElement, ThemeProvider: React.ComponentType<{
|
|
1147
|
+
theme: T;
|
|
1148
|
+
children: ReactNode;
|
|
1149
|
+
}>, themes: Array<{
|
|
1150
|
+
name: string;
|
|
1151
|
+
theme: T;
|
|
1152
|
+
}>, options?: StyleSnapshotOptions): void;
|
|
1153
|
+
|
|
1154
|
+
/**
|
|
1155
|
+
* Create multiple snapshot tests for different variants
|
|
1156
|
+
*
|
|
1157
|
+
* @example
|
|
1158
|
+
* ```tsx
|
|
1159
|
+
* snapshotVariants(
|
|
1160
|
+
* Button,
|
|
1161
|
+
* { children: 'Click me' },
|
|
1162
|
+
* { variant: ['primary', 'secondary', 'ghost'] }
|
|
1163
|
+
* );
|
|
1164
|
+
* ```
|
|
1165
|
+
*/
|
|
1166
|
+
export declare function snapshotVariants<P extends Record<string, unknown>>(Component: React.ComponentType<P>, baseProps: Partial<P>, variants: Partial<{
|
|
1167
|
+
[K in keyof P]: P[K][];
|
|
1168
|
+
}>, options?: SnapshotOptions): void;
|
|
1169
|
+
|
|
1170
|
+
export declare interface StressTestConfig {
|
|
1171
|
+
/** Test type */
|
|
1172
|
+
type: 'large-file' | 'large-dataset' | 'deep-tree' | 'many-components';
|
|
1173
|
+
/** Scale factor */
|
|
1174
|
+
itemCount: number;
|
|
1175
|
+
/** Duration (ms) */
|
|
1176
|
+
duration: number;
|
|
1177
|
+
/** Memory limit (MB) */
|
|
1178
|
+
memoryLimit: number;
|
|
1179
|
+
/** Acceptable frame drops (%) */
|
|
1180
|
+
maxFrameDropPercent: number;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
export declare interface StressTestResult {
|
|
1184
|
+
type: string;
|
|
1185
|
+
itemCount: number;
|
|
1186
|
+
duration: number;
|
|
1187
|
+
peakMemoryMb: number;
|
|
1188
|
+
averageFps: number;
|
|
1189
|
+
frameDropPercent: number;
|
|
1190
|
+
passed: boolean;
|
|
1191
|
+
errors: string[];
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
export declare interface StyleSnapshotOptions extends SnapshotOptions {
|
|
1195
|
+
/** CSS properties to capture */
|
|
1196
|
+
properties?: string[];
|
|
1197
|
+
/** Pseudo-element to capture (e.g., '::before') */
|
|
1198
|
+
pseudo?: string;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
export declare interface TelemetryConfig {
|
|
1202
|
+
/** Opt-in required */
|
|
1203
|
+
optInRequired: boolean;
|
|
1204
|
+
/** Endpoint */
|
|
1205
|
+
endpoint: string;
|
|
1206
|
+
/** Events to track */
|
|
1207
|
+
events: Array<'click' | 'navigation' | 'error' | 'performance' | 'custom'>;
|
|
1208
|
+
/** Sampling rate (0-1) */
|
|
1209
|
+
samplingRate: number;
|
|
1210
|
+
/** Session recording */
|
|
1211
|
+
sessionRecording: boolean;
|
|
1212
|
+
/** PII masking */
|
|
1213
|
+
piiMasking: boolean;
|
|
1214
|
+
/** Batch size */
|
|
1215
|
+
batchSize: number;
|
|
1216
|
+
/** Flush interval (ms) */
|
|
1217
|
+
flushInterval: number;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Generate consistent data-testid attributes.
|
|
1222
|
+
*
|
|
1223
|
+
* @example
|
|
1224
|
+
* testId('nice-button', 'submit') // 'nice-button-submit'
|
|
1225
|
+
* testId('nice-datagrid', 'row', 3) // 'nice-datagrid-row-3'
|
|
1226
|
+
*/
|
|
1227
|
+
export declare function testId(...parts: (string | number)[]): string;
|
|
1228
|
+
|
|
1229
|
+
/**
|
|
1230
|
+
* Create a model-based test
|
|
1231
|
+
*
|
|
1232
|
+
* @example
|
|
1233
|
+
* ```ts
|
|
1234
|
+
* const counterCommands = fc.commands([
|
|
1235
|
+
* fc.constant({ check: () => true, run: (m, r) => { m.value++; r.increment(); }, toString: () => 'increment' }),
|
|
1236
|
+
* fc.constant({ check: (m) => m.value > 0, run: (m, r) => { m.value--; r.decrement(); }, toString: () => 'decrement' }),
|
|
1237
|
+
* ]);
|
|
1238
|
+
*
|
|
1239
|
+
* testModel('Counter', { value: 0 }, () => new Counter(), counterCommands);
|
|
1240
|
+
* ```
|
|
1241
|
+
*/
|
|
1242
|
+
export declare function testModel<Model extends object, Real>(name: string, initialModel: () => Model, initialReal: () => Real, commands: fc.Arbitrary<fc.Command<Model, Real>[]>, config?: PropertyTestConfig): void;
|
|
1243
|
+
|
|
1244
|
+
/**
|
|
1245
|
+
* Run a property-based test with Vitest integration
|
|
1246
|
+
*
|
|
1247
|
+
* @example
|
|
1248
|
+
* ```ts
|
|
1249
|
+
* testProperty(
|
|
1250
|
+
* 'sorting is idempotent',
|
|
1251
|
+
* [fc.array(fc.integer())],
|
|
1252
|
+
* (arr) => {
|
|
1253
|
+
* const sorted = arr.sort((a, b) => a - b);
|
|
1254
|
+
* const sortedAgain = [...sorted].sort((a, b) => a - b);
|
|
1255
|
+
* expect(sorted).toEqual(sortedAgain);
|
|
1256
|
+
* }
|
|
1257
|
+
* );
|
|
1258
|
+
* ```
|
|
1259
|
+
*/
|
|
1260
|
+
export declare function testProperty<T extends unknown[]>(name: string, arbitraries: {
|
|
1261
|
+
[K in keyof T]: fc.Arbitrary<T[K]>;
|
|
1262
|
+
}, predicate: (...args: T) => void | Promise<void>, config?: PropertyTestConfig): void;
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* Run a synchronous property-based test
|
|
1266
|
+
*/
|
|
1267
|
+
export declare function testPropertySync<T extends unknown[]>(name: string, arbitraries: {
|
|
1268
|
+
[K in keyof T]: fc.Arbitrary<T[K]>;
|
|
1269
|
+
}, predicate: (...args: T) => void, config?: PropertyTestConfig): void;
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* Standard breakpoints for responsive visual testing
|
|
1273
|
+
*/
|
|
1274
|
+
export declare const VISUAL_BREAKPOINTS: {
|
|
1275
|
+
readonly mobile: {
|
|
1276
|
+
readonly width: 375;
|
|
1277
|
+
readonly height: 667;
|
|
1278
|
+
};
|
|
1279
|
+
readonly mobileLarge: {
|
|
1280
|
+
readonly width: 414;
|
|
1281
|
+
readonly height: 896;
|
|
1282
|
+
};
|
|
1283
|
+
readonly tablet: {
|
|
1284
|
+
readonly width: 768;
|
|
1285
|
+
readonly height: 1024;
|
|
1286
|
+
};
|
|
1287
|
+
readonly tabletLandscape: {
|
|
1288
|
+
readonly width: 1024;
|
|
1289
|
+
readonly height: 768;
|
|
1290
|
+
};
|
|
1291
|
+
readonly desktop: {
|
|
1292
|
+
readonly width: 1280;
|
|
1293
|
+
readonly height: 800;
|
|
1294
|
+
};
|
|
1295
|
+
readonly desktopLarge: {
|
|
1296
|
+
readonly width: 1440;
|
|
1297
|
+
readonly height: 900;
|
|
1298
|
+
};
|
|
1299
|
+
readonly ultrawide: {
|
|
1300
|
+
readonly width: 1920;
|
|
1301
|
+
readonly height: 1080;
|
|
1302
|
+
};
|
|
1303
|
+
};
|
|
1304
|
+
|
|
1305
|
+
/**
|
|
1306
|
+
* Theme configurations for visual testing
|
|
1307
|
+
*/
|
|
1308
|
+
export declare const VISUAL_THEMES: {
|
|
1309
|
+
readonly light: {
|
|
1310
|
+
readonly name: "light";
|
|
1311
|
+
readonly className: "theme-light";
|
|
1312
|
+
readonly background: "#ffffff";
|
|
1313
|
+
};
|
|
1314
|
+
readonly dark: {
|
|
1315
|
+
readonly name: "dark";
|
|
1316
|
+
readonly className: "theme-dark";
|
|
1317
|
+
readonly background: "#1a1a1a";
|
|
1318
|
+
};
|
|
1319
|
+
readonly highContrast: {
|
|
1320
|
+
readonly name: "high-contrast";
|
|
1321
|
+
readonly className: "theme-high-contrast";
|
|
1322
|
+
readonly background: "#000000";
|
|
1323
|
+
};
|
|
1324
|
+
};
|
|
1325
|
+
|
|
1326
|
+
export declare interface VisualDiffResult {
|
|
1327
|
+
componentName: string;
|
|
1328
|
+
viewport: string;
|
|
1329
|
+
matchPercentage: number;
|
|
1330
|
+
passed: boolean;
|
|
1331
|
+
baselineImage: string;
|
|
1332
|
+
currentImage: string;
|
|
1333
|
+
diffImage?: string;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
export declare interface VisualRegressionConfig {
|
|
1337
|
+
/** Screenshot directory */
|
|
1338
|
+
snapshotDir: string;
|
|
1339
|
+
/** Diff threshold (0-1) */
|
|
1340
|
+
diffThreshold: number;
|
|
1341
|
+
/** Update baseline on pass */
|
|
1342
|
+
updateBaseline: boolean;
|
|
1343
|
+
/** Viewports */
|
|
1344
|
+
viewports: Array<{
|
|
1345
|
+
width: number;
|
|
1346
|
+
height: number;
|
|
1347
|
+
name: string;
|
|
1348
|
+
}>;
|
|
1349
|
+
/** CSS animations disabled */
|
|
1350
|
+
disableAnimations: boolean;
|
|
1351
|
+
/** Mask dynamic regions */
|
|
1352
|
+
maskSelectors: string[];
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
export declare interface VisualSnapshot {
|
|
1356
|
+
name: string;
|
|
1357
|
+
viewport: {
|
|
1358
|
+
width: number;
|
|
1359
|
+
height: number;
|
|
1360
|
+
};
|
|
1361
|
+
theme: string;
|
|
1362
|
+
direction: 'ltr' | 'rtl';
|
|
1363
|
+
story?: string;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
export declare interface VisualTestConfig {
|
|
1367
|
+
/** Component name for screenshot naming */
|
|
1368
|
+
component: string;
|
|
1369
|
+
/** Story names to test */
|
|
1370
|
+
stories?: string[];
|
|
1371
|
+
/** Breakpoints to test */
|
|
1372
|
+
breakpoints?: (keyof typeof VISUAL_BREAKPOINTS)[];
|
|
1373
|
+
/** Themes to test */
|
|
1374
|
+
themes?: (keyof typeof VISUAL_THEMES)[];
|
|
1375
|
+
/** Test RTL layout */
|
|
1376
|
+
rtl?: boolean;
|
|
1377
|
+
/** Custom viewport sizes */
|
|
1378
|
+
customViewports?: Array<{
|
|
1379
|
+
name: string;
|
|
1380
|
+
width: number;
|
|
1381
|
+
height: number;
|
|
1382
|
+
}>;
|
|
1383
|
+
/** Wait time before screenshot (ms) */
|
|
1384
|
+
waitTime?: number;
|
|
1385
|
+
/** Tolerance for pixel differences (0-1) */
|
|
1386
|
+
tolerance?: number;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
/**
|
|
1390
|
+
* Storybook preset with visual testing addons
|
|
1391
|
+
*/
|
|
1392
|
+
export declare const visualTestingAddons: string[];
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* Global types for Storybook toolbar
|
|
1396
|
+
* Add to .storybook/preview.tsx
|
|
1397
|
+
*
|
|
1398
|
+
* @example
|
|
1399
|
+
* ```tsx
|
|
1400
|
+
* export const globalTypes = {
|
|
1401
|
+
* ...visualTestingGlobalTypes,
|
|
1402
|
+
* };
|
|
1403
|
+
* ```
|
|
1404
|
+
*/
|
|
1405
|
+
export declare const visualTestingGlobalTypes: {
|
|
1406
|
+
theme: {
|
|
1407
|
+
name: string;
|
|
1408
|
+
description: string;
|
|
1409
|
+
defaultValue: string;
|
|
1410
|
+
toolbar: {
|
|
1411
|
+
icon: string;
|
|
1412
|
+
items: {
|
|
1413
|
+
value: string;
|
|
1414
|
+
title: string;
|
|
1415
|
+
}[];
|
|
1416
|
+
showName: boolean;
|
|
1417
|
+
};
|
|
1418
|
+
};
|
|
1419
|
+
direction: {
|
|
1420
|
+
name: string;
|
|
1421
|
+
description: string;
|
|
1422
|
+
defaultValue: string;
|
|
1423
|
+
toolbar: {
|
|
1424
|
+
icon: string;
|
|
1425
|
+
items: {
|
|
1426
|
+
value: string;
|
|
1427
|
+
title: string;
|
|
1428
|
+
}[];
|
|
1429
|
+
showName: boolean;
|
|
1430
|
+
};
|
|
1431
|
+
};
|
|
1432
|
+
reducedMotion: {
|
|
1433
|
+
name: string;
|
|
1434
|
+
description: string;
|
|
1435
|
+
defaultValue: boolean;
|
|
1436
|
+
toolbar: {
|
|
1437
|
+
icon: string;
|
|
1438
|
+
items: {
|
|
1439
|
+
value: boolean;
|
|
1440
|
+
title: string;
|
|
1441
|
+
}[];
|
|
1442
|
+
showName: boolean;
|
|
1443
|
+
};
|
|
1444
|
+
};
|
|
1445
|
+
};
|
|
1446
|
+
|
|
1447
|
+
/**
|
|
1448
|
+
* Parameters for visual testing
|
|
1449
|
+
*/
|
|
1450
|
+
export declare const visualTestingParameters: {
|
|
1451
|
+
viewport: {
|
|
1452
|
+
viewports: {
|
|
1453
|
+
mobile: {
|
|
1454
|
+
name: string;
|
|
1455
|
+
styles: {
|
|
1456
|
+
width: string;
|
|
1457
|
+
height: string;
|
|
1458
|
+
};
|
|
1459
|
+
type: "mobile";
|
|
1460
|
+
};
|
|
1461
|
+
mobileLarge: {
|
|
1462
|
+
name: string;
|
|
1463
|
+
styles: {
|
|
1464
|
+
width: string;
|
|
1465
|
+
height: string;
|
|
1466
|
+
};
|
|
1467
|
+
type: "mobile";
|
|
1468
|
+
};
|
|
1469
|
+
tablet: {
|
|
1470
|
+
name: string;
|
|
1471
|
+
styles: {
|
|
1472
|
+
width: string;
|
|
1473
|
+
height: string;
|
|
1474
|
+
};
|
|
1475
|
+
type: "tablet";
|
|
1476
|
+
};
|
|
1477
|
+
desktop: {
|
|
1478
|
+
name: string;
|
|
1479
|
+
styles: {
|
|
1480
|
+
width: string;
|
|
1481
|
+
height: string;
|
|
1482
|
+
};
|
|
1483
|
+
type: "desktop";
|
|
1484
|
+
};
|
|
1485
|
+
desktopLarge: {
|
|
1486
|
+
name: string;
|
|
1487
|
+
styles: {
|
|
1488
|
+
width: string;
|
|
1489
|
+
height: string;
|
|
1490
|
+
};
|
|
1491
|
+
type: "desktop";
|
|
1492
|
+
};
|
|
1493
|
+
ultrawide: {
|
|
1494
|
+
name: string;
|
|
1495
|
+
styles: {
|
|
1496
|
+
width: string;
|
|
1497
|
+
height: string;
|
|
1498
|
+
};
|
|
1499
|
+
type: "desktop";
|
|
1500
|
+
};
|
|
1501
|
+
};
|
|
1502
|
+
defaultViewport: string;
|
|
1503
|
+
};
|
|
1504
|
+
chromatic: {
|
|
1505
|
+
viewports: number[];
|
|
1506
|
+
diffThreshold: number;
|
|
1507
|
+
pauseAnimationAtEnd: boolean;
|
|
1508
|
+
delay: number;
|
|
1509
|
+
};
|
|
1510
|
+
a11y: {
|
|
1511
|
+
element: string;
|
|
1512
|
+
config: {};
|
|
1513
|
+
options: {};
|
|
1514
|
+
manual: boolean;
|
|
1515
|
+
};
|
|
1516
|
+
layout: string;
|
|
1517
|
+
};
|
|
1518
|
+
|
|
1519
|
+
/**
|
|
1520
|
+
* Base Storybook configuration with visual testing
|
|
1521
|
+
*/
|
|
1522
|
+
export declare const visualTestingPreset: Partial<StorybookConfig>;
|
|
1523
|
+
|
|
1524
|
+
/**
|
|
1525
|
+
* Viewport configuration for Storybook
|
|
1526
|
+
*/
|
|
1527
|
+
export declare const visualTestingViewports: {
|
|
1528
|
+
mobile: {
|
|
1529
|
+
name: string;
|
|
1530
|
+
styles: {
|
|
1531
|
+
width: string;
|
|
1532
|
+
height: string;
|
|
1533
|
+
};
|
|
1534
|
+
type: "mobile";
|
|
1535
|
+
};
|
|
1536
|
+
mobileLarge: {
|
|
1537
|
+
name: string;
|
|
1538
|
+
styles: {
|
|
1539
|
+
width: string;
|
|
1540
|
+
height: string;
|
|
1541
|
+
};
|
|
1542
|
+
type: "mobile";
|
|
1543
|
+
};
|
|
1544
|
+
tablet: {
|
|
1545
|
+
name: string;
|
|
1546
|
+
styles: {
|
|
1547
|
+
width: string;
|
|
1548
|
+
height: string;
|
|
1549
|
+
};
|
|
1550
|
+
type: "tablet";
|
|
1551
|
+
};
|
|
1552
|
+
desktop: {
|
|
1553
|
+
name: string;
|
|
1554
|
+
styles: {
|
|
1555
|
+
width: string;
|
|
1556
|
+
height: string;
|
|
1557
|
+
};
|
|
1558
|
+
type: "desktop";
|
|
1559
|
+
};
|
|
1560
|
+
desktopLarge: {
|
|
1561
|
+
name: string;
|
|
1562
|
+
styles: {
|
|
1563
|
+
width: string;
|
|
1564
|
+
height: string;
|
|
1565
|
+
};
|
|
1566
|
+
type: "desktop";
|
|
1567
|
+
};
|
|
1568
|
+
ultrawide: {
|
|
1569
|
+
name: string;
|
|
1570
|
+
styles: {
|
|
1571
|
+
width: string;
|
|
1572
|
+
height: string;
|
|
1573
|
+
};
|
|
1574
|
+
type: "desktop";
|
|
1575
|
+
};
|
|
1576
|
+
};
|
|
1577
|
+
|
|
1578
|
+
/**
|
|
1579
|
+
* Wait for a condition to be true.
|
|
1580
|
+
*/
|
|
1581
|
+
export declare function waitFor(condition: () => boolean | Promise<boolean>, timeout?: number): Promise<void>;
|
|
1582
|
+
|
|
1583
|
+
/**
|
|
1584
|
+
* Wait for an element to appear in the DOM.
|
|
1585
|
+
*/
|
|
1586
|
+
export declare function waitForElement(selector: string, container?: HTMLElement, timeout?: number): Promise<HTMLElement | null>;
|
|
1587
|
+
|
|
1588
|
+
export declare type WcagLevel = 'A' | 'AA' | 'AAA';
|
|
1589
|
+
|
|
1590
|
+
/**
|
|
1591
|
+
* Full visual test configuration
|
|
1592
|
+
*/
|
|
1593
|
+
export declare function withFullVisualTesting<T extends Record<string, unknown>>(story: T, options?: {
|
|
1594
|
+
viewports?: (keyof typeof VISUAL_BREAKPOINTS)[];
|
|
1595
|
+
themes?: (keyof typeof VISUAL_THEMES)[];
|
|
1596
|
+
rtl?: boolean;
|
|
1597
|
+
}): T;
|
|
1598
|
+
|
|
1599
|
+
/**
|
|
1600
|
+
* Configure story for RTL visual testing
|
|
1601
|
+
*/
|
|
1602
|
+
export declare function withRTLTesting<T extends Record<string, unknown>>(story: T): T;
|
|
1603
|
+
|
|
1604
|
+
/**
|
|
1605
|
+
* Configure story for visual testing with themes
|
|
1606
|
+
*/
|
|
1607
|
+
export declare function withVisualThemes<T extends Record<string, unknown>>(story: T, themes?: (keyof typeof VISUAL_THEMES)[]): T;
|
|
1608
|
+
|
|
1609
|
+
/**
|
|
1610
|
+
* Configure story for visual testing with all viewports
|
|
1611
|
+
*/
|
|
1612
|
+
export declare function withVisualViewports<T extends Record<string, unknown>>(story: T, viewports?: (keyof typeof VISUAL_BREAKPOINTS)[]): T & {
|
|
1613
|
+
parameters: {
|
|
1614
|
+
chromatic: typeof chromaticDefaults;
|
|
1615
|
+
};
|
|
1616
|
+
};
|
|
1617
|
+
|
|
1618
|
+
export { }
|