@browserstack/mcp-server 2.2.5 → 2.2.6-beta.2

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 (38) hide show
  1. package/README.md +32 -194
  2. package/dist/lib/accessibility-routing.d.ts +6 -0
  3. package/dist/lib/accessibility-routing.js +6 -0
  4. package/dist/server-factory.js +6 -1
  5. package/dist/tools/accessibility.js +680 -69
  6. package/dist/tools/accessiblity-utils/app-report-fetcher.d.ts +412 -0
  7. package/dist/tools/accessiblity-utils/app-report-fetcher.js +926 -0
  8. package/dist/tools/accessiblity-utils/paginate.d.ts +27 -0
  9. package/dist/tools/accessiblity-utils/paginate.js +50 -0
  10. package/dist/tools/accessiblity-utils/report-fetcher.d.ts +116 -7
  11. package/dist/tools/accessiblity-utils/report-fetcher.js +268 -29
  12. package/dist/tools/accessiblity-utils/report-parser.d.ts +41 -1
  13. package/dist/tools/accessiblity-utils/report-parser.js +142 -43
  14. package/dist/tools/accessiblity-utils/scanner.d.ts +15 -1
  15. package/dist/tools/accessiblity-utils/scanner.js +3 -4
  16. package/dist/tools/appautomate-utils/appium-sdk/config-generator.d.ts +2 -0
  17. package/dist/tools/appautomate-utils/appium-sdk/config-generator.js +15 -5
  18. package/dist/tools/appautomate-utils/appium-sdk/constants.d.ts +2 -1
  19. package/dist/tools/appautomate-utils/appium-sdk/constants.js +6 -1
  20. package/dist/tools/appautomate-utils/appium-sdk/handler.js +12 -1
  21. package/dist/tools/appautomate-utils/appium-sdk/instructions.d.ts +3 -1
  22. package/dist/tools/appautomate-utils/appium-sdk/instructions.js +2 -2
  23. package/dist/tools/appautomate-utils/appium-sdk/languages/accessibility.d.ts +4 -0
  24. package/dist/tools/appautomate-utils/appium-sdk/languages/accessibility.js +47 -0
  25. package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.d.ts +3 -1
  26. package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.js +19 -6
  27. package/dist/tools/appautomate-utils/native-execution/appautomate.d.ts +7 -2
  28. package/dist/tools/appautomate-utils/native-execution/appautomate.js +15 -12
  29. package/dist/tools/appautomate-utils/native-execution/constants.d.ts +2 -1
  30. package/dist/tools/appautomate-utils/native-execution/constants.js +6 -1
  31. package/dist/tools/appautomate.js +29 -16
  32. package/dist/tools/testmanagement-utils/create-testrun.d.ts +1 -1
  33. package/dist/tools/testmanagement-utils/update-testrun.d.ts +1 -1
  34. package/dist/tools/tool-handoff.d.ts +3 -2
  35. package/dist/tools/tool-handoff.js +3 -2
  36. package/package.json +1 -1
  37. package/dist/tools/accessiblity-utils/accessibility-rag.d.ts +0 -12
  38. package/dist/tools/accessiblity-utils/accessibility-rag.js +0 -59
