@desplega.ai/qa-use 2.2.4 → 2.3.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.
Files changed (34) hide show
  1. package/dist/lib/api/browser-types.d.ts +19 -1
  2. package/dist/lib/api/browser-types.d.ts.map +1 -1
  3. package/dist/lib/api/browser.d.ts +5 -3
  4. package/dist/lib/api/browser.d.ts.map +1 -1
  5. package/dist/lib/api/browser.js +22 -3
  6. package/dist/lib/api/browser.js.map +1 -1
  7. package/dist/lib/api/index.d.ts +1 -0
  8. package/dist/lib/api/index.d.ts.map +1 -1
  9. package/dist/lib/api/index.js.map +1 -1
  10. package/dist/package.json +1 -1
  11. package/dist/src/cli/commands/browser/create.d.ts.map +1 -1
  12. package/dist/src/cli/commands/browser/create.js +44 -1
  13. package/dist/src/cli/commands/browser/create.js.map +1 -1
  14. package/dist/src/cli/commands/browser/run.d.ts.map +1 -1
  15. package/dist/src/cli/commands/browser/run.js +67 -9
  16. package/dist/src/cli/commands/browser/run.js.map +1 -1
  17. package/dist/src/cli/commands/browser/snapshot.d.ts.map +1 -1
  18. package/dist/src/cli/commands/browser/snapshot.js +14 -2
  19. package/dist/src/cli/commands/browser/snapshot.js.map +1 -1
  20. package/dist/src/cli/commands/test/export.d.ts.map +1 -1
  21. package/dist/src/cli/commands/test/export.js +47 -30
  22. package/dist/src/cli/commands/test/export.js.map +1 -1
  23. package/dist/src/cli/commands/test/sync.d.ts.map +1 -1
  24. package/dist/src/cli/commands/test/sync.js +54 -28
  25. package/dist/src/cli/commands/test/sync.js.map +1 -1
  26. package/dist/src/cli/lib/loader.d.ts +8 -0
  27. package/dist/src/cli/lib/loader.d.ts.map +1 -1
  28. package/dist/src/cli/lib/loader.js +38 -7
  29. package/dist/src/cli/lib/loader.js.map +1 -1
  30. package/lib/api/browser-types.ts +21 -1
  31. package/lib/api/browser.test.ts +50 -0
  32. package/lib/api/browser.ts +24 -3
  33. package/lib/api/index.ts +1 -0
  34. package/package.json +1 -1
@@ -53,6 +53,28 @@ export function resolveTestPath(testNameOrPath, directory) {
53
53
  }
54
54
  throw new Error(`Test file not found: ${testNameOrPath}`);
55
55
  }
