qa360 2.0.11 → 2.0.13

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.
Files changed (42) hide show
  1. package/dist/commands/ai.js +26 -14
  2. package/dist/commands/ask.d.ts +75 -23
  3. package/dist/commands/ask.js +413 -265
  4. package/dist/commands/crawl.d.ts +24 -0
  5. package/dist/commands/crawl.js +121 -0
  6. package/dist/commands/history.js +38 -3
  7. package/dist/commands/init.d.ts +89 -95
  8. package/dist/commands/init.js +282 -200
  9. package/dist/commands/run.d.ts +1 -0
  10. package/dist/core/adapters/playwright-ui.d.ts +45 -7
  11. package/dist/core/adapters/playwright-ui.js +365 -59
  12. package/dist/core/assertions/engine.d.ts +51 -0
  13. package/dist/core/assertions/engine.js +530 -0
  14. package/dist/core/assertions/index.d.ts +11 -0
  15. package/dist/core/assertions/index.js +11 -0
  16. package/dist/core/assertions/types.d.ts +121 -0
  17. package/dist/core/assertions/types.js +37 -0
  18. package/dist/core/crawler/index.d.ts +57 -0
  19. package/dist/core/crawler/index.js +281 -0
  20. package/dist/core/crawler/journey-generator.d.ts +49 -0
  21. package/dist/core/crawler/journey-generator.js +412 -0
  22. package/dist/core/crawler/page-analyzer.d.ts +88 -0
  23. package/dist/core/crawler/page-analyzer.js +709 -0
  24. package/dist/core/crawler/selector-generator.d.ts +34 -0
  25. package/dist/core/crawler/selector-generator.js +240 -0
  26. package/dist/core/crawler/types.d.ts +353 -0
  27. package/dist/core/crawler/types.js +6 -0
  28. package/dist/core/generation/crawler-pack-generator.d.ts +44 -0
  29. package/dist/core/generation/crawler-pack-generator.js +231 -0
  30. package/dist/core/generation/index.d.ts +2 -0
  31. package/dist/core/generation/index.js +2 -0
  32. package/dist/core/index.d.ts +3 -0
  33. package/dist/core/index.js +4 -0
  34. package/dist/core/types/pack-v1.d.ts +90 -0
  35. package/dist/index.js +6 -2
  36. package/examples/accessibility.yml +39 -16
  37. package/examples/api-basic.yml +19 -14
  38. package/examples/complete.yml +134 -42
  39. package/examples/fullstack.yml +66 -31
  40. package/examples/security.yml +47 -15
  41. package/examples/ui-basic.yml +16 -12
  42. package/package.json +3 -2
