@iblai/mcp 1.0.0 → 1.1.3
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 +95 -142
- package/dist/index.js +129 -97
- package/dist/index.js.map +1 -1
- package/dist/prompts/create-playwright-test.d.ts +2 -0
- package/dist/prompts/create-playwright-test.d.ts.map +1 -0
- package/dist/prompts/create-playwright-test.js +99 -0
- package/dist/prompts/create-playwright-test.js.map +1 -0
- package/dist/prompts/index.d.ts +4 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +4 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/setup-e2e-testing.d.ts +2 -0
- package/dist/prompts/setup-e2e-testing.d.ts.map +1 -0
- package/dist/prompts/setup-e2e-testing.js +162 -0
- package/dist/prompts/setup-e2e-testing.js.map +1 -0
- package/dist/prompts/setup-new-app.d.ts +2 -0
- package/dist/prompts/setup-new-app.d.ts.map +1 -0
- package/dist/prompts/setup-new-app.js +226 -0
- package/dist/prompts/setup-new-app.js.map +1 -0
- package/dist/resources/data-layer.js +14 -14
- package/dist/resources/guides-layout.js +5 -5
- package/dist/resources/guides-playwright.d.ts +8 -0
- package/dist/resources/guides-playwright.d.ts.map +1 -0
- package/dist/resources/guides-playwright.js +235 -0
- package/dist/resources/guides-playwright.js.map +1 -0
- package/dist/resources/guides-rbac.js +2 -2
- package/dist/resources/guides-theme.js +4 -4
- package/dist/resources/index.d.ts +3 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +5 -1
- package/dist/resources/index.js.map +1 -1
- package/dist/resources/packages-overview.d.ts.map +1 -1
- package/dist/resources/packages-overview.js +12 -6
- package/dist/resources/packages-overview.js.map +1 -1
- package/dist/resources/packages-playwright.d.ts +8 -0
- package/dist/resources/packages-playwright.d.ts.map +1 -0
- package/dist/resources/packages-playwright.js +161 -0
- package/dist/resources/packages-playwright.js.map +1 -0
- package/dist/resources/web-containers.d.ts.map +1 -1
- package/dist/resources/web-containers.js +82 -22
- package/dist/resources/web-containers.js.map +1 -1
- package/dist/resources/web-utils.d.ts.map +1 -1
- package/dist/resources/web-utils.js +46 -9
- package/dist/resources/web-utils.js.map +1 -1
- package/dist/tools/api-query-info.d.ts.map +1 -1
- package/dist/tools/api-query-info.js +248 -238
- package/dist/tools/api-query-info.js.map +1 -1
- package/dist/tools/component-info.d.ts.map +1 -1
- package/dist/tools/component-info.js +945 -469
- package/dist/tools/component-info.js.map +1 -1
- package/dist/tools/hook-info.d.ts.map +1 -1
- package/dist/tools/hook-info.js +229 -98
- package/dist/tools/hook-info.js.map +1 -1
- package/dist/tools/index.d.ts +15 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/page-template.js +8 -8
- package/dist/tools/page-template.js.map +1 -1
- package/dist/tools/playwright-helper-info.d.ts +16 -0
- package/dist/tools/playwright-helper-info.d.ts.map +1 -0
- package/dist/tools/playwright-helper-info.js +849 -0
- package/dist/tools/playwright-helper-info.js.map +1 -0
- package/dist/tools/provider-setup.js +4 -4
- package/dist/tools/provider-setup.js.map +1 -1
- package/package.json +19 -6
|
@@ -0,0 +1,849 @@
|
|
|
1
|
+
export const playwrightHelperInfoTool = {
|
|
2
|
+
name: 'get_playwright_helper_info',
|
|
3
|
+
description: 'Get detailed documentation for a specific Playwright test helper from @iblai/iblai-js/playwright',
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: 'object',
|
|
6
|
+
properties: {
|
|
7
|
+
helperName: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
description: 'Name of the Playwright helper (e.g., createPlaywrightConfig, reliableClick, safeWaitForURL, createAuthSetup)',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
required: ['helperName'],
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
const helpers = {
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// NAVIGATION
|
|
18
|
+
// ============================================================================
|
|
19
|
+
safeWaitForURL: `# safeWaitForURL
|
|
20
|
+
|
|
21
|
+
\`\`\`typescript
|
|
22
|
+
import { safeWaitForURL } from '@iblai/iblai-js/playwright';
|
|
23
|
+
|
|
24
|
+
async function safeWaitForURL(
|
|
25
|
+
page: Page,
|
|
26
|
+
urlMatcher: string | RegExp | ((url: URL) => boolean),
|
|
27
|
+
options?: SafeWaitForURLOptions
|
|
28
|
+
): Promise<void>
|
|
29
|
+
|
|
30
|
+
interface SafeWaitForURLOptions {
|
|
31
|
+
timeout?: number; // Default: 30000
|
|
32
|
+
waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit';
|
|
33
|
+
maxRetries?: number; // Default: 3
|
|
34
|
+
}
|
|
35
|
+
\`\`\`
|
|
36
|
+
|
|
37
|
+
**Use instead of \`page.waitForURL\`**. Handles Firefox \`NS_BINDING_ABORTED\` errors and Safari navigation policy issues by catching and retrying.
|
|
38
|
+
|
|
39
|
+
## Example
|
|
40
|
+
|
|
41
|
+
\`\`\`typescript
|
|
42
|
+
// Wait for navigation to a specific path
|
|
43
|
+
await safeWaitForURL(page, (url) => url.pathname.includes('/dashboard'));
|
|
44
|
+
|
|
45
|
+
// With string pattern
|
|
46
|
+
await safeWaitForURL(page, '**/dashboard');
|
|
47
|
+
|
|
48
|
+
// With options
|
|
49
|
+
await safeWaitForURL(page, /\\/settings/, { timeout: 10000, maxRetries: 5 });
|
|
50
|
+
\`\`\`
|
|
51
|
+
|
|
52
|
+
**Related:** \`waitForPageLoad\`, \`waitForPageReady\``,
|
|
53
|
+
waitForPageLoad: `# waitForPageLoad
|
|
54
|
+
|
|
55
|
+
\`\`\`typescript
|
|
56
|
+
import { waitForPageLoad } from '@iblai/iblai-js/playwright';
|
|
57
|
+
|
|
58
|
+
async function waitForPageLoad(page: Page): Promise<void>
|
|
59
|
+
\`\`\`
|
|
60
|
+
|
|
61
|
+
Waits for complete page load: \`load\` event, \`domcontentloaded\`, \`networkidle\`, and dismisses any dialogs that appear. Comprehensive page load wait.
|
|
62
|
+
|
|
63
|
+
## Example
|
|
64
|
+
|
|
65
|
+
\`\`\`typescript
|
|
66
|
+
await page.goto('https://app.example.com');
|
|
67
|
+
await waitForPageLoad(page);
|
|
68
|
+
\`\`\`
|
|
69
|
+
|
|
70
|
+
**Related:** \`waitForPageReady\`, \`safeWaitForURL\``,
|
|
71
|
+
isFirefox: `# isFirefox
|
|
72
|
+
|
|
73
|
+
\`\`\`typescript
|
|
74
|
+
import { isFirefox } from '@iblai/iblai-js/playwright';
|
|
75
|
+
|
|
76
|
+
function isFirefox(page: Page): boolean
|
|
77
|
+
\`\`\`
|
|
78
|
+
|
|
79
|
+
Check if current browser is Firefox. Useful for browser-specific test logic.
|
|
80
|
+
|
|
81
|
+
## Example
|
|
82
|
+
|
|
83
|
+
\`\`\`typescript
|
|
84
|
+
if (isFirefox(page)) {
|
|
85
|
+
// Firefox-specific handling
|
|
86
|
+
await page.waitForTimeout(500);
|
|
87
|
+
}
|
|
88
|
+
\`\`\``,
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// PAGE INTERACTION HELPERS
|
|
91
|
+
// ============================================================================
|
|
92
|
+
waitForPageReady: `# waitForPageReady
|
|
93
|
+
|
|
94
|
+
\`\`\`typescript
|
|
95
|
+
import { waitForPageReady } from '@iblai/iblai-js/playwright';
|
|
96
|
+
|
|
97
|
+
async function waitForPageReady(page: Page, timeout?: number): Promise<void>
|
|
98
|
+
\`\`\`
|
|
99
|
+
|
|
100
|
+
Waits for \`document.readyState\` to be \`'complete'\`. Use in \`beforeEach\` after navigation.
|
|
101
|
+
|
|
102
|
+
## Example
|
|
103
|
+
|
|
104
|
+
\`\`\`typescript
|
|
105
|
+
test.beforeEach(async ({ page }) => {
|
|
106
|
+
await page.goto(APP_HOST);
|
|
107
|
+
await waitForPageReady(page);
|
|
108
|
+
});
|
|
109
|
+
\`\`\`
|
|
110
|
+
|
|
111
|
+
**Related:** \`waitForPageLoad\`, \`safeWaitForURL\``,
|
|
112
|
+
reliableClick: `# reliableClick
|
|
113
|
+
|
|
114
|
+
\`\`\`typescript
|
|
115
|
+
import { reliableClick } from '@iblai/iblai-js/playwright';
|
|
116
|
+
|
|
117
|
+
async function reliableClick(
|
|
118
|
+
page: Page,
|
|
119
|
+
locator: Locator,
|
|
120
|
+
timeout?: number, // Default: 5000
|
|
121
|
+
maxRetries?: number // Default: 3
|
|
122
|
+
): Promise<void>
|
|
123
|
+
\`\`\`
|
|
124
|
+
|
|
125
|
+
Click with automatic retry on detached elements, hidden elements, and race conditions. Waits for element to be stable before clicking.
|
|
126
|
+
|
|
127
|
+
## Example
|
|
128
|
+
|
|
129
|
+
\`\`\`typescript
|
|
130
|
+
// Click a button
|
|
131
|
+
await reliableClick(page, page.getByRole('button', { name: 'Save' }));
|
|
132
|
+
|
|
133
|
+
// With custom timeout and retries
|
|
134
|
+
await reliableClick(page, page.locator('[data-testid="submit"]'), 10000, 5);
|
|
135
|
+
\`\`\`
|
|
136
|
+
|
|
137
|
+
**Related:** \`reliableFill\`, \`waitForElementStable\``,
|
|
138
|
+
reliableFill: `# reliableFill
|
|
139
|
+
|
|
140
|
+
\`\`\`typescript
|
|
141
|
+
import { reliableFill } from '@iblai/iblai-js/playwright';
|
|
142
|
+
|
|
143
|
+
async function reliableFill(
|
|
144
|
+
page: Page,
|
|
145
|
+
locator: Locator,
|
|
146
|
+
value: string,
|
|
147
|
+
timeout?: number, // Default: 5000
|
|
148
|
+
maxRetries?: number // Default: 3
|
|
149
|
+
): Promise<void>
|
|
150
|
+
\`\`\`
|
|
151
|
+
|
|
152
|
+
Fill input with automatic retry. Clears existing value, fills new value, and verifies the value was set correctly.
|
|
153
|
+
|
|
154
|
+
## Example
|
|
155
|
+
|
|
156
|
+
\`\`\`typescript
|
|
157
|
+
await reliableFill(page, page.getByLabel('Email'), 'user@example.com');
|
|
158
|
+
await reliableFill(page, page.getByPlaceholder('Search'), 'query', 10000);
|
|
159
|
+
\`\`\`
|
|
160
|
+
|
|
161
|
+
**Related:** \`reliableClick\`, \`waitForElementStable\``,
|
|
162
|
+
waitForElementStable: `# waitForElementStable
|
|
163
|
+
|
|
164
|
+
\`\`\`typescript
|
|
165
|
+
import { waitForElementStable } from '@iblai/iblai-js/playwright';
|
|
166
|
+
|
|
167
|
+
async function waitForElementStable(
|
|
168
|
+
page: Page,
|
|
169
|
+
locator: Locator,
|
|
170
|
+
timeout?: number // Default: 5000
|
|
171
|
+
): Promise<void>
|
|
172
|
+
\`\`\`
|
|
173
|
+
|
|
174
|
+
Waits for an element to be attached, visible, and not animating.
|
|
175
|
+
|
|
176
|
+
## Example
|
|
177
|
+
|
|
178
|
+
\`\`\`typescript
|
|
179
|
+
const dialog = page.getByRole('dialog');
|
|
180
|
+
await waitForElementStable(page, dialog);
|
|
181
|
+
await dialog.getByRole('button', { name: 'Confirm' }).click();
|
|
182
|
+
\`\`\`
|
|
183
|
+
|
|
184
|
+
**Related:** \`waitForDialogReady\`, \`reliableClick\``,
|
|
185
|
+
waitForDialogReady: `# waitForDialogReady
|
|
186
|
+
|
|
187
|
+
\`\`\`typescript
|
|
188
|
+
import { waitForDialogReady } from '@iblai/iblai-js/playwright';
|
|
189
|
+
|
|
190
|
+
async function waitForDialogReady(
|
|
191
|
+
page: Page,
|
|
192
|
+
dialogLocator: Locator,
|
|
193
|
+
timeout?: number // Default: 5000
|
|
194
|
+
): Promise<void>
|
|
195
|
+
\`\`\`
|
|
196
|
+
|
|
197
|
+
Wait for a dialog/modal to be visible and fully loaded (not just appearing but content rendered).
|
|
198
|
+
|
|
199
|
+
## Example
|
|
200
|
+
|
|
201
|
+
\`\`\`typescript
|
|
202
|
+
await reliableClick(page, page.getByRole('button', { name: 'Edit' }));
|
|
203
|
+
const dialog = page.getByRole('dialog');
|
|
204
|
+
await waitForDialogReady(page, dialog);
|
|
205
|
+
\`\`\`
|
|
206
|
+
|
|
207
|
+
**Related:** \`closeWithEsc\`, \`waitForElementStable\``,
|
|
208
|
+
selectDateFromCalendar: `# selectDateFromCalendar
|
|
209
|
+
|
|
210
|
+
\`\`\`typescript
|
|
211
|
+
import { selectDateFromCalendar } from '@iblai/iblai-js/playwright';
|
|
212
|
+
|
|
213
|
+
async function selectDateFromCalendar(
|
|
214
|
+
page: Page,
|
|
215
|
+
dialogLocator: Locator,
|
|
216
|
+
targetDate: Date,
|
|
217
|
+
timeout?: number // Default: 5000
|
|
218
|
+
): Promise<void>
|
|
219
|
+
\`\`\`
|
|
220
|
+
|
|
221
|
+
Select a date from a calendar date picker component.
|
|
222
|
+
|
|
223
|
+
## Example
|
|
224
|
+
|
|
225
|
+
\`\`\`typescript
|
|
226
|
+
const datePicker = page.getByRole('dialog');
|
|
227
|
+
await selectDateFromCalendar(page, datePicker, new Date('2024-03-15'));
|
|
228
|
+
\`\`\``,
|
|
229
|
+
closeWithEsc: `# closeWithEsc
|
|
230
|
+
|
|
231
|
+
\`\`\`typescript
|
|
232
|
+
import { closeWithEsc } from '@iblai/iblai-js/playwright';
|
|
233
|
+
|
|
234
|
+
async function closeWithEsc(page: Page): Promise<void>
|
|
235
|
+
\`\`\`
|
|
236
|
+
|
|
237
|
+
Press Escape key to close modals/dialogs/dropdowns.
|
|
238
|
+
|
|
239
|
+
## Example
|
|
240
|
+
|
|
241
|
+
\`\`\`typescript
|
|
242
|
+
// Open a dialog, interact, then close
|
|
243
|
+
await reliableClick(page, page.getByRole('button', { name: 'Settings' }));
|
|
244
|
+
// ... interact with dialog ...
|
|
245
|
+
await closeWithEsc(page);
|
|
246
|
+
\`\`\`
|
|
247
|
+
|
|
248
|
+
**Related:** \`waitForDialogReady\``,
|
|
249
|
+
checkAdminStatus: `# checkAdminStatus
|
|
250
|
+
|
|
251
|
+
\`\`\`typescript
|
|
252
|
+
import { checkAdminStatus } from '@iblai/iblai-js/playwright';
|
|
253
|
+
|
|
254
|
+
async function checkAdminStatus(page: Page): Promise<boolean>
|
|
255
|
+
\`\`\`
|
|
256
|
+
|
|
257
|
+
Check if the current user has admin status by reading from localStorage.
|
|
258
|
+
|
|
259
|
+
## Example
|
|
260
|
+
|
|
261
|
+
\`\`\`typescript
|
|
262
|
+
const isAdmin = await checkAdminStatus(page);
|
|
263
|
+
if (isAdmin) {
|
|
264
|
+
// Test admin-only features
|
|
265
|
+
await expect(page.getByRole('link', { name: 'Admin' })).toBeVisible();
|
|
266
|
+
}
|
|
267
|
+
\`\`\``,
|
|
268
|
+
// ============================================================================
|
|
269
|
+
// UTILITY FUNCTIONS
|
|
270
|
+
// ============================================================================
|
|
271
|
+
retry: `# retry
|
|
272
|
+
|
|
273
|
+
\`\`\`typescript
|
|
274
|
+
import { retry } from '@iblai/iblai-js/playwright';
|
|
275
|
+
|
|
276
|
+
async function retry(
|
|
277
|
+
action: () => Promise<void>,
|
|
278
|
+
errorMessage: string,
|
|
279
|
+
retryCount?: number // Default: 3
|
|
280
|
+
): Promise<void>
|
|
281
|
+
\`\`\`
|
|
282
|
+
|
|
283
|
+
Generic retry wrapper. Executes the action and retries on failure.
|
|
284
|
+
|
|
285
|
+
## Example
|
|
286
|
+
|
|
287
|
+
\`\`\`typescript
|
|
288
|
+
await retry(
|
|
289
|
+
async () => {
|
|
290
|
+
await page.getByRole('button', { name: 'Load More' }).click();
|
|
291
|
+
await expect(page.getByTestId('items')).toHaveCount(20);
|
|
292
|
+
},
|
|
293
|
+
'Failed to load more items',
|
|
294
|
+
5
|
|
295
|
+
);
|
|
296
|
+
\`\`\``,
|
|
297
|
+
isJSON: `# isJSON
|
|
298
|
+
|
|
299
|
+
\`\`\`typescript
|
|
300
|
+
import { isJSON } from '@iblai/iblai-js/playwright';
|
|
301
|
+
|
|
302
|
+
function isJSON(value: string): boolean
|
|
303
|
+
\`\`\`
|
|
304
|
+
|
|
305
|
+
Check if a string is valid JSON.
|
|
306
|
+
|
|
307
|
+
## Example
|
|
308
|
+
|
|
309
|
+
\`\`\`typescript
|
|
310
|
+
const text = await page.locator('#response').textContent();
|
|
311
|
+
if (isJSON(text)) {
|
|
312
|
+
const data = JSON.parse(text);
|
|
313
|
+
}
|
|
314
|
+
\`\`\``,
|
|
315
|
+
logger: `# logger
|
|
316
|
+
|
|
317
|
+
\`\`\`typescript
|
|
318
|
+
import { logger } from '@iblai/iblai-js/playwright';
|
|
319
|
+
\`\`\`
|
|
320
|
+
|
|
321
|
+
Winston logger instance. Shows \`info\` level output locally (colorized), silent in CI.
|
|
322
|
+
|
|
323
|
+
## Example
|
|
324
|
+
|
|
325
|
+
\`\`\`typescript
|
|
326
|
+
logger.info('Navigating to dashboard');
|
|
327
|
+
logger.warn('Retrying failed click');
|
|
328
|
+
logger.error('Element not found after retries');
|
|
329
|
+
\`\`\`
|
|
330
|
+
|
|
331
|
+
Methods: \`info()\`, \`warn()\`, \`error()\`, \`debug()\``,
|
|
332
|
+
// ============================================================================
|
|
333
|
+
// ACCESSIBILITY
|
|
334
|
+
// ============================================================================
|
|
335
|
+
expectNoAccessibilityViolations: `# expectNoAccessibilityViolations
|
|
336
|
+
|
|
337
|
+
\`\`\`typescript
|
|
338
|
+
import { expectNoAccessibilityViolations } from '@iblai/iblai-js/playwright';
|
|
339
|
+
|
|
340
|
+
async function expectNoAccessibilityViolations(page: Page): Promise<void>
|
|
341
|
+
\`\`\`
|
|
342
|
+
|
|
343
|
+
Run axe-core accessibility audit on the full page. Asserts no WCAG 2.1 AA violations.
|
|
344
|
+
|
|
345
|
+
## Example
|
|
346
|
+
|
|
347
|
+
\`\`\`typescript
|
|
348
|
+
test('should have no accessibility violations', async ({ page }) => {
|
|
349
|
+
await page.goto(APP_HOST);
|
|
350
|
+
await waitForPageReady(page);
|
|
351
|
+
await expectNoAccessibilityViolations(page);
|
|
352
|
+
});
|
|
353
|
+
\`\`\`
|
|
354
|
+
|
|
355
|
+
**Related:** \`expectNoAccessibilityViolationsOnDialogs\``,
|
|
356
|
+
expectNoAccessibilityViolationsOnDialogs: `# expectNoAccessibilityViolationsOnDialogs
|
|
357
|
+
|
|
358
|
+
\`\`\`typescript
|
|
359
|
+
import { expectNoAccessibilityViolationsOnDialogs } from '@iblai/iblai-js/playwright';
|
|
360
|
+
|
|
361
|
+
async function expectNoAccessibilityViolationsOnDialogs(
|
|
362
|
+
page: Page,
|
|
363
|
+
rules?: string[],
|
|
364
|
+
exclude?: string[]
|
|
365
|
+
): Promise<void>
|
|
366
|
+
\`\`\`
|
|
367
|
+
|
|
368
|
+
Run axe-core on dialog elements specifically. Useful when testing modals/dialogs that may have different accessibility contexts.
|
|
369
|
+
|
|
370
|
+
## Example
|
|
371
|
+
|
|
372
|
+
\`\`\`typescript
|
|
373
|
+
await reliableClick(page, page.getByRole('button', { name: 'Open Settings' }));
|
|
374
|
+
await waitForDialogReady(page, page.getByRole('dialog'));
|
|
375
|
+
await expectNoAccessibilityViolationsOnDialogs(page);
|
|
376
|
+
\`\`\`
|
|
377
|
+
|
|
378
|
+
**Related:** \`expectNoAccessibilityViolations\``,
|
|
379
|
+
// ============================================================================
|
|
380
|
+
// AUTH HELPERS
|
|
381
|
+
// ============================================================================
|
|
382
|
+
createAuthSetup: `# createAuthSetup
|
|
383
|
+
|
|
384
|
+
\`\`\`typescript
|
|
385
|
+
import { test as setup, createAuthSetup } from '@iblai/iblai-js/playwright';
|
|
386
|
+
|
|
387
|
+
function createAuthSetup(config: AuthSetupConfig): SetupFn
|
|
388
|
+
|
|
389
|
+
interface AuthSetupConfig {
|
|
390
|
+
hostUrl: string;
|
|
391
|
+
authHost: string;
|
|
392
|
+
appName: string;
|
|
393
|
+
postLoginUrlMatcher: (url: URL) => boolean;
|
|
394
|
+
authFlow?: AuthFlowType; // Default: 'username_password'
|
|
395
|
+
authIdp?: string;
|
|
396
|
+
}
|
|
397
|
+
\`\`\`
|
|
398
|
+
|
|
399
|
+
Factory function that creates a Playwright auth setup test. Authenticates once per browser and saves storage state to \`playwright/.auth/user-{browser}.json\`.
|
|
400
|
+
|
|
401
|
+
## Example
|
|
402
|
+
|
|
403
|
+
\`\`\`typescript
|
|
404
|
+
// e2e/auth.setup.ts
|
|
405
|
+
import { test as setup, createAuthSetup } from '@iblai/iblai-js/playwright';
|
|
406
|
+
|
|
407
|
+
setup(
|
|
408
|
+
'authenticate',
|
|
409
|
+
createAuthSetup({
|
|
410
|
+
hostUrl: process.env.MENTOR_NEXTJS_HOST || '',
|
|
411
|
+
authHost: process.env.AUTH_HOST || '',
|
|
412
|
+
appName: 'mentor',
|
|
413
|
+
postLoginUrlMatcher: (url) =>
|
|
414
|
+
url.href.includes('/platform/') || url.href.includes('/home'),
|
|
415
|
+
}),
|
|
416
|
+
);
|
|
417
|
+
\`\`\`
|
|
418
|
+
|
|
419
|
+
**Related:** \`AuthFlowBuilder\`, \`loginWithEmailAndPassword\``,
|
|
420
|
+
AuthFlowBuilder: `# AuthFlowBuilder
|
|
421
|
+
|
|
422
|
+
\`\`\`typescript
|
|
423
|
+
import { AuthFlowBuilder } from '@iblai/iblai-js/playwright';
|
|
424
|
+
|
|
425
|
+
class AuthFlowBuilder {
|
|
426
|
+
constructor(flow: AuthFlowType, idp: string, authHost: string)
|
|
427
|
+
|
|
428
|
+
async run(
|
|
429
|
+
page: Page,
|
|
430
|
+
step: StepFn,
|
|
431
|
+
username: string,
|
|
432
|
+
password: string,
|
|
433
|
+
hostUrl: string,
|
|
434
|
+
authUrl: string,
|
|
435
|
+
postLoginUrlMatcher?: (url: URL) => boolean
|
|
436
|
+
): Promise<void>
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
type AuthFlowType = 'username_password' | 'magic_link' | 'sso' | 'direct_sso';
|
|
440
|
+
\`\`\`
|
|
441
|
+
|
|
442
|
+
Handles different authentication flows. Used internally by \`createAuthSetup\` but can be used directly for custom auth scenarios.
|
|
443
|
+
|
|
444
|
+
## Supported Flows
|
|
445
|
+
|
|
446
|
+
- **\`username_password\`**: Email/password form login
|
|
447
|
+
- **\`magic_link\`**: Email magic link via Mailsac
|
|
448
|
+
- **\`sso\`**: SSO via identity provider (navigates to IDP)
|
|
449
|
+
- **\`direct_sso\`**: Direct SSO redirect
|
|
450
|
+
|
|
451
|
+
**Related:** \`createAuthSetup\`, \`loginWithEmailAndPassword\``,
|
|
452
|
+
loginWithEmailAndPassword: `# loginWithEmailAndPassword
|
|
453
|
+
|
|
454
|
+
\`\`\`typescript
|
|
455
|
+
import { loginWithEmailAndPassword } from '@iblai/iblai-js/playwright';
|
|
456
|
+
|
|
457
|
+
async function loginWithEmailAndPassword(
|
|
458
|
+
page: Page,
|
|
459
|
+
username: string,
|
|
460
|
+
password: string,
|
|
461
|
+
hostUrl: string,
|
|
462
|
+
postLoginUrlMatcher?: (url: URL) => boolean
|
|
463
|
+
): Promise<void>
|
|
464
|
+
\`\`\`
|
|
465
|
+
|
|
466
|
+
Login using email and password. Navigates to auth page, fills credentials, submits, and waits for redirect.
|
|
467
|
+
|
|
468
|
+
## Example
|
|
469
|
+
|
|
470
|
+
\`\`\`typescript
|
|
471
|
+
await loginWithEmailAndPassword(
|
|
472
|
+
page,
|
|
473
|
+
'test@example.com',
|
|
474
|
+
'password123',
|
|
475
|
+
'https://mentor.example.com',
|
|
476
|
+
(url) => url.pathname.includes('/home')
|
|
477
|
+
);
|
|
478
|
+
\`\`\`
|
|
479
|
+
|
|
480
|
+
**Related:** \`createAuthSetup\`, \`signUpWithEmailAndPassword\``,
|
|
481
|
+
signUpWithEmailAndPassword: `# signUpWithEmailAndPassword
|
|
482
|
+
|
|
483
|
+
\`\`\`typescript
|
|
484
|
+
import { signUpWithEmailAndPassword } from '@iblai/iblai-js/playwright';
|
|
485
|
+
|
|
486
|
+
async function signUpWithEmailAndPassword(
|
|
487
|
+
page: Page,
|
|
488
|
+
authHost: string,
|
|
489
|
+
postSignUpUrl: string,
|
|
490
|
+
credentials?: SignUpCredentials,
|
|
491
|
+
alreadyInSignupPage?: boolean
|
|
492
|
+
): Promise<void>
|
|
493
|
+
|
|
494
|
+
interface SignUpCredentials {
|
|
495
|
+
email: string;
|
|
496
|
+
password: string;
|
|
497
|
+
}
|
|
498
|
+
\`\`\`
|
|
499
|
+
|
|
500
|
+
Sign up a new user with email/password. Navigates to signup page, fills form, submits, and waits for redirect.
|
|
501
|
+
|
|
502
|
+
## Example
|
|
503
|
+
|
|
504
|
+
\`\`\`typescript
|
|
505
|
+
await signUpWithEmailAndPassword(
|
|
506
|
+
page,
|
|
507
|
+
'https://auth.example.com',
|
|
508
|
+
'https://mentor.example.com/home',
|
|
509
|
+
{ email: 'newuser@example.com', password: 'SecurePass123!' }
|
|
510
|
+
);
|
|
511
|
+
\`\`\`
|
|
512
|
+
|
|
513
|
+
**Related:** \`loginWithEmailAndPassword\``,
|
|
514
|
+
loginWithMicrosoftIdp: `# loginWithMicrosoftIdp
|
|
515
|
+
|
|
516
|
+
\`\`\`typescript
|
|
517
|
+
import { loginWithMicrosoftIdp } from '@iblai/iblai-js/playwright';
|
|
518
|
+
|
|
519
|
+
async function loginWithMicrosoftIdp(
|
|
520
|
+
page: Page,
|
|
521
|
+
username: string,
|
|
522
|
+
password: string
|
|
523
|
+
): Promise<void>
|
|
524
|
+
\`\`\`
|
|
525
|
+
|
|
526
|
+
Login through Microsoft identity provider (Azure AD / Entra ID).
|
|
527
|
+
|
|
528
|
+
**Related:** \`AuthFlowBuilder\`, \`createAuthSetup\``,
|
|
529
|
+
canChatWithEmbedMentor: `# canChatWithEmbedMentor
|
|
530
|
+
|
|
531
|
+
\`\`\`typescript
|
|
532
|
+
import { canChatWithEmbedMentor } from '@iblai/iblai-js/playwright';
|
|
533
|
+
|
|
534
|
+
async function canChatWithEmbedMentor(
|
|
535
|
+
page: Page,
|
|
536
|
+
openChatButton: Locator
|
|
537
|
+
): Promise<void>
|
|
538
|
+
\`\`\`
|
|
539
|
+
|
|
540
|
+
Test helper to verify chat functionality with an embedded mentor widget.
|
|
541
|
+
|
|
542
|
+
**Related:** \`getMentorIdFromUrl\``,
|
|
543
|
+
getMentorIdFromUrl: `# getMentorIdFromUrl
|
|
544
|
+
|
|
545
|
+
\`\`\`typescript
|
|
546
|
+
import { getMentorIdFromUrl } from '@iblai/iblai-js/playwright';
|
|
547
|
+
|
|
548
|
+
function getMentorIdFromUrl(url: string): string
|
|
549
|
+
\`\`\`
|
|
550
|
+
|
|
551
|
+
Extract mentor ID from a URL path.`,
|
|
552
|
+
// ============================================================================
|
|
553
|
+
// CONFIG GENERATION
|
|
554
|
+
// ============================================================================
|
|
555
|
+
createPlaywrightConfig: `# createPlaywrightConfig
|
|
556
|
+
|
|
557
|
+
\`\`\`typescript
|
|
558
|
+
import { createPlaywrightConfig } from '@iblai/iblai-js/playwright';
|
|
559
|
+
|
|
560
|
+
function createPlaywrightConfig(
|
|
561
|
+
options: CreatePlaywrightConfigOptions
|
|
562
|
+
): PlaywrightTestConfig
|
|
563
|
+
|
|
564
|
+
interface CreatePlaywrightConfigOptions {
|
|
565
|
+
testDir?: string; // Default: '.'
|
|
566
|
+
devices?: string[]; // Default: ['Desktop Chrome', 'Desktop Firefox', 'Desktop Safari', 'Desktop Edge']
|
|
567
|
+
platforms: PlatformConfig[];
|
|
568
|
+
customReporterPath?: string; // Default: './custom-reporter.ts'
|
|
569
|
+
extraProjects?: Project[];
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
interface PlatformConfig {
|
|
573
|
+
name: string;
|
|
574
|
+
devices?: string[];
|
|
575
|
+
dependencies?: string[];
|
|
576
|
+
otherTestMatch?: string[];
|
|
577
|
+
testIgnore?: string[];
|
|
578
|
+
}
|
|
579
|
+
\`\`\`
|
|
580
|
+
|
|
581
|
+
Generates a complete Playwright config with per-browser auth setup projects. Produces:
|
|
582
|
+
- Auth setup projects per browser (setup-chrome, setup-firefox, etc.)
|
|
583
|
+
- Test projects per platform/browser combination
|
|
584
|
+
- CI mode: retries=3, workers=1, headless, trace=retain-on-failure
|
|
585
|
+
- Local mode: retries=0, headed (via HEADED env var), trace=on-first-retry
|
|
586
|
+
|
|
587
|
+
## Example
|
|
588
|
+
|
|
589
|
+
\`\`\`typescript
|
|
590
|
+
// e2e/playwright.config.ts
|
|
591
|
+
import { createPlaywrightConfig } from '@iblai/iblai-js/playwright';
|
|
592
|
+
import dotenv from 'dotenv';
|
|
593
|
+
import path from 'path';
|
|
594
|
+
|
|
595
|
+
dotenv.config({ path: path.resolve(__dirname, '.env.development') });
|
|
596
|
+
|
|
597
|
+
export default createPlaywrightConfig({
|
|
598
|
+
platforms: [
|
|
599
|
+
{
|
|
600
|
+
name: 'mentornextjs',
|
|
601
|
+
dependencies: ['setup'],
|
|
602
|
+
otherTestMatch: ['**mentornextjs/*/*.spec.ts'],
|
|
603
|
+
},
|
|
604
|
+
],
|
|
605
|
+
});
|
|
606
|
+
\`\`\`
|
|
607
|
+
|
|
608
|
+
**Related:** \`generateProjectConfig\`, \`generateBrowserSetupProjects\``,
|
|
609
|
+
generateProjectConfig: `# generateProjectConfig
|
|
610
|
+
|
|
611
|
+
\`\`\`typescript
|
|
612
|
+
import { generateProjectConfig } from '@iblai/iblai-js/playwright';
|
|
613
|
+
\`\`\`
|
|
614
|
+
|
|
615
|
+
Generate per-browser project configuration objects. Used internally by \`createPlaywrightConfig\`.
|
|
616
|
+
|
|
617
|
+
**Related:** \`createPlaywrightConfig\``,
|
|
618
|
+
generateBrowserSetupProjects: `# generateBrowserSetupProjects
|
|
619
|
+
|
|
620
|
+
\`\`\`typescript
|
|
621
|
+
import { generateBrowserSetupProjects } from '@iblai/iblai-js/playwright';
|
|
622
|
+
\`\`\`
|
|
623
|
+
|
|
624
|
+
Generate auth setup projects for each browser. Used internally by \`createPlaywrightConfig\`.
|
|
625
|
+
|
|
626
|
+
**Related:** \`createPlaywrightConfig\``,
|
|
627
|
+
getBrowserKey: `# getBrowserKey
|
|
628
|
+
|
|
629
|
+
\`\`\`typescript
|
|
630
|
+
import { getBrowserKey } from '@iblai/iblai-js/playwright';
|
|
631
|
+
|
|
632
|
+
function getBrowserKey(deviceName: string): string
|
|
633
|
+
\`\`\`
|
|
634
|
+
|
|
635
|
+
Convert a Playwright device name to a browser key. Example: \`'Desktop Chrome'\` → \`'chrome'\`.
|
|
636
|
+
|
|
637
|
+
**Related:** \`createPlaywrightConfig\``,
|
|
638
|
+
// ============================================================================
|
|
639
|
+
// ENVIRONMENT CONFIG
|
|
640
|
+
// ============================================================================
|
|
641
|
+
createEnvConfig: `# createEnvConfig
|
|
642
|
+
|
|
643
|
+
\`\`\`typescript
|
|
644
|
+
import { createEnvConfig } from '@iblai/iblai-js/playwright';
|
|
645
|
+
|
|
646
|
+
function createEnvConfig(overrides?: Partial<EnvConfig>): EnvConfig
|
|
647
|
+
|
|
648
|
+
interface EnvConfig {
|
|
649
|
+
skillHost: string;
|
|
650
|
+
authHost: string;
|
|
651
|
+
analyticsHost: string;
|
|
652
|
+
mentorHost: string;
|
|
653
|
+
mentorNextjsHost: string;
|
|
654
|
+
authNextjsHost: string;
|
|
655
|
+
playwrightUsername: string;
|
|
656
|
+
playwrightPassword: string;
|
|
657
|
+
inviteUsername: string;
|
|
658
|
+
inviteUserPassword: string;
|
|
659
|
+
authFlow: AuthFlowType;
|
|
660
|
+
authIdp: string;
|
|
661
|
+
enableStripeTest: boolean;
|
|
662
|
+
iblMentorDisabledTabs: string;
|
|
663
|
+
embedUrl: string;
|
|
664
|
+
wcagRange: string;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
type AuthFlowType = 'username_password' | 'magic_link' | 'sso' | 'direct_sso';
|
|
668
|
+
\`\`\`
|
|
669
|
+
|
|
670
|
+
Typed environment variable reader. Reads from \`process.env\` and provides typed defaults.
|
|
671
|
+
|
|
672
|
+
## Example
|
|
673
|
+
|
|
674
|
+
\`\`\`typescript
|
|
675
|
+
const env = createEnvConfig();
|
|
676
|
+
await page.goto(env.mentorNextjsHost);
|
|
677
|
+
\`\`\`
|
|
678
|
+
|
|
679
|
+
**Related:** \`createAuthSetup\``,
|
|
680
|
+
// ============================================================================
|
|
681
|
+
// MAIL CLIENT
|
|
682
|
+
// ============================================================================
|
|
683
|
+
MailsacClient: `# MailsacClient
|
|
684
|
+
|
|
685
|
+
\`\`\`typescript
|
|
686
|
+
import { MailsacClient } from '@iblai/iblai-js/playwright';
|
|
687
|
+
|
|
688
|
+
class MailsacClient {
|
|
689
|
+
constructor(apiKey: string)
|
|
690
|
+
|
|
691
|
+
async getEmails(inbox: string): Promise<Email[]>
|
|
692
|
+
async getEmailById(email: string, messageId: string): Promise<EmailDetail>
|
|
693
|
+
async deleteEmail(emailId: string): Promise<void>
|
|
694
|
+
}
|
|
695
|
+
\`\`\`
|
|
696
|
+
|
|
697
|
+
Email testing client for Mailsac. Used with magic link auth flow testing.
|
|
698
|
+
|
|
699
|
+
## Example
|
|
700
|
+
|
|
701
|
+
\`\`\`typescript
|
|
702
|
+
const mail = new MailsacClient(process.env.MAILSAC_API_KEY);
|
|
703
|
+
const emails = await mail.getEmails('test@mailsac.com');
|
|
704
|
+
\`\`\`
|
|
705
|
+
|
|
706
|
+
**Related:** \`AuthFlowBuilder\` (magic_link flow)`,
|
|
707
|
+
// ============================================================================
|
|
708
|
+
// CUSTOM REPORTER
|
|
709
|
+
// ============================================================================
|
|
710
|
+
CustomReporter: `# CustomReporter
|
|
711
|
+
|
|
712
|
+
\`\`\`typescript
|
|
713
|
+
import { CustomReporter } from '@iblai/iblai-js/playwright';
|
|
714
|
+
// or re-export:
|
|
715
|
+
export { CustomReporter as default } from '@iblai/iblai-js/playwright';
|
|
716
|
+
\`\`\`
|
|
717
|
+
|
|
718
|
+
Playwright custom reporter with \`onBegin\`, \`onTestBegin\`, \`onTestEnd\`, \`onEnd\` hooks. Provides formatted console output for test results.
|
|
719
|
+
|
|
720
|
+
## Usage
|
|
721
|
+
|
|
722
|
+
Create \`e2e/custom-reporter.ts\`:
|
|
723
|
+
\`\`\`typescript
|
|
724
|
+
export { CustomReporter as default } from '@iblai/iblai-js/playwright';
|
|
725
|
+
\`\`\`
|
|
726
|
+
|
|
727
|
+
This is automatically referenced by \`createPlaywrightConfig\`.
|
|
728
|
+
|
|
729
|
+
**Related:** \`createPlaywrightConfig\``,
|
|
730
|
+
// ============================================================================
|
|
731
|
+
// REPORT DOWNLOAD
|
|
732
|
+
// ============================================================================
|
|
733
|
+
buildReportUrl: `# buildReportUrl
|
|
734
|
+
|
|
735
|
+
\`\`\`typescript
|
|
736
|
+
import { buildReportUrl } from '@iblai/iblai-js/playwright';
|
|
737
|
+
|
|
738
|
+
function buildReportUrl(baseUrl: string, platformKey: string, reportName: string): string
|
|
739
|
+
\`\`\`
|
|
740
|
+
|
|
741
|
+
Build a report download URL from base URL, platform key, and report name.
|
|
742
|
+
|
|
743
|
+
**Related:** \`navigateToReportDownload\`, \`waitForReportDownload\``,
|
|
744
|
+
navigateToReportDownload: `# navigateToReportDownload
|
|
745
|
+
|
|
746
|
+
\`\`\`typescript
|
|
747
|
+
import { navigateToReportDownload } from '@iblai/iblai-js/playwright';
|
|
748
|
+
|
|
749
|
+
async function navigateToReportDownload(
|
|
750
|
+
page: Page,
|
|
751
|
+
options: ReportDownloadOptions
|
|
752
|
+
): Promise<void>
|
|
753
|
+
|
|
754
|
+
interface ReportDownloadOptions {
|
|
755
|
+
baseUrl: string;
|
|
756
|
+
platformKey: string;
|
|
757
|
+
reportName: string;
|
|
758
|
+
timeout?: number;
|
|
759
|
+
}
|
|
760
|
+
\`\`\`
|
|
761
|
+
|
|
762
|
+
Navigate to a report download page and wait for it to be ready.
|
|
763
|
+
|
|
764
|
+
**Related:** \`buildReportUrl\`, \`verifyPreparingPhase\`, \`waitForReportDownload\``,
|
|
765
|
+
waitForReportDownload: `# waitForReportDownload
|
|
766
|
+
|
|
767
|
+
\`\`\`typescript
|
|
768
|
+
import { waitForReportDownload } from '@iblai/iblai-js/playwright';
|
|
769
|
+
|
|
770
|
+
async function waitForReportDownload(
|
|
771
|
+
page: Page,
|
|
772
|
+
options: ReportDownloadOptions
|
|
773
|
+
): Promise<void>
|
|
774
|
+
\`\`\`
|
|
775
|
+
|
|
776
|
+
Full report download flow: navigates, waits through preparing → downloading → done phases.
|
|
777
|
+
|
|
778
|
+
**Related:** \`navigateToReportDownload\`, \`verifyPreparingPhase\`, \`verifyDownloadingPhase\`, \`verifyDonePhase\``,
|
|
779
|
+
// ============================================================================
|
|
780
|
+
// SHARED TEST HELPERS
|
|
781
|
+
// ============================================================================
|
|
782
|
+
inviteUserTest: `# inviteUserTest
|
|
783
|
+
|
|
784
|
+
\`\`\`typescript
|
|
785
|
+
import { inviteUserTest } from '@iblai/iblai-js/playwright';
|
|
786
|
+
|
|
787
|
+
async function inviteUserTest(page: Page, inviteModal: Locator): Promise<void>
|
|
788
|
+
\`\`\`
|
|
789
|
+
|
|
790
|
+
Shared test helper for invite user flow. Opens invite modal, fills email, submits.
|
|
791
|
+
|
|
792
|
+
**Related:** \`navigateToAccountComponent\``,
|
|
793
|
+
navigateToDataReports: `# navigateToDataReports
|
|
794
|
+
|
|
795
|
+
\`\`\`typescript
|
|
796
|
+
import { navigateToDataReports } from '@iblai/iblai-js/playwright';
|
|
797
|
+
|
|
798
|
+
async function navigateToDataReports(page: Page): Promise<void>
|
|
799
|
+
\`\`\`
|
|
800
|
+
|
|
801
|
+
Navigate to the Data Reports section in analytics.
|
|
802
|
+
|
|
803
|
+
**Related:** \`shouldDisplayReportCards\``,
|
|
804
|
+
shouldDisplayReportCards: `# shouldDisplayReportCards
|
|
805
|
+
|
|
806
|
+
\`\`\`typescript
|
|
807
|
+
import { shouldDisplayReportCards } from '@iblai/iblai-js/playwright';
|
|
808
|
+
|
|
809
|
+
async function shouldDisplayReportCards(
|
|
810
|
+
page: Page,
|
|
811
|
+
reportCards: Array<{ name: string; testId: string }>
|
|
812
|
+
): Promise<void>
|
|
813
|
+
\`\`\`
|
|
814
|
+
|
|
815
|
+
Verify that report cards are displayed with correct names and test IDs.
|
|
816
|
+
|
|
817
|
+
**Related:** \`navigateToDataReports\``,
|
|
818
|
+
};
|
|
819
|
+
// Aliases — common alternate names
|
|
820
|
+
helpers['safe_wait_for_url'] = helpers['safeWaitForURL'];
|
|
821
|
+
helpers['wait_for_page_ready'] = helpers['waitForPageReady'];
|
|
822
|
+
helpers['reliable_click'] = helpers['reliableClick'];
|
|
823
|
+
helpers['reliable_fill'] = helpers['reliableFill'];
|
|
824
|
+
helpers['wait_for_dialog_ready'] = helpers['waitForDialogReady'];
|
|
825
|
+
helpers['close_with_esc'] = helpers['closeWithEsc'];
|
|
826
|
+
helpers['create_auth_setup'] = helpers['createAuthSetup'];
|
|
827
|
+
helpers['create_playwright_config'] = helpers['createPlaywrightConfig'];
|
|
828
|
+
helpers['create_env_config'] = helpers['createEnvConfig'];
|
|
829
|
+
helpers['expect_no_accessibility_violations'] = helpers['expectNoAccessibilityViolations'];
|
|
830
|
+
helpers['login_with_email_and_password'] = helpers['loginWithEmailAndPassword'];
|
|
831
|
+
helpers['wait_for_page_load'] = helpers['waitForPageLoad'];
|
|
832
|
+
helpers['build_report_url'] = helpers['buildReportUrl'];
|
|
833
|
+
helpers['wait_for_report_download'] = helpers['waitForReportDownload'];
|
|
834
|
+
export function getPlaywrightHelperInfo(helperName) {
|
|
835
|
+
const info = helpers[helperName];
|
|
836
|
+
if (info)
|
|
837
|
+
return info;
|
|
838
|
+
// Fuzzy match
|
|
839
|
+
const lower = helperName.toLowerCase();
|
|
840
|
+
const match = Object.keys(helpers).find((k) => k.toLowerCase() === lower || k.toLowerCase().replace(/_/g, '') === lower.replace(/_/g, ''));
|
|
841
|
+
if (match)
|
|
842
|
+
return helpers[match];
|
|
843
|
+
const available = Object.keys(helpers)
|
|
844
|
+
.filter((k) => !k.includes('_'))
|
|
845
|
+
.sort()
|
|
846
|
+
.join(', ');
|
|
847
|
+
return `Helper "${helperName}" not found.\n\nAvailable helpers:\n${available}\n\nUse get_playwright_helper_info with any of the above names.`;
|
|
848
|
+
}
|
|
849
|
+
//# sourceMappingURL=playwright-helper-info.js.map
|