56
+ /**
57
+ * Find a local test file by its ID
58
+ *
59
+ * @param testId - The UUID to search for
60
+ * @param directory - Test directory root
61
+ * @returns File path if found, null otherwise
62
+ */
63
+ export async function findLocalTestById(testId, directory) {
64
+ const files = await discoverTests(directory);
65
+ for (const file of files) {
66
+ try {
67
+ const def = await loadTestDefinition(file);
68
+ if (def.id === testId) {
69
+ return file;
70
+ }
71
+ }
72
+ catch {
73
+ // Skip files that fail to load
74
+ }
75
+ }
76
+ return null;
77
+ }
56
78
  /**
57
79
  * Load a test and all its dependencies recursively
58
80
  *
@@ -63,22 +85,31 @@ export function resolveTestPath(testNameOrPath, directory) {
63
85
  export async function loadTestWithDeps(testName, directory) {
64
86
  const definitions = [];
65
87
  const loaded = new Set();
66
- async function loadRecursive(name) {
88
+ async function loadRecursive(nameOrPath, isFullPath = false) {
67
89
  // Avoid circular dependencies
68
- if (loaded.has(name))
90
+ if (loaded.has(nameOrPath))
69
91
  return;
70
- loaded.add(name);
71
- const filePath = resolveTestPath(name, directory);
92
+ loaded.add(nameOrPath);
93
+ // If isFullPath is true (from findLocalTestById), use directly; otherwise resolve
94
+ const filePath = isFullPath ? nameOrPath : resolveTestPath(nameOrPath, directory);
72
95
  const def = await loadTestDefinition(filePath);
73
- // Load dependency first (if it exists and is a local file)
96
+ // Load dependency first (if it exists)
74
97
  if (def.depends_on) {
75
98
  // Check if depends_on is a UUID (cloud test) or a file name
76
99
  const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(def.depends_on);
77
- if (!isUuid) {
100
+ if (isUuid) {
101
+ // Try to find local file with this ID first
102
+ const localFile = await findLocalTestById(def.depends_on, directory);
103
+ if (localFile) {
104
+ // Load from local file (localFile is already a full path from discoverTests)
105
+ await loadRecursive(localFile, true);
106
+ }
107
+ // If not found locally, API will resolve at runtime
108
+ }
109
+ else {
78
110
  // It's a local file reference
79
111
  await loadRecursive(def.depends_on);
80
112
  }
81
- // If it's a UUID, the API will resolve it
82
113
  }
83
114
  definitions.push(def);
84
115
  }
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../../src/cli/lib/loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../../src/cli/lib/loader.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,7 @@
6
6
  // Session Types
7
7
  // ==========================================
8
8
 
9
- export type BrowserSessionStatus = 'starting' | 'active' | 'closing' | 'closed';
9
+ export type BrowserSessionStatus = 'starting' | 'active' | 'closing' | 'closed' | 'failed';
10
10
 
11
11
  export type ViewportType = 'desktop' | 'mobile' | 'tablet';
12
12
 
@@ -16,6 +16,8 @@ export interface CreateBrowserSessionOptions {
16
16
  timeout?: number; // Session timeout in seconds (60-3600)
17
17
  ws_url?: string; // WebSocket URL for remote/tunneled browser
18
18
  record_blocks?: boolean; // Enable block recording for test generation
19
+ after_test_id?: string; // Run a test before session becomes interactive
20
+ vars?: Record<string, string>; // Variable overrides for after_test_id test
19
21
  }
20
22
 
21
23
  export interface BrowserSession {
@@ -167,6 +169,17 @@ export interface WaitForLoadAction {
167
169
 
168
170
  export interface SnapshotAction {
169
171
  type: 'snapshot';
172
+ interactive?: boolean;
173
+ compact?: boolean;
174
+ max_depth?: number;
175
+ scope?: string;
176
+ }
177
+
178
+ export interface SnapshotOptions {
179
+ interactive?: boolean; // Only include interactive elements
180
+ compact?: boolean; // Remove empty structural elements
181
+ max_depth?: number; // Limit tree depth (1-20)
182
+ scope?: string; // CSS selector to scope snapshot
170
183
  }
171
184
 
172
185
  export interface ScreenshotAction {
@@ -209,9 +222,16 @@ export interface ActionResult {
209
222
  url_after?: string; // URL after action executed
210
223
  }
211
224
 
225
+ export interface SnapshotFilterStats {
226
+ original_lines: number;
227
+ filtered_lines: number;
228
+ reduction_percent: number;
229
+ }
230
+
212
231
  export interface SnapshotResult {
213
232
  snapshot: string;
214
233
  url?: string;
234
+ filter_stats?: SnapshotFilterStats;
215
235
  }
216
236
 
217
237
  export interface UrlResult {
@@ -286,6 +286,56 @@ describe('BrowserApiClient', () => {
286
286
  expect(snapshot.snapshot).toContain('Example');
287
287
  expect(snapshot.url).toBe('https://example.com');
288
288
  });
289
+
290
+ it('should get ARIA snapshot with filtering options', async () => {
291
+ const mockSnapshot = {
292
+ snapshot: '- button "Submit" [ref=e1]',
293
+ url: 'https://example.com',
294
+ filter_stats: {
295
+ original_lines: 450,
296
+ filtered_lines: 42,
297
+ reduction_percent: 91,
298
+ },
299
+ };
300
+ mockAxiosInstance.get.mockResolvedValueOnce({ data: mockSnapshot });
301
+
302
+ const snapshot = await client.getSnapshot('session-123', {
303
+ interactive: true,
304
+ compact: true,
305
+ max_depth: 3,
306
+ });
307
+
308
+ expect(mockAxiosInstance.get).toHaveBeenCalledWith(
309
+ '/sessions/session-123/snapshot?interactive=true&compact=true&max_depth=3'
310
+ );
311
+ expect(snapshot.filter_stats?.reduction_percent).toBe(91);
312
+ });
313
+
314
+ it('should get ARIA snapshot with scope option', async () => {
315
+ const mockSnapshot = {
316
+ snapshot: '- heading "Main Content" [ref=e1]',
317
+ url: 'https://example.com',
318
+ };
319
+ mockAxiosInstance.get.mockResolvedValueOnce({ data: mockSnapshot });
320
+
321
+ await client.getSnapshot('session-123', { scope: '#main' });
322
+
323
+ expect(mockAxiosInstance.get).toHaveBeenCalledWith(
324
+ '/sessions/session-123/snapshot?scope=%23main'
325
+ );
326
+ });
327
+
328
+ it('should get ARIA snapshot without options (backward compatible)', async () => {
329
+ const mockSnapshot = {
330
+ snapshot: '- heading "Example" [ref=e1]',
331
+ url: 'https://example.com',
332
+ };
333
+ mockAxiosInstance.get.mockResolvedValueOnce({ data: mockSnapshot });
334
+
335
+ await client.getSnapshot('session-123');
336
+
337
+ expect(mockAxiosInstance.get).toHaveBeenCalledWith('/sessions/session-123/snapshot');
338
+ });
289
339
  });
290
340
 
291
341
  describe('getScreenshot', () => {
@@ -10,6 +10,7 @@ import type {
10
10
  BrowserAction,
11
11
  ActionResult,
12
12
  SnapshotResult,
13
+ SnapshotOptions,
13
14
  UrlResult,
14
15
  BlocksResult,
15
16
  CreateBrowserSessionOptions,
@@ -74,6 +75,8 @@ export class BrowserApiClient {
74
75
  timeout: options.timeout ?? 300,
75
76
  ...(options.ws_url && { ws_url: options.ws_url }),
76
77
  ...(options.record_blocks !== undefined && { record_blocks: options.record_blocks }),
78
+ ...(options.after_test_id && { after_test_id: options.after_test_id }),
79
+ ...(options.vars && Object.keys(options.vars).length > 0 && { vars: options.vars }),
77
80
  });
78
81
 
79
82
  return response.data as BrowserSession;
@@ -140,11 +143,16 @@ export class BrowserApiClient {
140
143
  return session;
141
144
  }
142
145
 
143
- // If session is closed or failed, throw error
146
+ // If session is closed, throw error
144
147
  if (session.status === 'closed') {
145
148
  throw new Error(`Session ${sessionId} is closed`);
146
149
  }
147
150
 
151
+ // If session failed (e.g., after_test_id test failed), return session for error handling
152
+ if (session.status === 'failed') {
153
+ return session;
154
+ }
155
+
148
156
  // Wait before polling again
149
157
  await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
150
158
  }
@@ -174,10 +182,21 @@ export class BrowserApiClient {
174
182
 
175
183
  /**
176
184
  * Get the ARIA accessibility tree snapshot
185
+ * @param sessionId - The session ID
186
+ * @param options - Filtering options (interactive, compact, max_depth, scope)
177
187
  */
