@smartbit4all/playwright-qa 0.1.0
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 +334 -0
- package/dist/config/defaults.d.ts +18 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +25 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +82 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +58 -0
- package/dist/core/index.js.map +1 -0
- package/dist/datapool/index.d.ts +29 -0
- package/dist/datapool/index.d.ts.map +1 -0
- package/dist/datapool/index.js +84 -0
- package/dist/datapool/index.js.map +1 -0
- package/dist/datapool/loader.d.ts +12 -0
- package/dist/datapool/loader.d.ts.map +1 -0
- package/dist/datapool/loader.js +68 -0
- package/dist/datapool/loader.js.map +1 -0
- package/dist/datapool/locale.d.ts +2 -0
- package/dist/datapool/locale.d.ts.map +1 -0
- package/dist/datapool/locale.js +60 -0
- package/dist/datapool/locale.js.map +1 -0
- package/dist/datapool/unique.d.ts +4 -0
- package/dist/datapool/unique.d.ts.map +1 -0
- package/dist/datapool/unique.js +17 -0
- package/dist/datapool/unique.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/screenshot/directory.d.ts +9 -0
- package/dist/screenshot/directory.d.ts.map +1 -0
- package/dist/screenshot/directory.js +122 -0
- package/dist/screenshot/directory.js.map +1 -0
- package/dist/screenshot/highlight.d.ts +10 -0
- package/dist/screenshot/highlight.d.ts.map +1 -0
- package/dist/screenshot/highlight.js +36 -0
- package/dist/screenshot/highlight.js.map +1 -0
- package/dist/screenshot/index.d.ts +12 -0
- package/dist/screenshot/index.d.ts.map +1 -0
- package/dist/screenshot/index.js +54 -0
- package/dist/screenshot/index.js.map +1 -0
- package/dist/seed/index.d.ts +41 -0
- package/dist/seed/index.d.ts.map +1 -0
- package/dist/seed/index.js +143 -0
- package/dist/seed/index.js.map +1 -0
- package/dist/steps/grid.steps.d.ts +21 -0
- package/dist/steps/grid.steps.d.ts.map +1 -0
- package/dist/steps/grid.steps.js +154 -0
- package/dist/steps/grid.steps.js.map +1 -0
- package/dist/steps/index.d.ts +4 -0
- package/dist/steps/index.d.ts.map +1 -0
- package/dist/steps/index.js +14 -0
- package/dist/steps/index.js.map +1 -0
- package/dist/steps/navigation.steps.d.ts +4 -0
- package/dist/steps/navigation.steps.d.ts.map +1 -0
- package/dist/steps/navigation.steps.js +79 -0
- package/dist/steps/navigation.steps.js.map +1 -0
- package/dist/steps/wait.d.ts +8 -0
- package/dist/steps/wait.d.ts.map +1 -0
- package/dist/steps/wait.js +14 -0
- package/dist/steps/wait.js.map +1 -0
- package/package.json +55 -0
- package/templates/ci/playwright-qa-pipeline.yml +54 -0
- package/templates/playwright-qa/datapools/.gitkeep +0 -0
- package/templates/playwright-qa/package.json +14 -0
- package/templates/playwright-qa/playwright.config.ts +20 -0
- package/templates/playwright-qa/steps/.gitkeep +0 -0
- package/templates/playwright-qa/suites/.gitkeep +0 -0
- package/templates/playwright-qa/tsconfig.json +11 -0
- package/templates/playwright-qa/types/.gitkeep +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# @smartbit4all/playwright-qa
|
|
2
|
+
|
|
3
|
+
Playwright-based testing and documentation framework. Provides screenshot utilities, typed datapools with locale support, and TestStep/TestSuite conventions.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @smartbit4all/playwright-qa
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js 20+ and Playwright as a peer dependency:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @playwright/test
|
|
15
|
+
npx playwright install --with-deps chromium
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { test } from '@playwright/test';
|
|
22
|
+
import { initSuite, screenshot } from '@smartbit4all/playwright-qa';
|
|
23
|
+
|
|
24
|
+
test.beforeAll(() => {
|
|
25
|
+
initSuite({ screenshotDir: './screenshots' });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('take a screenshot', async ({ page }) => {
|
|
29
|
+
await page.goto('https://demo.playwright.dev/todomvc');
|
|
30
|
+
await screenshot(page, 'todomvc-home');
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Suite Setup
|
|
35
|
+
|
|
36
|
+
Every TestSuite should call `initSuite()` in `beforeAll`. This single call resets all internal state (config, datapools, screenshot directory, seed handlers) and optionally sets up the screenshot directory.
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { initSuite } from '@smartbit4all/playwright-qa';
|
|
40
|
+
|
|
41
|
+
// With screenshots — cleans the directory and initializes it
|
|
42
|
+
initSuite({ screenshotDir: './screenshots' });
|
|
43
|
+
|
|
44
|
+
// Without screenshots — tests run normally, screenshot calls return null
|
|
45
|
+
initSuite();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
When no `screenshotDir` is provided, all screenshot functions (`screenshot`, `screenshotHighlight`, `screenshotRegion`, `screenshotRegionHighlight`) become no-ops and return `null` instead of a file path. This means TestSteps that include screenshot calls work without modification — no conditional logic needed.
|
|
49
|
+
|
|
50
|
+
## API Reference
|
|
51
|
+
|
|
52
|
+
### Screenshot
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { screenshot, screenshotHighlight, screenshotRegion, screenshotRegionHighlight } from '@smartbit4all/playwright-qa';
|
|
56
|
+
|
|
57
|
+
// Full page screenshot — returns file path, or null if screenshots are disabled
|
|
58
|
+
await screenshot(page, 'page-name');
|
|
59
|
+
await screenshot(page, 'category/page-name'); // name path = subdirectory
|
|
60
|
+
await screenshot(page, 'page-name', { fullPage: true });
|
|
61
|
+
|
|
62
|
+
// Full page with highlighted element
|
|
63
|
+
await screenshotHighlight(page, 'name', '#selector');
|
|
64
|
+
await screenshotHighlight(page, 'name', '#selector', { style: 'subtle' });
|
|
65
|
+
|
|
66
|
+
// Region screenshot (single element)
|
|
67
|
+
await screenshotRegion(page, 'name', '#region-selector');
|
|
68
|
+
|
|
69
|
+
// Region with highlighted element inside
|
|
70
|
+
await screenshotRegionHighlight(page, 'name', '#region', '#highlight');
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
All screenshot functions return `Promise<string | null>`. They return `null` when no screenshot directory has been configured (see [Suite Setup](#suite-setup)).
|
|
74
|
+
|
|
75
|
+
### Datapool
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { datapool, configureDatapool } from '@smartbit4all/playwright-qa';
|
|
79
|
+
|
|
80
|
+
// Global configuration (typically in beforeAll)
|
|
81
|
+
configureDatapool({ locale: 'hu', basePath: './datapools' });
|
|
82
|
+
|
|
83
|
+
// Load a datapool
|
|
84
|
+
const companies = datapool<Company>('companies');
|
|
85
|
+
|
|
86
|
+
// Access items
|
|
87
|
+
const item = companies.byKey('it4all'); // by key (meta.key field, default: "code")
|
|
88
|
+
const derived = companies.derive('it4all', { name: 'Modified' }); // template + overrides
|
|
89
|
+
const first = companies.findFirst('city', 'Budapest'); // first match by field
|
|
90
|
+
const matches = companies.findAll('role', 'admin'); // all matches by field
|
|
91
|
+
const random = companies.random(); // random item
|
|
92
|
+
const all = companies.all(); // all items
|
|
93
|
+
const count = companies.count(); // count
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Built-in Steps
|
|
97
|
+
|
|
98
|
+
The package ships reusable TestSteps for common smartbit4all UI patterns (grid, tree navigation). These are available via a separate subpath import to keep them distinct from the core API:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { selectGridRow, navigateInTree } from '@smartbit4all/playwright-qa/steps';
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Grid
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import {
|
|
108
|
+
selectGridRow,
|
|
109
|
+
filterAndSelectGridRow,
|
|
110
|
+
applyGridFilters,
|
|
111
|
+
clearGridFilters,
|
|
112
|
+
} from '@smartbit4all/playwright-qa/steps';
|
|
113
|
+
|
|
114
|
+
// Find a row by table content (paginates automatically) and double-click it
|
|
115
|
+
await selectGridRow(page, { 'Azonosító': 'DOC-001' });
|
|
116
|
+
|
|
117
|
+
// Find by simple text match
|
|
118
|
+
await selectGridRow(page, 'DOC-001');
|
|
119
|
+
|
|
120
|
+
// Open the row's context menu and click an action
|
|
121
|
+
await selectGridRow(page, { 'Azonosító': 'DOC-001' }, 'Szerkesztés');
|
|
122
|
+
|
|
123
|
+
// Use the filter form above the grid, then select the row
|
|
124
|
+
await filterAndSelectGridRow(page, { 'Azonosító': 'DOC-001' });
|
|
125
|
+
|
|
126
|
+
// Apply/clear filters independently
|
|
127
|
+
await applyGridFilters(page, { 'Név': 'Teszt' });
|
|
128
|
+
await clearGridFilters(page);
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Navigation
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import { navigateToMain, navigateInTree } from '@smartbit4all/playwright-qa/steps';
|
|
135
|
+
|
|
136
|
+
// Click the logo to return to the main screen
|
|
137
|
+
await navigateToMain(page);
|
|
138
|
+
|
|
139
|
+
// Navigate a tree (PrimeNG or Angular Material) — expands intermediate nodes, clicks the last one
|
|
140
|
+
await navigateInTree(page, ['Ügyek']);
|
|
141
|
+
await navigateInTree(page, ['Dokumentumok', 'Tender']);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Utilities
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { waitForAngularIdle } from '@smartbit4all/playwright-qa/steps';
|
|
148
|
+
|
|
149
|
+
// Wait for Angular SPA to settle (double networkidle with pause)
|
|
150
|
+
await waitForAngularIdle(page);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`waitForAngularIdle` is also available for project-specific steps that need the same wait pattern.
|
|
154
|
+
|
|
155
|
+
## Developer Guide — Writing TestSteps
|
|
156
|
+
|
|
157
|
+
TestSteps are simple async functions that implement one atomic UI operation.
|
|
158
|
+
|
|
159
|
+
**Rules:**
|
|
160
|
+
- Receive data as parameters — never import or reference datapools
|
|
161
|
+
- Include locator logic, waits, technical assertions, and screenshots
|
|
162
|
+
- Group related steps in one file per entity/feature
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// steps/company.steps.ts
|
|
166
|
+
import { Page } from '@playwright/test';
|
|
167
|
+
import { screenshot } from '@smartbit4all/playwright-qa';
|
|
168
|
+
|
|
169
|
+
export async function fillCompanyForm(page: Page, company: Company) {
|
|
170
|
+
await page.fill('[data-testid="company-name"]', company.name);
|
|
171
|
+
await page.fill('[data-testid="tax-number"]', company.taxNumber);
|
|
172
|
+
await screenshot(page, 'company/form-filled');
|
|
173
|
+
await page.click('[data-testid="save-button"]');
|
|
174
|
+
await page.waitForSelector('.success-toast');
|
|
175
|
+
await screenshot(page, 'company/saved');
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Organizer Guide — Writing TestSuites
|
|
180
|
+
|
|
181
|
+
TestSuites are Playwright `test.describe` blocks that read like a scenario script.
|
|
182
|
+
|
|
183
|
+
**Rules:**
|
|
184
|
+
- Call `initSuite()` in `beforeAll` to reset state and configure screenshots
|
|
185
|
+
- Initialize datapools in `beforeAll`
|
|
186
|
+
- Select data, then call TestSteps in order
|
|
187
|
+
- Add business-level assertions
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// suites/company-management.suite.ts
|
|
191
|
+
import { test } from '@playwright/test';
|
|
192
|
+
import { initSuite, datapool, unique, type DataPool } from '@smartbit4all/playwright-qa';
|
|
193
|
+
import { navigateToMain, selectGridRow } from '@smartbit4all/playwright-qa/steps';
|
|
194
|
+
import { fillCompanyForm } from '../steps/company.steps';
|
|
195
|
+
import type { Company } from '../types';
|
|
196
|
+
|
|
197
|
+
test.describe('Company Management', () => {
|
|
198
|
+
let companies: DataPool<Company>;
|
|
199
|
+
|
|
200
|
+
test.beforeAll(() => {
|
|
201
|
+
initSuite({ screenshotDir: './screenshots' });
|
|
202
|
+
companies = datapool<Company>('companies');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test('Create new company', async ({ page }) => {
|
|
206
|
+
const company = companies.derive('it4all', { taxNumber: unique('TAX') });
|
|
207
|
+
await fillCompanyForm(page, company);
|
|
208
|
+
await navigateToMain(page);
|
|
209
|
+
await selectGridRow(page, { 'Adószám': company.taxNumber });
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Seed Framework
|
|
215
|
+
|
|
216
|
+
Seed populates application data from datapools — either via API or through the UI.
|
|
217
|
+
|
|
218
|
+
### API Seeding
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { registerSeedHandler, seedViaApi } from '@smartbit4all/playwright-qa';
|
|
222
|
+
|
|
223
|
+
// Register a handler (project-specific)
|
|
224
|
+
registerSeedHandler<Company>('companies', {
|
|
225
|
+
seed: async (company, options) => {
|
|
226
|
+
await fetch(`${options.baseUrl}/api/companies`, {
|
|
227
|
+
method: 'POST',
|
|
228
|
+
headers: { Authorization: `Bearer ${options.authToken}` },
|
|
229
|
+
body: JSON.stringify(company),
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Seed all companies
|
|
235
|
+
const result = await seedViaApi('companies', { baseUrl, authToken });
|
|
236
|
+
console.log(`Seeded ${result.success}/${result.total}`);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### UI Seeding
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
import { registerUiSeedStep, seedViaUi } from '@smartbit4all/playwright-qa';
|
|
243
|
+
|
|
244
|
+
// Register a UI seed step (reuses your TestSteps)
|
|
245
|
+
registerUiSeedStep<Company>('companies', async (page, company) => {
|
|
246
|
+
await fillCompanyForm(page, company);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Seed through the UI
|
|
250
|
+
const result = await seedViaUi(page, 'companies', { basePath: './datapools', locale: 'hu' });
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Seed Profiles
|
|
254
|
+
|
|
255
|
+
For complex data with dependencies, use seed profiles:
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"name": "development-full",
|
|
260
|
+
"order": ["users", "organizations", "companies", "documents"],
|
|
261
|
+
"dependencies": {
|
|
262
|
+
"documents": ["companies", "users"],
|
|
263
|
+
"companies": ["organizations"]
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
import { seed } from '@smartbit4all/playwright-qa';
|
|
270
|
+
|
|
271
|
+
const profile = JSON.parse(fs.readFileSync('seed-profiles/dev.json', 'utf-8'));
|
|
272
|
+
const results = await seed(profile, 'api', { baseUrl, authToken, basePath: './datapools' });
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## CI Setup
|
|
276
|
+
|
|
277
|
+
### Azure DevOps
|
|
278
|
+
|
|
279
|
+
1. Copy `templates/ci/playwright-qa-pipeline.yml` to your project repo
|
|
280
|
+
2. Set pipeline variables:
|
|
281
|
+
- `BASE_URL`: Your application URL (e.g., `https://staging.example.com`)
|
|
282
|
+
- `LOCALE`: Datapool locale (e.g., `hu`)
|
|
283
|
+
3. The pipeline will:
|
|
284
|
+
- Run all Playwright tests
|
|
285
|
+
- Publish JUnit results to the Test tab
|
|
286
|
+
- Upload screenshots and HTML report as artifacts
|
|
287
|
+
|
|
288
|
+
### Project Setup
|
|
289
|
+
|
|
290
|
+
Copy the `templates/playwright-qa/` directory to your project repo:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
cp -r node_modules/@smartbit4all/playwright-qa/templates/playwright-qa ./playwright-qa
|
|
294
|
+
cd playwright-qa
|
|
295
|
+
npm install
|
|
296
|
+
npx playwright install --with-deps chromium
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Development
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
git clone <repo-url>
|
|
303
|
+
cd platform-playwright
|
|
304
|
+
npm install
|
|
305
|
+
npx playwright install --with-deps chromium
|
|
306
|
+
npm test
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Testing locally in a project
|
|
310
|
+
|
|
311
|
+
Use `npm link` to try the package in your own project without publishing:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
# In platform-playwright:
|
|
315
|
+
npm run build
|
|
316
|
+
npm link
|
|
317
|
+
|
|
318
|
+
# In your project:
|
|
319
|
+
npm link @smartbit4all/playwright-qa
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
After linking, your project uses the local build directly. When you make changes to the package, rebuild with `npm run build` — no need to re-link.
|
|
323
|
+
|
|
324
|
+
To remove the link later:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# In your project:
|
|
328
|
+
npm unlink @smartbit4all/playwright-qa
|
|
329
|
+
npm install
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## License
|
|
333
|
+
|
|
334
|
+
LGPL-3.0-or-later
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface HighlightStyle {
|
|
2
|
+
outline: string;
|
|
3
|
+
backgroundColor: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ViewportSize {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
}
|
|
9
|
+
export interface PlatformPlaywrightConfig {
|
|
10
|
+
screenshotDir: string;
|
|
11
|
+
locale: string;
|
|
12
|
+
datapoolsDir: string;
|
|
13
|
+
highlightStylesFile: string;
|
|
14
|
+
viewport: ViewportSize;
|
|
15
|
+
}
|
|
16
|
+
export declare const defaultConfig: PlatformPlaywrightConfig;
|
|
17
|
+
export declare const defaultHighlightStyles: Record<string, HighlightStyle>;
|
|
18
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,eAAO,MAAM,aAAa,EAAE,wBAM3B,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAajE,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultHighlightStyles = exports.defaultConfig = void 0;
|
|
4
|
+
exports.defaultConfig = {
|
|
5
|
+
screenshotDir: './screenshots',
|
|
6
|
+
locale: 'en',
|
|
7
|
+
datapoolsDir: './datapools',
|
|
8
|
+
highlightStylesFile: './highlight-styles.json',
|
|
9
|
+
viewport: { width: 1920, height: 1080 },
|
|
10
|
+
};
|
|
11
|
+
exports.defaultHighlightStyles = {
|
|
12
|
+
default: {
|
|
13
|
+
outline: '3px solid red',
|
|
14
|
+
backgroundColor: 'rgba(255, 0, 0, 0.1)',
|
|
15
|
+
},
|
|
16
|
+
subtle: {
|
|
17
|
+
outline: '2px dashed gray',
|
|
18
|
+
backgroundColor: 'rgba(128, 128, 128, 0.05)',
|
|
19
|
+
},
|
|
20
|
+
success: {
|
|
21
|
+
outline: '3px solid green',
|
|
22
|
+
backgroundColor: 'rgba(0, 255, 0, 0.1)',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":";;;AAkBa,QAAA,aAAa,GAA6B;IACrD,aAAa,EAAE,eAAe;IAC9B,MAAM,EAAE,IAAI;IACZ,YAAY,EAAE,aAAa;IAC3B,mBAAmB,EAAE,yBAAyB;IAC9C,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;CACxC,CAAC;AAEW,QAAA,sBAAsB,GAAmC;IACpE,OAAO,EAAE;QACP,OAAO,EAAE,eAAe;QACxB,eAAe,EAAE,sBAAsB;KACxC;IACD,MAAM,EAAE;QACN,OAAO,EAAE,iBAAiB;QAC1B,eAAe,EAAE,2BAA2B;KAC7C;IACD,OAAO,EAAE;QACP,OAAO,EAAE,iBAAiB;QAC1B,eAAe,EAAE,sBAAsB;KACxC;CACF,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type PlatformPlaywrightConfig, type HighlightStyle, type ViewportSize } from './defaults';
|
|
2
|
+
export type { PlatformPlaywrightConfig, HighlightStyle, ViewportSize };
|
|
3
|
+
export declare function loadConfig(basePath?: string): PlatformPlaywrightConfig;
|
|
4
|
+
export declare function loadHighlightStyles(basePath?: string): Record<string, HighlightStyle>;
|
|
5
|
+
export declare function getHighlightStyle(name?: string, basePath?: string): HighlightStyle;
|
|
6
|
+
export declare function resetConfig(): void;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,wBAAwB,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC;AAKvE,wBAAgB,UAAU,CAAC,QAAQ,GAAE,MAAsB,GAAG,wBAAwB,CAarF;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAcpG;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,MAAkB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc,CAO7F;AAED,wBAAgB,WAAW,IAAI,IAAI,CAGlC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadConfig = loadConfig;
|
|
37
|
+
exports.loadHighlightStyles = loadHighlightStyles;
|
|
38
|
+
exports.getHighlightStyle = getHighlightStyle;
|
|
39
|
+
exports.resetConfig = resetConfig;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const defaults_1 = require("./defaults");
|
|
43
|
+
let resolvedConfig = null;
|
|
44
|
+
let resolvedHighlightStyles = null;
|
|
45
|
+
function loadConfig(basePath = process.cwd()) {
|
|
46
|
+
if (resolvedConfig)
|
|
47
|
+
return resolvedConfig;
|
|
48
|
+
const configPath = path.resolve(basePath, 'playwright-qa.config.json');
|
|
49
|
+
let projectConfig = {};
|
|
50
|
+
if (fs.existsSync(configPath)) {
|
|
51
|
+
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
52
|
+
projectConfig = JSON.parse(raw);
|
|
53
|
+
}
|
|
54
|
+
resolvedConfig = { ...defaults_1.defaultConfig, ...projectConfig };
|
|
55
|
+
return resolvedConfig;
|
|
56
|
+
}
|
|
57
|
+
function loadHighlightStyles(basePath = process.cwd()) {
|
|
58
|
+
if (resolvedHighlightStyles)
|
|
59
|
+
return resolvedHighlightStyles;
|
|
60
|
+
const config = loadConfig(basePath);
|
|
61
|
+
const stylesPath = path.resolve(basePath, config.highlightStylesFile);
|
|
62
|
+
let projectStyles = {};
|
|
63
|
+
if (fs.existsSync(stylesPath)) {
|
|
64
|
+
const raw = fs.readFileSync(stylesPath, 'utf-8');
|
|
65
|
+
projectStyles = JSON.parse(raw);
|
|
66
|
+
}
|
|
67
|
+
resolvedHighlightStyles = { ...defaults_1.defaultHighlightStyles, ...projectStyles };
|
|
68
|
+
return resolvedHighlightStyles;
|
|
69
|
+
}
|
|
70
|
+
function getHighlightStyle(name = 'default', basePath) {
|
|
71
|
+
const styles = loadHighlightStyles(basePath);
|
|
72
|
+
const style = styles[name];
|
|
73
|
+
if (!style) {
|
|
74
|
+
throw new Error(`Highlight style '${name}' not found. Available: ${Object.keys(styles).join(', ')}`);
|
|
75
|
+
}
|
|
76
|
+
return style;
|
|
77
|
+
}
|
|
78
|
+
function resetConfig() {
|
|
79
|
+
resolvedConfig = null;
|
|
80
|
+
resolvedHighlightStyles = null;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeA,gCAaC;AAED,kDAcC;AAED,8CAOC;AAED,kCAGC;AA1DD,uCAAyB;AACzB,2CAA6B;AAC7B,yCAMoB;AAIpB,IAAI,cAAc,GAAoC,IAAI,CAAC;AAC3D,IAAI,uBAAuB,GAA0C,IAAI,CAAC;AAE1E,SAAgB,UAAU,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IACzD,IAAI,cAAc;QAAE,OAAO,cAAc,CAAC;IAE1C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,2BAA2B,CAAC,CAAC;IACvE,IAAI,aAAa,GAAsC,EAAE,CAAC;IAE1D,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACjD,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,cAAc,GAAG,EAAE,GAAG,wBAAa,EAAE,GAAG,aAAa,EAAE,CAAC;IACxD,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,SAAgB,mBAAmB,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IAClE,IAAI,uBAAuB;QAAE,OAAO,uBAAuB,CAAC;IAE5D,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACtE,IAAI,aAAa,GAAmC,EAAE,CAAC;IAEvD,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACjD,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,uBAAuB,GAAG,EAAE,GAAG,iCAAsB,EAAE,GAAG,aAAa,EAAE,CAAC;IAC1E,OAAO,uBAAuB,CAAC;AACjC,CAAC;AAED,SAAgB,iBAAiB,CAAC,OAAe,SAAS,EAAE,QAAiB;IAC3E,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,2BAA2B,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvG,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAgB,WAAW;IACzB,cAAc,GAAG,IAAI,CAAC;IACtB,uBAAuB,GAAG,IAAI,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface SuiteConfig {
|
|
2
|
+
locale: string;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
screenshotDir?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface InitSuiteOptions {
|
|
7
|
+
screenshotDir?: string | null;
|
|
8
|
+
autoPrefix?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function initSuite(options?: InitSuiteOptions): void;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAiB1D"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.initSuite = initSuite;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const config_1 = require("../config");
|
|
39
|
+
const datapool_1 = require("../datapool");
|
|
40
|
+
const screenshot_1 = require("../screenshot");
|
|
41
|
+
const seed_1 = require("../seed");
|
|
42
|
+
function initSuite(options) {
|
|
43
|
+
(0, config_1.resetConfig)();
|
|
44
|
+
(0, datapool_1.resetDatapoolConfig)();
|
|
45
|
+
(0, screenshot_1.resetScreenshotDir)();
|
|
46
|
+
(0, seed_1.resetSeedHandlers)();
|
|
47
|
+
const screenshotDir = options?.screenshotDir;
|
|
48
|
+
if (screenshotDir) {
|
|
49
|
+
if (fs.existsSync(screenshotDir)) {
|
|
50
|
+
fs.rmSync(screenshotDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
(0, screenshot_1.initScreenshotDir)(screenshotDir);
|
|
53
|
+
}
|
|
54
|
+
if (options?.autoPrefix) {
|
|
55
|
+
(0, screenshot_1.setAutoPrefix)(true);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,8BAiBC;AAlCD,uCAAyB;AACzB,sCAAwC;AACxC,0CAAkD;AAClD,8CAAqF;AACrF,kCAA4C;AAa5C,SAAgB,SAAS,CAAC,OAA0B;IAClD,IAAA,oBAAW,GAAE,CAAC;IACd,IAAA,8BAAmB,GAAE,CAAC;IACtB,IAAA,+BAAkB,GAAE,CAAC;IACrB,IAAA,wBAAiB,GAAE,CAAC;IAEpB,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,CAAC;IAC7C,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YACjC,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,CAAC;QACD,IAAA,8BAAiB,EAAC,aAAa,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC;QACxB,IAAA,0BAAa,EAAC,IAAI,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type DatapoolMeta } from './loader';
|
|
2
|
+
export type { DatapoolMeta } from './loader';
|
|
3
|
+
export { unique, uniqueSeq, resetUniqueSeq } from './unique';
|
|
4
|
+
export interface DatapoolOptions {
|
|
5
|
+
basePath?: string;
|
|
6
|
+
locale?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function configureDatapool(options: {
|
|
9
|
+
locale?: string;
|
|
10
|
+
basePath?: string;
|
|
11
|
+
}): void;
|
|
12
|
+
export declare function resetDatapoolConfig(): void;
|
|
13
|
+
export declare class DataPool<T> {
|
|
14
|
+
private items;
|
|
15
|
+
private locale;
|
|
16
|
+
private locales;
|
|
17
|
+
private keyField;
|
|
18
|
+
readonly meta: DatapoolMeta;
|
|
19
|
+
constructor(items: T[], meta: DatapoolMeta, locale: string);
|
|
20
|
+
byKey(key: string): T;
|
|
21
|
+
derive(key: string, overrides: Partial<T>): T;
|
|
22
|
+
findFirst<K extends keyof T>(field: K, value: T[K]): T;
|
|
23
|
+
findAll<K extends keyof T>(field: K, value: T[K]): T[];
|
|
24
|
+
random(): T;
|
|
25
|
+
all(): T[];
|
|
26
|
+
count(): number;
|
|
27
|
+
}
|
|
28
|
+
export declare function datapool<T>(name: string, options?: DatapoolOptions): DataPool<T>;
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/datapool/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAI/D,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAK7D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAGvF;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;gBAG1B,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,MAAM;IAShB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC;IAWrB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAK7C,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAUtD,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;IAKtD,MAAM,IAAI,CAAC;IAQX,GAAG,IAAI,CAAC,EAAE;IAMV,KAAK,IAAI,MAAM;CAGhB;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAAC,CAAC,CAAC,CAOpF"}
|