@@ -0,0 +1,412 @@
1
+ /**
2
+ * App Accessibility: the issues of a mobile app build run through App Automate with
3
+ * accessibility on. Unlike the web products there is no CSV export behind an access key,
4
+ * so the issues come inline, one API page per batch of scanned screens.
5
+ */
6
+ export declare const APP_API_BASE = "https://api-app-accessibility.browserstack.com/automate/api/v1";
7
+ export declare const APP_DASHBOARD = "https://app-accessibility.browserstack.com";
8
+ /** Manual (Workflow Analyzer) reports recorded on the dashboard: a separate, older route. */
9
+ export declare const MANUAL_API_BASE = "https://api-app-accessibility.browserstack.com/api/v1";
10
+ export declare const MAX_SNAPSHOT_PAGES = 20;
11
+ /** A dashboard link names a build by number; a build someone just opened is among the newest. */
12
+ export declare const MAX_APP_BUILD_LIST_PAGES = 3;
13
+ export declare const MAX_APP_AUTOMATE_BUILD_PAGES = 3;
14
+ export interface AppBuildMeta {
15
+ /** The build's number within its project, which the dashboard link uses. */
16
+ build_id: number;
17
+ created_at?: string;
18
+ th_build_id: string;
19
+ name: string;
20
+ normalised_name: string;
21
+ project_name: string;
22
+ /** running | rule_processing | passed | failed | timeout | update_os_version */
23
+ status: string;
24
+ issue_summary?: {
25
+ total?: number;
26
+ scan_count?: number;
27
+ };
28
+ fup?: {
29
+ capped?: boolean;
30
+ tests_partial?: boolean;
31
+ tests_dropped?: boolean;
32
+ };
33
+ /** What ran the tests: an SDK framework (pytest, …) or a native one (Espresso-Junit4, …). */
34
+ session_data?: {
35
+ framework?: {
36
+ name?: string;
37
+ };
38
+ };
39
+ }
40
+ interface AppRuleIssue {
41
+ uid: string;
42
+ status?: string;
43
+ duplication_count?: number;
44
+ issue_class_android?: string;
45
+ issue_class_ios?: string;
46
+ issue_id_android?: string;
47
+ issue_id_ios?: string;
48
+ /** An iOS element's class. */
49
+ issue_type_ios?: string;
50
+ how_to_fix_desc?: string;
51
+ issue_details?: {
52
+ label?: string;
53
+ value?: unknown;
54
+ important?: boolean;
55
+ }[];
56
+ /** The rule's inputs for this element, among them what it expects (`expected_ratio`, …). */
57
+ rule_dynamic_meta?: Record<string, unknown>;
58
+ }
59
+ interface AppRule {
60
+ rule_id: string;
61
+ label: string;
62
+ description?: string;
63
+ severity?: string;
64
+ guidelines?: {
65
+ message?: string;
66
+ }[];
67
+ rule_issues?: AppRuleIssue[];
68
+ }
69
+ export interface AppSnapshot {
70
+ meta?: {
71
+ screenshot_url?: string;
72
+ testcase_name?: string;
73
+ /** A manual report's snapshot keeps its rules here. */
74
+ aggregated_results?: AppRule[];
75
+ };
76
+ aggregated_results?: AppRule[];
77
+ }
78
+ export type AppAccessibilityIssue = {
79
+ issue_type: string;
80
+ rule_id: string;
81
+ severity: string;
82
+ /** Which scanned screen of which test the element was on. */
83
+ screen: string;
84
+ /** The element's id when it has one, else its class. */
85
+ component: string;
86
+ /** The element's identifying details, as captured on the device. */
87
+ element: Record<string, unknown>;
88
+ issue_description: string;
89
+ how_to_fix: string;
90
+ /** The WCAG success criteria the rule maps to. */
91
+ wcag: string;
92
+ screenshot?: string;
93
+ /** How many more occurrences of this issue the report folded into it. */
94
+ duplicate_count?: number;
95
+ /**
96
+ * What the rule measured on the element (a contrast issue's colours and ratio, a touch
97
+ * target's size, a font size, the label it found) and what it expects, so a fix can be
98
+ * sized.
99
+ */
100
+ measured?: Record<string, unknown>;
101
+ };
102
+ /** A report's issues counted by severity, by rule and by screen, largest first. */
103
+ export interface AppIssueSummary {
104
+ by_severity: Record<string, number>;
105
+ by_rule: {
106
+ rule_id: string;
107
+ issue_type: string;
108
+ count: number;
109
+ }[];
110
+ by_screen: {
111
+ screen: string;
112
+ count: number;
113
+ }[];
114
+ }
115
+ /** An issue as a page hands it out: what is its own, with its rule and screen named. */
116
+ export type AppIssueRow = Omit<AppAccessibilityIssue, "issue_type" | "issue_description" | "wcag" | "screenshot" | "how_to_fix" | "component"> & {
117
+ /** The element's id or class; an element with neither is known by its rule. */
118
+ component?: string;
119
+ /** Only when it differs from the rule's usual fix, which is under the page's rules. */
120
+ how_to_fix?: string;
121
+ };
122
+ /** What a page's issues share, said once: per rule, and each screen's screenshot. */
123
+ export interface AppIssuePageContext {
124
+ rules: Record<string, {
125
+ issue_type: string;
126
+ issue_description: string;
127
+ wcag: string;
128
+ how_to_fix: string;
129
+ }>;
130
+ screens: Record<string, string>;
131
+ }
132
+ export interface AppBuildReport extends AppIssuePageContext {
133
+ records: AppIssueRow[];
134
+ page_length: number;
135
+ total_issues: number;
136
+ next_page: number | null;
137
+ /** How many issues the pages after this one hold. */
138
+ remaining: number;
139
+ summary: AppIssueSummary;
140
+ /** Issues hidden in the dashboard, which the API leaves out of the screens. */
141
+ hidden_issues: number;
142
+ scan_count: number;
143
+ status: string;
144
+ build_name: string;
145
+ dashboard_link?: string;
146
+ /** Whether the fair-usage cap dropped tests or scans from this build. */
147
+ fup_capped: boolean;
148
+ /** The test framework the build ran under, when the build's details name it. */
149
+ framework?: string;
150
+ /** How many screens were read, when the snapshot page limit stopped short of them all. */
151
+ screens_read?: number;
152
+ }
153
+ /** A manual (Workflow Analyzer) report's issues, read inline from its scanned screens. */
154
+ export interface AppManualReport extends AppIssuePageContext {
155
+ records: AppIssueRow[];
156
+ page_length: number;
157
+ /**
158
+ * The issues, duplicates left out as the dashboard leaves them out when `deduplicated`;
159
+ * else every occurrence the Manual Reports API lists, which does not mark duplicates.
160
+ */
161
+ total_issues: number;
162
+ /** Read from the dashboard's own screens: duplicates left out, issues with their element. */
163
+ deduplicated: boolean;
164
+ next_page: number | null;
165
+ /** How many issues the pages after this one hold. */
166
+ remaining: number;
167
+ summary: AppIssueSummary;
168
+ dashboard_count: number;
169
+ duplicate_occurrences: number;
170
+ hidden_issues: number;
171
+ scan_count: number;
172
+ /** complete | in_progress */
173
+ status: string;
174
+ report_name: string;
175
+ device?: string;
176
+ dashboard_link: string;
177
+ }
178
+ /** Every issue of one app build, with what a comparison needs to know of the build. */
179
+ export interface AppBuildIssues {
180
+ buildId: string;
181
+ build_name: string;
182
+ build_number: number;
183
+ created_at?: string;
184
+ status: string;
185
+ scan_count: number;
186
+ /** The tests whose screens were scanned, in the order first seen. */
187
+ tests: string[];
188
+ issues: AppAccessibilityIssue[];
189
+ }
190
+ /** An earlier build of a project, as the build list names it. */
191
+ export interface AppBuildRef {
192
+ buildId: string;
193
+ name?: string;
194
+ build_number?: number;
195
+ created_at?: string;
196
+ /** Whether it has the later build's name; a native run's builds are each named apart. */
197
+ same_name: boolean;
198
+ /**
199
+ * Whether the project's whole build list was read. When it was not, a build of the same
200
+ * name may still be further back than the newest builds read.
201
+ */
202
+ searched_all: boolean;
203
+ }
204
+ export interface AppProjectRow {
205
+ id: number;
206
+ name: string;
207
+ created_at?: string;
208
+ }
209
+ /** A build as the listing tool shows it: what it is, how it went, and how to read it. */
210
+ export interface AppBuildRow {
211
+ buildId: string;
212
+ build_number?: number;
213
+ name: string;
214
+ status?: string;
215
+ report_status?: string;
216
+ created_at?: string;
217
+ scan_count: number;
218
+ issues: {
219
+ total: number;
220
+ critical: number;
221
+ serious: number;
222
+ moderate: number;
223
+ minor: number;
224
+ };
225
+ app?: string;
226
+ framework?: string;
227
+ dashboard_link: string;
228
+ }
229
+ export interface AppManualReportRow {
230
+ reportId: string;
231
+ name: string;
232
+ status?: string;
233
+ created_at?: string;
234
+ app?: string;
235
+ scan_count: number;
236
+ issues: {
237
+ total: number;
238
+ critical: number;
239
+ serious: number;
240
+ moderate: number;
241
+ minor: number;
242
+ duplicates: number;
243
+ hidden: number;
244
+ };
245
+ dashboard_link: string;
246
+ }
247
+ /** One row per element with an issue, most severe first. Screens are numbered in order. */
248
+ export declare function flattenAppSnapshots(details: AppSnapshot[]): AppAccessibilityIssue[];
249
+ /**
250
+ * An issue's name, description, WCAG criteria and fix are its rule's, and its screenshot is
251
+ * its screen's: two thirds of an issue's length, repeated on every one. Said once, under
252
+ * the page's rules and screens, a page holds about three times as many issues. An issue
253
+ * keeps its own fix only when it differs from its rule's usual one.
254
+ */
255
+ export declare function compactAppIssues(all: AppAccessibilityIssue[]): {
256
+ rows: AppIssueRow[];
257
+ context: AppIssuePageContext;
258
+ };
259
+ /** The rules and screens a page's issues name, and nothing else. */
260
+ export declare function contextOf(records: AppIssueRow[], { rules, screens }: AppIssuePageContext): AppIssuePageContext;
261
+ /** The issues counted by severity, by rule and by screen, largest first. */
262
+ export declare function summarizeAppIssues(rows: AppAccessibilityIssue[]): AppIssueSummary;
263
+ /**
264
+ * Which issues of two builds are the same issue. Issues that look alike (one rule on
265
+ * elements known by neither id nor label) are paired one for one, those on the same screen
266
+ * and spot first, then on the same screen, then any; what is left over in either build is
267
+ * new or resolved. When the builds scanned a different number of screens, a screen one of
268
+ * them has no counterpart for is set apart: an earlier screen's leftovers were not seen
269
+ * again (`unconfirmed`), and a later screen's were not looked for before (`first_scanned`).
270
+ * With as many screens in each, they correspond, and a screen with nothing left was fixed.
271
+ * So new, first scanned and still open add up to the later build's issues, and resolved,
272
+ * unconfirmed and still open to the earlier one's.
273
+ */
274
+ export declare function compareAppIssues(before: AppAccessibilityIssue[], after: AppAccessibilityIssue[], { sameScreens }?: {
275
+ sameScreens?: boolean;
276
+ }): {
277
+ added: AppAccessibilityIssue[];
278
+ first_scanned: AppAccessibilityIssue[];
279
+ resolved: AppAccessibilityIssue[];
280
+ unconfirmed: AppAccessibilityIssue[];
281
+ retained: number;
282
+ };
283
+ /** The id a manual report's dashboard link names (`/report/{uuid}`), if it is one. */
284
+ export declare function manualReportIdFromDashboardLink(url: URL): string | undefined;
285
+ /** A manual report has no status of its own; it is complete once it has ended. */
286
+ export declare function manualReportStatus(detail: {
287
+ meta_data?: {
288
+ ended_at?: string | null;
289
+ };
290
+ }): string;
291
+ export declare class AppAccessibilityApi {
292
+ private readonly headers;
293
+ constructor(headers: () => Record<string, string> | undefined);
294
+ /** The build's details, or undefined when the API does not know the id. */
295
+ buildMeta(buildId: string): Promise<AppBuildMeta | undefined>;
296
+ /**
297
+ * The id of the build an App Accessibility dashboard link points at, if it is one: the
298
+ * project's newest builds, by number. (The list's name filter would not do: the link
299
+ * carries TestHub's name for the build, which the filter does not match.)
300
+ */
301
+ buildIdFromDashboardLink(url: URL): Promise<string | undefined>;
302
+ /**
303
+ * The accessibility build of an App Automate build or session link. An SDK (Appium)
304
+ * session's test code carries the TestHub build id its results went to, which is the
305
+ * App Accessibility build when accessibility was on; a build link goes through any one
306
+ * of its sessions. A native (Espresso, XCUITest) build has no SDK session, and is found
307
+ * by name instead.
308
+ */
309
+ buildIdFromAppAutomateLink(url: URL): Promise<string | undefined>;
310
+ private buildOfSdkSession;
311
+ /** The first SDK session of an App Automate build; a native build lists none. */
312
+ private anySdkSession;
313
+ /**
314
+ * A native build's details name its project and when it started; App Accessibility lists
315
+ * the run under the same project, created as it started, and named as the App Automate
316
+ * build list names it ("Build #N: app vX"). The start finds it among the project's newest
317
+ * builds; the name, read from the account's build list, tells runs that started together
318
+ * apart, and finds a run older than those.
319
+ */
320
+ private buildOfNativeBuild;
321
+ /** A native build's project and start, from whichever framework API knows the build. */
322
+ private nativeBuild;
323
+ /** The project's builds created within moments of a run's start, newest first. */
324
+ private buildsStartedNear;
325
+ /** The build's name in the account's App Automate build list, walked newest first. */
326
+ private appAutomateBuildName;
327
+ /** The App Accessibility project of that exact name, if any. */
328
+ private projectId;
329
+ /**
330
+ * The projects whose name contains `name`, as the API searches it. A failed search is an
331
+ * error, not an empty list, or a correct name would read as one that matches nothing.
332
+ */
333
+ private projectsNamed;
334
+ /**
335
+ * A listing's page. The API answers an empty list with 404 ("No builds found") for
336
+ * access-key callers, which is not an error here; any other failure is, a 404 from a
337
+ * wrong route or a missing permission included.
338
+ */
339
+ private listing;
340
+ /** The newest projects, as many as asked for. */
341
+ listAppProjects(limit: number): Promise<{
342
+ projects: AppProjectRow[];
343
+ total: number;
344
+ }>;
345
+ /**
346
+ * A project's newest builds, by exact project name, optionally filtered by build name.
347
+ * A project name that matches none exactly names the near matches, so the agent can
348
+ * pick rather than guess.
349
+ */
350
+ listAppBuilds(projectName: string, buildName: string | undefined, limit: number): Promise<{
351
+ project: {
352
+ id: number;
353
+ name: string;
354
+ };
355
+ total: number;
356
+ builds: AppBuildRow[];
357
+ }>;
358
+ /** The newest manual reports, optionally filtered by name. */
359
+ listAppManualReports(name: string | undefined, limit: number): Promise<{
360
+ total: number;
361
+ reports: AppManualReportRow[];
362
+ }>;
363
+ /** A manual report's details, or undefined when the API does not know the id. */
364
+ manualReport(reportId: string): Promise<any | undefined>;
365
+ /**
366
+ * A manual report's screens as the dashboard reads them, duplicates left out and each
367
+ * issue with its element, fix and measurements; undefined while that route answers an
368
+ * access key with a login redirect, as it does until it takes one.
369
+ */
370
+ private dashboardScreens;
371
+ /** Every occurrence the Manual Reports API lists, and the device the report ran on. */
372
+ private manualApiScreens;
373
+ /**
374
+ * A manual report's issues, most severe first: from the dashboard's own screens when the
375
+ * route takes the access key, so the count is the dashboard's and each issue names its
376
+ * element; else every occurrence the Manual Reports API lists, which marks neither
377
+ * duplicates nor elements, with the dashboard's count stated next to it.
378
+ */
379
+ appReportIssues(reportId: string, cursor?: number, maxCharacterLength?: number): Promise<AppManualReport>;
380
+ /**
381
+ * The id of the project's build that `pick` accepts, newest first, within the first
382
+ * pages; `buildName` narrows the list to builds named like it, when the name is known
383
+ * to be the build's own.
384
+ */
385
+ private findBuild;
386
+ /**
387
+ * The project's builds a page at a time, newest first, within the first pages; `more`
388
+ * says whether the list goes on past the page. A page that fails is an error, not the end
389
+ * of the list, or a build with earlier ones would read as its project's first.
390
+ */
391
+ private projectBuilds;
392
+ /**
393
+ * The build before this one in its project: the newest earlier build of the same name,
394
+ * as an SDK suite keeps its name from run to run, or else the build just before it, as
395
+ * each native (Espresso, XCUITest) run is named apart. None for a project's first build.
396
+ */
397
+ previousBuild(buildId: string): Promise<AppBuildRef | undefined>;
398
+ /** The build's page on the App Accessibility dashboard, when its project can be found. */
399
+ private dashboardLink;
400
+ /**
401
+ * Every scanned screen of the build, up to the page limit, how many issues the dashboard
402
+ * hides, and whether more screens lie past the limit.
403
+ */
404
+ private snapshots;
405
+ private requireBuildMeta;
406
+ /** The build's details and scanned screens; a build with no scans has none to read. */
407
+ private readBuild;
408
+ /** Every issue of the build at once, to compare it with another. */
409
+ buildIssues(buildId: string): Promise<AppBuildIssues>;
410
+ report(buildId: string, cursor?: number, maxCharacterLength?: number): Promise<AppBuildReport>;
411
+ }
412
+ export {};