178
- async getSnapshot(sessionId: string): Promise<SnapshotResult> {
188
+ async getSnapshot(sessionId: string, options: SnapshotOptions = {}): Promise<SnapshotResult> {
179
189
  try {
180
- const response = await this.client.get(`/sessions/${sessionId}/snapshot`);
190
+ const params = new URLSearchParams();
191
+ if (options.interactive) params.append('interactive', 'true');
192
+ if (options.compact) params.append('compact', 'true');
193
+ if (options.max_depth !== undefined) params.append('max_depth', options.max_depth.toString());
194
+ if (options.scope) params.append('scope', options.scope);
195
+
196
+ const queryString = params.toString();
197
+ const url = `/sessions/${sessionId}/snapshot${queryString ? `?${queryString}` : ''}`;
198
+
199
+ const response = await this.client.get(url);
181
200
  return response.data as SnapshotResult;
182
201
  } catch (error) {
183
202
  throw this.handleError(error, 'get snapshot');
@@ -354,6 +373,8 @@ export type {
354
373
  BrowserAction,
355
374
  ActionResult,
356
375
  SnapshotResult,
376
+ SnapshotOptions,
377
+ SnapshotFilterStats,
357
378
  UrlResult,
358
379
  CreateBrowserSessionOptions,
359
380
  BrowserSessionStatus,
package/lib/api/index.ts CHANGED
@@ -236,6 +236,7 @@ export interface RunCliTestOptions {
236
236
  store_recording?: boolean;
237
237
  store_har?: boolean;
238
238
  ws_url?: string;
239
+ vars?: Record<string, string>; // Variable overrides for cloud test (test_id)
239
240
  }
240
241
 
241
242
  export type SSECallback = (event: SSEEvent) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desplega.ai/qa-use",
3
- "version": "2.2.4",
3
+ "version": "2.3.0",
4
4
  "packageManager": "bun@^1.3.4",
5
5
  "description": "QA automation tool for browser testing with MCP server support",
6
6
  "type": "module",