@@ -0,0 +1,34 @@
1
+ /**
2
+ * QA360 Selector Generator
3
+ *
4
+ * Generates stable, resilient CSS selectors for web elements
5
+ */
6
+ import type { ElementInfo } from './types.js';
7
+ /**
8
+ * Generate optimal selector for an element
9
+ */
10
+ export declare function generateSelector(element: {
11
+ tagName?: string;
12
+ id?: string;
13
+ className?: string;
14
+ attributes?: Record<string, string>;
15
+ textContent?: string;
16
+ role?: string;
17
+ name?: string;
18
+ }): string;
19
+ /**
20
+ * Generate selector from Playwright element handle
21
+ */
22
+ export declare function generateSelectorFromElement(element: any, page: any): Promise<ElementInfo>;
23
+ /**
24
+ * Optimize selector for resiliency
25
+ */
26
+ export declare function optimizeSelector(selector: string): string;
27
+ /**
28
+ * Generate fallback selectors for resilience
29
+ */
30
+ export declare function generateFallbackSelectors(primarySelector: string): string[];
31
+ /**
32
+ * Score selector quality (0-100)
33
+ */
34
+ export declare function scoreSelector(selector: string): number;
@@ -0,0 +1,240 @@
1
+ /**
2
+ * QA360 Selector Generator
3
+ *
4
+ * Generates stable, resilient CSS selectors for web elements
5
+ */
6
+ /**
7
+ * Selector priority (most stable first)
8
+ */
9
+ const SELECTOR_PRIORITY = [
10
+ 'data-testid', // Best: explicit test attribute
11
+ 'data-cy', // Cypress convention
12
+ 'data-test', // Common convention
13
+ 'data-test-id', // Common convention
14
+ 'id', // Good if stable
15
+ 'aria-label', // Accessible, usually stable
16
+ 'name', // Form field names
17
+ 'role + aria-label', // ARIA combo
18
+ 'class', // Less stable, use as fallback
19
+ 'tag + text', // Content-based
20
+ 'nth-child', // Last resort
21
+ ];
22
+ /**
23
+ * Generate optimal selector for an element
24
+ */
25
+ export function generateSelector(element) {
26
+ const { tagName, id, className, attributes = {}, textContent, role, name } = element;
27
+ // 1. Best: data-testid or similar test attributes
28
+ for (const attr of ['data-testid', 'data-cy', 'data-test', 'data-test-id']) {
29
+ if (attributes[attr]) {
30
+ return `[${attr}="${attributes[attr]}"]`;
31
+ }
32
+ }
33
+ // 2. ID (if not auto-generated)
34
+ if (id && !isGeneratedId(id)) {
35
+ return `#${escapeCss(id)}`;
36
+ }
37
+ // 3. aria-label (accessible and stable)
38
+ if (attributes['aria-label']) {
39
+ return `[aria-label="${escapeCss(attributes['aria-label'])}"]`;
40
+ }
41
+ // 4. Form field name
42
+ if (name) {
43
+ return `[name="${escapeCss(name)}"]`;
44
+ }
45
+ // 5. Role + label combination
46
+ if (role && attributes['aria-label']) {
47
+ return `[role="${role}"][aria-label="${escapeCss(attributes['aria-label'])}"]`;
48
+ }
49
+ // 6. Class (avoid if too generic)
50
+ if (className && !isGenericClass(className)) {
51
+ const classes = className.split(' ').filter(c => !isGenericClass(c));
52
+ if (classes.length > 0) {
53
+ const classSelector = classes.map(c => `.${escapeCss(c)}`).join('');
54
+ // Qualify with tag if available
55
+ return tagName ? `${tagName}${classSelector}` : classSelector;
56
+ }
57
+ }
58
+ // 7. Tag + text content (for buttons, links)
59
+ if (tagName && textContent && textContent.trim()) {
60
+ const text = textContent.trim().slice(0, 50);
61
+ return `${tagName}:has-text("${escapeCss(text)}")`;
62
+ }
63
+ // 8. Tag only (last resort)
64
+ return tagName || '*';
65
+ }
66
+ /**
67
+ * Generate selector from Playwright element handle
68
+ */
69
+ export async function generateSelectorFromElement(element, page) {
70
+ try {
71
+ // Get all attributes
72
+ const attributes = await element.evaluate((el) => {
73
+ const attrs = {};
74
+ for (const attr of el.attributes || []) {
75
+ attrs[attr.name] = attr.value;
76
+ }
77
+ return attrs;
78
+ });
79
+ // Get basic info
80
+ const tagName = await element.evaluate((el) => el.tagName?.toLowerCase());
81
+ const textContent = await element.evaluate((el) => el.textContent?.trim());
82
+ const className = attributes.class || attributes.className;
83
+ const id = attributes.id;
84
+ const role = attributes.role || attributes['role'];
85
+ const name = attributes.name;
86
+ // Generate selector
87
+ const selector = generateSelector({
88
+ tagName,
89
+ id,
90
+ className,
91
+ attributes,
92
+ textContent,
93
+ role,
94
+ name,
95
+ });
96
+ // Determine stability
97
+ const stable = isSelectorStable(selector);
98
+ return {
99
+ selector,
100
+ text: textContent || undefined,
101
+ ariaLabel: attributes['aria-label'],
102
+ testId: attributes['data-testid'] || attributes['data-cy'] || attributes['data-test'],
103
+ role: role || undefined,
104
+ type: tagName || 'unknown',
105
+ stable,
106
+ };
107
+ }
108
+ catch (error) {
109
+ // Fallback
110
+ return {
111
+ selector: 'unknown',
112
+ type: 'unknown',
113
+ stable: false,
114
+ };
115
+ }
116
+ }
117
+ /**
118
+ * Check if ID is auto-generated (not stable)
119
+ */
120
+ function isGeneratedId(id) {
121
+ // Patterns indicating auto-generated IDs
122
+ const generatedPatterns = [
123
+ /^\w+_\d+$/, // react_123, vue_456
124
+ /^(ember|ember)\d+$/, // ember1234
125
+ /^yui_[^_]+_\d+$/, // yui_gen_123
126
+ /^\w+-\w+-\w+$/, // random-hash patterns
127
+ /^[a-f0-9]{8,}$/, // hex hashes
128
+ ];
129
+ return generatedPatterns.some(pattern => pattern.test(id));
130
+ }
131
+ /**
132
+ * Check if class is too generic
133
+ */
134
+ function isGenericClass(className) {
135
+ const genericClasses = [
136
+ 'active', 'inactive', 'selected', 'disabled', 'enabled',
137
+ 'hidden', 'visible', 'show', 'hide', 'open', 'closed',
138
+ 'first', 'last', 'odd', 'even',
139
+ 'container', 'wrapper', 'content', 'section',
140
+ 'btn', 'button', 'input', 'form', 'field',
141
+ 'row', 'col', 'column', 'grid',
142
+ ];
143
+ const classes = className.split(' ');
144
+ return classes.every(c => genericClasses.includes(c));
145
+ }
146
+ /**
147
+ * Check if selector is considered stable
148
+ */
149
+ function isSelectorStable(selector) {
150
+ // Stable selectors: data-testid, aria-label, stable IDs
151
+ const stablePatterns = [
152
+ /\[data-(testid|test|test-id|cy)/,
153
+ /\[aria-label=/,
154
+ /\[name=/,
155
+ /#\w[\w-]*\w/, // ID with word chars
156
+ ];
157
+ // Unstable selectors: nth-child, generated classes
158
+ const unstablePatterns = [
159
+ /:nth-child/,
160
+ /:\w+-\w+-\w+/, // hash-like classes
161
+ ];
162
+ const hasStable = stablePatterns.some(p => p.test(selector));
163
+ const hasUnstable = unstablePatterns.some(p => p.test(selector));
164
+ return hasStable || !hasUnstable;
165
+ }
166
+ /**
167
+ * Escape special CSS characters
168
+ */
169
+ function escapeCss(str) {
170
+ return str.replace(/(["\\])/g, '\\$1').replace(/"/g, '\\"');
171
+ }
172
+ /**
173
+ * Optimize selector for resiliency
174
+ */
175
+ export function optimizeSelector(selector) {
176
+ // Remove unnecessary descendants
177
+ let optimized = selector.replace(/\s*>\s*/g, ' > ');
178
+ // Use :has() for more specific targeting
179
+ if (optimized.includes(' ')) {
180
+ const parts = optimized.split(' ');
181
+ if (parts.length > 3) {
182
+ // Keep only the last 3 parts for specificity
183
+ optimized = parts.slice(-3).join(' ');
184
+ }
185
+ }
186
+ return optimized;
187
+ }
188
+ /**
189
+ * Generate fallback selectors for resilience
190
+ */
191
+ export function generateFallbackSelectors(primarySelector) {
192
+ const fallbacks = [];
193
+ // If primary is data-testid, add aria-label fallback
194
+ if (primarySelector.includes('[data-testid')) {
195
+ const testId = primarySelector.match(/\[data-testid="([^"]+)"\]/)?.[1];
196
+ if (testId) {
197
+ // Try aria-label with similar text
198
+ fallbacks.push(`[aria-label="${testId}"]`);
199
+ }
200
+ }
201
+ // If primary is ID, add name fallback
202
+ if (primarySelector.startsWith('#')) {
203
+ const id = primarySelector.slice(1);
204
+ fallbacks.push(`[name="${id}"]`);
205
+ }
206
+ // Add generic fallback based on tag
207
+ const tagMatch = primarySelector.match(/^(\w+)/);
208
+ if (tagMatch) {
209
+ fallbacks.push(tagMatch[1]);
210
+ }
211
+ return fallbacks;
212
+ }
213
+ /**
214
+ * Score selector quality (0-100)
215
+ */
216
+ export function scoreSelector(selector) {
217
+ let score = 50; // Base score
218
+ // Bonus for test attributes
219
+ if (selector.includes('[data-testid'))
220
+ score += 40;
221
+ else if (selector.includes('[data-test'))
222
+ score += 35;
223
+ else if (selector.includes('[data-cy'))
224
+ score += 30;
225
+ else if (selector.includes('[aria-label'))
226
+ score += 25;
227
+ else if (selector.startsWith('#'))
228
+ score += 20;
229
+ else if (selector.includes('[name='))
230
+ score += 15;
231
+ // Penalty for unstable patterns
232
+ if (selector.includes(':nth-child'))
233
+ score -= 30;
234
+ if (selector.includes(':has-text'))
235
+ score -= 10;
236
+ // Bonus for specificity balance
237
+ if (!selector.includes(' '))
238
+ score += 5; // Simple selector
239
+ return Math.max(0, Math.min(100, score));
240
+ }
@@ -0,0 +1,353 @@
1
+ /**
2
+ * QA360 Web Crawler - Type Definitions
3
+ *
4
+ * Automatically discovers and analyzes web applications for E2E test generation
5
+ */
6
+ /**
7
+ * Crawler configuration options
8
+ */
9
+ export interface CrawlOptions {
10
+ /** Base URL to start crawling */
11
+ baseUrl: string;
12
+ /** Maximum depth to follow links (default: 3) */
13
+ maxDepth?: number;
14
+ /** Maximum number of pages to crawl (default: 50) */
15
+ maxPages?: number;
16
+ /** Follow internal links (default: true) */
17
+ followLinks?: boolean;
18
+ /** Discover and analyze forms (default: true) */
19
+ discoverForms?: boolean;
20
+ /** Discover buttons and actions (default: true) */
21
+ discoverButtons?: boolean;
22
+ /** Regex patterns to exclude (e.g., ['/admin', '/logout', '/api']) */
23
+ excludePatterns?: string[];
24
+ /** Authentication for protected areas */
25
+ auth?: CrawlAuth;
26
+ /** Timeout per page in milliseconds (default: 30000) */
27
+ timeout?: number;
28
+ /** Whether to take screenshots (default: false) */
29
+ screenshots?: boolean;
30
+ /** Headless mode (default: true) */
31
+ headless?: boolean;
32
+ /** Wait for network idle before analysis (default: true) */
33
+ waitForNetworkIdle?: boolean;
34
+ }
35
+ /**
36
+ * Authentication for crawling
37
+ */
38
+ export interface CrawlAuth {
39
+ /** Type of authentication */
40
+ type: 'basic' | 'form' | 'bearer' | 'cookie';
41
+ /** URL for login form (for type: 'form') */
42
+ loginUrl?: string;
43
+ /** Username */
44
+ username?: string;
45
+ /** Password */
46
+ password?: string;
47
+ /** Username selector (for type: 'form') */
48
+ usernameSelector?: string;
49
+ /** Password selector (for type: 'form') */
50
+ passwordSelector?: string;
51
+ /** Submit button selector (for type: 'form') */
52
+ submitSelector?: string;
53
+ /** Bearer token (for type: 'bearer') */
54
+ token?: string;
55
+ /** Cookies (for type: 'cookie') */
56
+ cookies?: Array<{
57
+ name: string;
58
+ value: string;
59
+ domain?: string;
60
+ }>;
61
+ }
62
+ /**
63
+ * Element information discovered on a page
64
+ */
65
+ export interface ElementInfo {
66
+ /** CSS selector (optimized for stability) */
67
+ selector: string;
68
+ /** Text content */
69
+ text?: string;
70
+ /** aria-label if present */
71
+ ariaLabel?: string;
72
+ /** data-testid if present */
73
+ testId?: string;
74
+ /** Element role */
75
+ role?: string;
76
+ /** Element type */
77
+ type: string;
78
+ /** Whether selector is considered stable */
79
+ stable: boolean;
80
+ }
81
+ /**
82
+ * Form field information
83
+ */
84
+ export interface FieldInfo extends ElementInfo {
85
+ /** Field input type */
86
+ inputType: string;
87
+ /** Field name */
88
+ name?: string;
89
+ /** Whether field is required */
90
+ required: boolean;
91
+ /** Placeholder text */
92
+ placeholder?: string;
93
+ /** Options for select elements */
94
+ options?: string[];
95
+ /** Validation attributes */
96
+ validation?: {
97
+ min?: number | string;
98
+ max?: number | string;
99
+ pattern?: string;
100
+ minLength?: number;
101
+ maxLength?: number;
102
+ };
103
+ }
104
+ /**
105
+ * Form definition discovered on a page
106
+ */
107
+ export interface FormInfo {
108
+ /** Form action/endpoint */
109
+ action?: string;
110
+ /** Form method */
111
+ method?: string;
112
+ /** Stable selector for the form */
113
+ selector: string;
114
+ /** Form purpose (detected) */
115
+ purpose: 'login' | 'signup' | 'search' | 'contact' | 'checkout' | 'filter' | 'other';
116
+ /** All fields in the form */
117
+ fields: FieldInfo[];
118
+ /** Submit button */
119
+ submitButton?: ElementInfo;
120
+ /** Confidence score for purpose detection (0-1) */
121
+ confidence: number;
122
+ }
123
+ /**
124
+ * Link information
125
+ */
126
+ export interface LinkInfo extends ElementInfo {
127
+ /** href URL */
128
+ url: string;
129
+ /** Whether link is internal to the domain */
130
+ internal: boolean;
131
+ /** Whether link was visited */
132
+ visited: boolean;
133
+ }
134
+ /**
135
+ * Page definition after crawling
136
+ */
137
+ export interface PageDefinition {
138
+ /** Full URL */
139
+ url: string;
140
+ /** Path relative to base */
141
+ path: string;
142
+ /** Page title */
143
+ title: string;
144
+ /** Depth from base URL */
145
+ depth: number;
146
+ /** HTTP status code */
147
+ status: number;
148
+ /** Load time in milliseconds */
149
+ loadTime: number;
150
+ /** Content type */
151
+ contentType?: string;
152
+ /** Meta description */
153
+ description?: string;
154
+ /** All discovered elements */
155
+ elements: {
156
+ /** Buttons on the page */
157
+ buttons: ElementInfo[];
158
+ /** Links on the page */
159
+ links: LinkInfo[];
160
+ /** Forms on the page */
161
+ forms: FormInfo[];
162
+ /** Input fields (standalone) */
163
+ inputs: FieldInfo[];
164
+ /** Select dropdowns */
165
+ selects: FieldInfo[];
166
+ /** Checkboxes */
167
+ checkboxes: ElementInfo[];
168
+ /** Radio buttons */
169
+ radios: ElementInfo[];
170
+ };
171
+ /** Navigation elements detected */
172
+ navigation: {
173
+ /** Main navigation menu */
174
+ main?: {
175
+ selector: string;
176
+ items: LinkInfo[];
177
+ };
178
+ /** Breadcrumb */
179
+ breadcrumb?: {
180
+ selector: string;
181
+ items: Array<{
182
+ text: string;
183
+ url: string;
184
+ }>;
185
+ };
186
+ /** Pagination */
187
+ pagination?: {
188
+ selector: string;
189
+ nextPage?: LinkInfo;
190
+ prevPage?: LinkInfo;
191
+ };
192
+ /** Footer links */
193
+ footer?: {
194
+ selector: string;
195
+ items: LinkInfo[];
196
+ };
197
+ };
198
+ /** Screenshot (base64) */
199
+ screenshot?: string;
200
+ /** Accessibility snapshot */
201
+ accessibility?: A11ySnapshot;
202
+ /** Page type detected */
203
+ pageType: 'homepage' | 'listing' | 'detail' | 'form' | 'dashboard' | 'login' | 'signup' | 'other';
204
+ /** Confidence for page type (0-1) */
205
+ pageTypeConfidence: number;
206
+ }
207
+ /**
208
+ * Accessibility snapshot from axe-core
209
+ */
210
+ export interface A11ySnapshot {
211
+ /** Accessibility score (0-100) */
212
+ score: number;
213
+ /** Violations found */
214
+ violations: Array<{
215
+ id: string;
216
+ impact: 'critical' | 'serious' | 'moderate' | 'minor';
217
+ description: string;
218
+ nodes: number;
219
+ selectors: string[];
220
+ }>;
221
+ /** Pass count */
222
+ passes: number;
223
+ /** Incomplete checks */
224
+ incomplete: number;
225
+ }
226
+ /**
227
+ * User journey discovered
228
+ */
229
+ export interface UserJourney {
230
+ /** Journey name */
231
+ name: string;
232
+ /** Journey description */
233
+ description: string;
234
+ /** Journey type */
235
+ type: 'authentication' | 'navigation' | 'transaction' | 'search' | 'form-submission' | 'other';
236
+ /** Steps in the journey */
237
+ steps: JourneyStep[];
238
+ /** Entry point URL */
239
+ entryPoint: string;
240
+ /** Expected final URL */
241
+ finalUrl?: string;
242
+ /** Estimated duration in seconds */
243
+ estimatedDuration: number;
244
+ }
245
+ /**
246
+ * Single step in a user journey
247
+ */
248
+ export interface JourneyStep {
249
+ /** Step order */
250
+ order: number;
251
+ /** Step description */
252
+ description: string;
253
+ /** Action to perform */
254
+ action: JourneyAction;
255
+ /** Target selector */
256
+ selector?: string;
257
+ /** Value to input (for fill actions) */
258
+ value?: string;
259
+ /** Expected outcome */
260
+ expected?: {
261
+ /** Expected URL after action */
262
+ url?: string;
263
+ /** Expected visible element */
264
+ visible?: string;
265
+ /** Expected text content */
266
+ text?: string;
267
+ };
268
+ /** Wait time in ms */
269
+ wait?: number;
270
+ }
271
+ /**
272
+ * Journey action types
273
+ */
274
+ export type JourneyAction = 'navigate' | 'click' | 'fill' | 'select' | 'check' | 'uncheck' | 'upload' | 'hover' | 'press' | 'waitFor' | 'waitForNavigation' | 'scroll';
275
+ /**
276
+ * Site map structure
277
+ */
278
+ export interface SiteMap {
279
+ /** Base URL */
280
+ baseUrl: string;
281
+ /** All discovered pages */
282
+ pages: PageDefinition[];
283
+ /** Pages by depth */
284
+ pagesByDepth: Record<number, PageDefinition[]>;
285
+ /** Orphan pages (no links to them) */
286
+ orphans: PageDefinition[];
287
+ /** Page type distribution */
288
+ pageTypeDistribution: Record<string, number>;
289
+ /** Total unique links */
290
+ totalLinks: number;
291
+ /** Total forms */
292
+ totalForms: number;
293
+ /** Crawl metadata */
294
+ metadata: {
295
+ /** Pages crawled */
296
+ pagesCrawled: number;
297
+ /** Pages skipped (excluded) */
298
+ pagesSkipped: number;
299
+ /** Pages failed */
300
+ pagesFailed: number;
301
+ /** Total duration in ms */
302
+ duration: number;
303
+ /** Average page load time */
304
+ avgLoadTime: number;
305
+ /** Max depth reached */
306
+ maxDepth: number;
307
+ };
308
+ }
309
+ /**
310
+ * Complete crawl result
311
+ */
312
+ export interface CrawlResult {
313
+ /** Success status */
314
+ success: boolean;
315
+ /** Site map */
316
+ siteMap: SiteMap;
317
+ /** Discovered user journeys */
318
+ userJourneys: UserJourney[];
319
+ /** Forms requiring testing */
320
+ forms: FormInfo[];
321
+ /** Pages requiring accessibility testing */
322
+ accessibilityIssues: Array<{
323
+ page: string;
324
+ score: number;
325
+ violations: A11ySnapshot['violations'];
326
+ }>;
327
+ /** Warnings */
328
+ warnings: string[];
329
+ /** Errors */
330
+ errors: Array<{
331
+ page: string;
332
+ error: string;
333
+ }>;
334
+ }
335
+ /**
336
+ * Crawler progress callback
337
+ */
338
+ export interface CrawlProgress {
339
+ /** Current page being crawled */
340
+ currentPage: string;
341
+ /** Pages completed */
342
+ completed: number;
343
+ /** Total pages to crawl */
344
+ total: number;
345
+ /** Percentage complete */
346
+ progress: number;
347
+ /** Current depth */
348
+ depth: number;
349
+ }
350
+ /**
351
+ * Crawler events
352
+ */
353
+ export type CrawlEventHandler = (event: 'page-start' | 'page-complete' | 'page-error' | 'journey-discovered' | 'complete', data: CrawlProgress | PageDefinition | UserJourney | CrawlResult) => void;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * QA360 Web Crawler - Type Definitions
3
+ *
4
+ * Automatically discovers and analyzes web applications for E2E test generation
5
+ */
6
+ export {};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * QA360 Crawler Pack Generator
3
+ *
4
+ * Crawls a website and generates a complete pack.yml with E2E tests
5
+ */
6
+ import type { CrawlOptions, CrawlResult } from '../crawler/index.js';
7
+ /**
8
+ * Crawler Pack Generator Options
9
+ */
10
+ export interface CrawlerPackGeneratorOptions {
11
+ /** Base URL to crawl */
12
+ baseUrl: string;
13
+ /** Output pack file path */
14
+ output?: string;
15
+ /** Crawl options */
16
+ crawl?: Partial<CrawlOptions>;
17
+ /** Pack name */
18
+ packName?: string;
19
+ /** Include accessibility tests */
20
+ includeA11y?: boolean;
21
+ /** Include performance tests */
22
+ includePerf?: boolean;
23
+ /** Include security tests */
24
+ includeSecurity?: boolean;
25
+ /** Custom journey names */
26
+ journeyNames?: Record<string, string>;
27
+ }
28
+ /**
29
+ * Generate pack.yml from crawled website
30
+ */
31
+ export declare function generatePackFromCrawl(options: CrawlerPackGeneratorOptions): Promise<{
32
+ success: boolean;
33
+ packPath?: string;
34
+ result?: CrawlResult;
35
+ error?: string;
36
+ }>;
37
+ /**
38
+ * Quick crawl - generates pack without detailed analysis
39
+ */
40
+ export declare function quickCrawl(baseUrl: string, outputPath?: string): Promise<{
41
+ success: boolean;
42
+ packPath?: string;
43
+ error?: string;
44
+ }>;