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

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 (37) hide show
  1. package/dist/server-factory.js +1 -6
  2. package/dist/tools/accessibility.js +69 -680
  3. package/dist/tools/accessiblity-utils/accessibility-rag.d.ts +12 -0
  4. package/dist/tools/accessiblity-utils/accessibility-rag.js +59 -0
  5. package/dist/tools/accessiblity-utils/report-fetcher.d.ts +7 -116
  6. package/dist/tools/accessiblity-utils/report-fetcher.js +29 -268
  7. package/dist/tools/accessiblity-utils/report-parser.d.ts +1 -41
  8. package/dist/tools/accessiblity-utils/report-parser.js +43 -142
  9. package/dist/tools/accessiblity-utils/scanner.d.ts +1 -15
  10. package/dist/tools/accessiblity-utils/scanner.js +4 -3
  11. package/dist/tools/appautomate-utils/appium-sdk/config-generator.d.ts +0 -2
  12. package/dist/tools/appautomate-utils/appium-sdk/config-generator.js +5 -15
  13. package/dist/tools/appautomate-utils/appium-sdk/constants.d.ts +1 -2
  14. package/dist/tools/appautomate-utils/appium-sdk/constants.js +1 -6
  15. package/dist/tools/appautomate-utils/appium-sdk/handler.js +1 -12
  16. package/dist/tools/appautomate-utils/appium-sdk/instructions.d.ts +1 -3
  17. package/dist/tools/appautomate-utils/appium-sdk/instructions.js +2 -2
  18. package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.d.ts +1 -3
  19. package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.js +6 -19
  20. package/dist/tools/appautomate-utils/native-execution/appautomate.d.ts +2 -7
  21. package/dist/tools/appautomate-utils/native-execution/appautomate.js +12 -15
  22. package/dist/tools/appautomate-utils/native-execution/constants.d.ts +1 -2
  23. package/dist/tools/appautomate-utils/native-execution/constants.js +1 -6
  24. package/dist/tools/appautomate.js +16 -29
  25. package/dist/tools/testmanagement-utils/create-testrun.d.ts +1 -1
  26. package/dist/tools/testmanagement-utils/update-testrun.d.ts +1 -1
  27. package/dist/tools/tool-handoff.d.ts +2 -3
  28. package/dist/tools/tool-handoff.js +2 -3
  29. package/package.json +1 -1
  30. package/dist/lib/accessibility-routing.d.ts +0 -6
  31. package/dist/lib/accessibility-routing.js +0 -6
  32. package/dist/tools/accessiblity-utils/app-report-fetcher.d.ts +0 -412
  33. package/dist/tools/accessiblity-utils/app-report-fetcher.js +0 -926
  34. package/dist/tools/accessiblity-utils/paginate.d.ts +0 -27
  35. package/dist/tools/accessiblity-utils/paginate.js +0 -50
  36. package/dist/tools/appautomate-utils/appium-sdk/languages/accessibility.d.ts +0 -4
  37. package/dist/tools/appautomate-utils/appium-sdk/languages/accessibility.js +0 -47
@@ -138,17 +138,8 @@ export async function uploadXcuiApp(appPath, config) {
138
138
  export async function uploadXcuiTestSuite(testSuitePath, config) {
139
139
  return uploadFileToBrowserStack(testSuitePath, "https://api-cloud.browserstack.com/app-automate/xcuitest/v2/test-suite", "test_suite_url", config, { allowedExtensions: [".zip"] });
140
140
  }
141
- function buildRequestBody(app_url, test_suite_url, devices, project, options) {
142
- return {
143
- app: app_url,
144
- testSuite: test_suite_url,
145
- devices,
146
- project,
147
- ...(options.accessibility ? { accessibility: true } : {}),
148
- };
149
- }
150
141
  // Triggers an Espresso test run on BrowserStack and returns the build_id
151
- export async function triggerEspressoBuild(app_url, test_suite_url, devices, project, config, options = {}) {
142
+ export async function triggerEspressoBuild(app_url, test_suite_url, devices, project, config) {
152
143
  const authHeader = "Basic " + Buffer.from(getBrowserStackAuth(config)).toString("base64");
153
144
  const response = await apiClient.post({
154
145
  url: "https://api-cloud.browserstack.com/app-automate/espresso/v2/build",
@@ -157,9 +148,10 @@ export async function triggerEspressoBuild(app_url, test_suite_url, devices, pro
157
148
  "Content-Type": "application/json",
158
149
  },
159
150
  body: {
160
- ...buildRequestBody(app_url, test_suite_url, devices, project, options),
161
- // An Espresso build's App Accessibility report is generated through Test Observability.
162
- ...(options.accessibility ? { testObservability: true } : {}),
151
+ app: app_url,
152
+ testSuite: test_suite_url,
153
+ devices,
154
+ project,
163
155
  },
164
156
  });
165
157
  if (response.data.build_id) {
@@ -168,7 +160,7 @@ export async function triggerEspressoBuild(app_url, test_suite_url, devices, pro
168
160
  throw new Error(`Failed to trigger Espresso build: ${JSON.stringify(response.data)}`);
169
161
  }
170
162
  // Triggers an XCUITest run on BrowserStack and returns the build_id
171
- export async function triggerXcuiBuild(app_url, test_suite_url, devices, project, config, options = {}) {
163
+ export async function triggerXcuiBuild(app_url, test_suite_url, devices, project, config) {
172
164
  const auth = {
173
165
  username: config["browserstack-username"],
174
166
  password: config["browserstack-access-key"],
@@ -180,7 +172,12 @@ export async function triggerXcuiBuild(app_url, test_suite_url, devices, project
180
172
  Buffer.from(`${auth.username}:${auth.password}`).toString("base64"),
181
173
  "Content-Type": "application/json",
182
174
  },
183
- body: buildRequestBody(app_url, test_suite_url, devices, project, options),
175
+ body: {
176
+ app: app_url,
177
+ testSuite: test_suite_url,
178
+ devices,
179
+ project,
180
+ },
184
181
  });
185
182
  if (response.data.build_id) {
186
183
  return response.data.build_id;
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { AppTestPlatform } from "./types.js";
3
- export declare const RUN_APP_AUTOMATE_DESCRIPTION = "Execute pre-built native mobile test suites (Espresso for Android, XCUITest for iOS) by direct upload to BrowserStack. ONLY for compiled .apk/.ipa test files. This is NOT for SDK integration or Appium tests. For Appium-based testing with SDK setup, use 'setupBrowserStackAppAutomateTests' instead. Set accessibility: true to also run App Accessibility (WCAG) checks during the tests; the issues are then read with fetchAccessibilityIssues.";
3
+ export declare const RUN_APP_AUTOMATE_DESCRIPTION = "Execute pre-built native mobile test suites (Espresso for Android, XCUITest for iOS) by direct upload to BrowserStack. ONLY for compiled .apk/.ipa test files. This is NOT for SDK integration or Appium tests. For Appium-based testing with SDK setup, use 'setupBrowserStackAppAutomateTests' instead.";
4
4
  export declare const MobileDeviceSchema: z.ZodObject<{
5
5
  platform: z.ZodEnum<{
6
6
  android: "android";
@@ -22,5 +22,4 @@ export declare const RUN_APP_AUTOMATE_SCHEMA: {
22
22
  }, z.core.$strip>>>;
23
23
  project: z.ZodDefault<z.ZodOptional<z.ZodString>>;
24
24
  detectedAutomationFramework: z.ZodEnum<typeof AppTestPlatform>;
25
- accessibility: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
26
25
  };
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { AppTestPlatform } from "./types.js";
3
- export const RUN_APP_AUTOMATE_DESCRIPTION = `Execute pre-built native mobile test suites (Espresso for Android, XCUITest for iOS) by direct upload to BrowserStack. ONLY for compiled .apk/.ipa test files. This is NOT for SDK integration or Appium tests. For Appium-based testing with SDK setup, use 'setupBrowserStackAppAutomateTests' instead. Set accessibility: true to also run App Accessibility (WCAG) checks during the tests; the issues are then read with fetchAccessibilityIssues.`;
3
+ export const RUN_APP_AUTOMATE_DESCRIPTION = `Execute pre-built native mobile test suites (Espresso for Android, XCUITest for iOS) by direct upload to BrowserStack. ONLY for compiled .apk/.ipa test files. This is NOT for SDK integration or Appium tests. For Appium-based testing with SDK setup, use 'setupBrowserStackAppAutomateTests' instead.`;
4
4
  export const MobileDeviceSchema = z.object({
5
5
  platform: z
6
6
  .enum(["android", "ios"])
@@ -46,9 +46,4 @@ export const RUN_APP_AUTOMATE_SCHEMA = {
46
46
  detectedAutomationFramework: z
47
47
  .nativeEnum(AppTestPlatform)
48
48
  .describe("The automation framework used in the project, such as 'espresso' (Android) or 'xcuitest' (iOS)."),
49
- accessibility: z
50
- .boolean()
51
- .optional()
52
- .default(false)
53
- .describe("App Accessibility checks on screens the tests touch (Android 11+, iOS 14+); suite must be built with BrowserStack's SDK."),
54
49
  };
@@ -96,26 +96,8 @@ async function takeAppScreenshot(args) {
96
96
  }
97
97
  }
98
98
  }
99
- /**
100
- * What a native suite needs for App Accessibility to scan it. The build request's flag
101
- * turns the checks on, but only a suite built with BrowserStack's instrumentation records
102
- * scans; without it the run finishes with none, and nothing says why.
103
- */
104
- const NATIVE_ACCESSIBILITY_SETUP = {
105
- Espresso: "The test suite must be built with BrowserStack's Gradle plugin and SDK, or the run records no scans: classpath 'com.browserstack:gradle-tool:latest.release' in the root build.gradle, id 'com.browserstack.gradle-tool' in the app's plugins, and androidTestImplementation 'com.browserstack:browserstack-java-sdk:latest.release' (1.31.0 or newer). The app also needs internet permission.",
106
- XCUITest: "The UI test target must embed and initialize the BrowserStack Swift SDK (BrowserstackSwiftSDK.xcframework, or the Swift package), or the run records no scans: set NSPrincipalClass to BrowserstackSwiftSDK.BrowserstackSwiftSDK in the test target's Info.plist, or call BrowserstackSwiftSDK.init() in the test class's init(). Swift 5.4+ and iOS 14+.",
107
- };
108
- /** The run's build and, with accessibility on, where its issues are read once it finishes. */
109
- function runStartedMessage(framework, buildId, accessibility) {
110
- const link = `https://app-automate.browserstack.com/builds/${buildId}`;
111
- const a11y = accessibility
112
- ? `\n\n♿ App Accessibility checks are on. ${NATIVE_ACCESSIBILITY_SETUP[framework] ?? ""}\nWhen the build finishes (typically 10–20 minutes), read the issues with fetchAccessibilityIssues, reportUrl: ${link} — it maps the build to its accessibility report and waits while the report is still processing.`
113
- : "";
114
- return `✅ ${framework} run started successfully!\n\n🔧 Build ID: ${buildId}\n🔗 View your build: ${link}${a11y}`;
115
- }
116
99
  //Runs AppAutomate tests on BrowserStack by uploading app and test suite, then triggering a test run.
117
100
  async function runAppTestsOnBrowserStack(args, config) {
118
- const accessibility = args.accessibility === true;
119
101
  // Validate that either paths or URLs are provided for both app and test suite
120
102
  if (!args.browserstackAppUrl && !args.appPath) {
121
103
  throw new Error("appPath is required when browserstackAppUrl is not provided");
@@ -123,13 +105,8 @@ async function runAppTestsOnBrowserStack(args, config) {
123
105
  if (!args.browserstackTestSuiteUrl && !args.testSuitePath) {
124
106
  throw new Error("testSuitePath is required when browserstackTestSuiteUrl is not provided");
125
107
  }
126
- // Validate devices against real BrowserStack device data, and ask for them as App Automate
127
- // lists them: a version given as "14" is "14.0" there, and a run asking for "-14" waits for
128
- // a device that never matches.
129
- const validated = await validateAppAutomateDevices(args.devices);
130
- const deviceStrings = args.devices.length > 0
131
- ? validated.map((device) => `${device.deviceName}-${device.osVersion}`)
132
- : [];
108
+ // Validate devices against real BrowserStack device data
109
+ await validateAppAutomateDevices(args.devices);
133
110
  switch (args.detectedAutomationFramework) {
134
111
  case AppTestPlatform.ESPRESSO: {
135
112
  try {
@@ -151,12 +128,17 @@ async function runAppTestsOnBrowserStack(args, config) {
151
128
  test_suite_url = await uploadEspressoTestSuite(args.testSuitePath, config);
152
129
  logger.info(`Test suite uploaded. URL: ${test_suite_url}`);
153
130
  }
154
- const build_id = await triggerEspressoBuild(app_url, test_suite_url, deviceStrings, args.project, config, { accessibility });
131
+ // Convert array format to string format for Espresso
132
+ const deviceStrings = args.devices.map((device) => {
133
+ const [, deviceName, osVersion] = device;
134
+ return `${deviceName}-${osVersion}`;
135
+ });
136
+ const build_id = await triggerEspressoBuild(app_url, test_suite_url, deviceStrings, args.project, config);
155
137
  return {
156
138
  content: [
157
139
  {
158
140
  type: "text",
159
- text: runStartedMessage("Espresso", build_id, accessibility),
141
+ text: `✅ Espresso run started successfully!\n\n🔧 Build ID: ${build_id}\n🔗 View your build: https://app-automate.browserstack.com/builds/${build_id}`,
160
142
  },
161
143
  ],
162
144
  };
@@ -186,12 +168,17 @@ async function runAppTestsOnBrowserStack(args, config) {
186
168
  test_suite_url = await uploadXcuiTestSuite(args.testSuitePath, config);
187
169
  logger.info(`Test suite uploaded. URL: ${test_suite_url}`);
188
170
  }
189
- const build_id = await triggerXcuiBuild(app_url, test_suite_url, deviceStrings, args.project, config, { accessibility });
171
+ // Convert array format to string format for XCUITest
172
+ const deviceStrings = args.devices.map((device) => {
173
+ const [, deviceName, osVersion] = device;
174
+ return `${deviceName}-${osVersion}`;
175
+ });
176
+ const build_id = await triggerXcuiBuild(app_url, test_suite_url, deviceStrings, args.project, config);
190
177
  return {
191
178
  content: [
192
179
  {
193
180
  type: "text",
194
- text: runStartedMessage("XCUITest", build_id, accessibility),
181
+ text: `✅ XCUITest run started successfully!\n\n🔧 Build ID: ${build_id}\n🔗 View your build: https://app-automate.browserstack.com/builds/${build_id}`,
195
182
  },
196
183
  ],
197
184
  };
@@ -11,8 +11,8 @@ export declare const CreateTestRunSchema: z.ZodObject<{
11
11
  description: z.ZodOptional<z.ZodString>;
12
12
  run_state: z.ZodOptional<z.ZodEnum<{
13
13
  done: "done";
14
- in_progress: "in_progress";
15
14
  new_run: "new_run";
15
+ in_progress: "in_progress";
16
16
  under_review: "under_review";
17
17
  rejected: "rejected";
18
18
  closed: "closed";
@@ -11,8 +11,8 @@ export declare const UpdateTestRunSchema: z.ZodObject<{
11
11
  name: z.ZodOptional<z.ZodString>;
12
12
  run_state: z.ZodOptional<z.ZodEnum<{
13
13
  done: "done";
14
- in_progress: "in_progress";
15
14
  new_run: "new_run";
15
+ in_progress: "in_progress";
16
16
  under_review: "under_review";
17
17
  rejected: "rejected";
18
18
  closed: "closed";
@@ -62,9 +62,8 @@ export declare const NEEDS_BUILD_ID: string;
62
62
  */
63
63
  export declare const NEEDS_SESSION_ID: string;
64
64
  /**
65
- * A scan run's ids come from startAccessibilityScan; a build's id is printed by the SDK at
66
- * the end of its run. Nothing here lists builds or reports, but the tool takes a report's
67
- * dashboard link, or an Automate link, and looks the ids up itself.
65
+ * A scan run's ids come from startAccessibilityScan. Nothing here lists builds or reports,
66
+ * but the tool takes a report's dashboard link and looks the ids up itself.
68
67
  */
69
68
  export declare const NEEDS_A11Y_SCAN_ID = " Ids: startAccessibilityScan or a dashboard link; nothing here lists reports.";
70
69
  /** Auth-config ids are not listable by any tool here. */
@@ -71,9 +71,8 @@ export const NEEDS_BUILD_ID = needsIdFrom("a BrowserStack build id", "getBuildId
71
71
  export const NEEDS_SESSION_ID = " Requires a session id. listSessions lists them for a build; if you do not have the " +
72
72
  "build either, getBuildId or listBuildId resolves one from a project and build name.";
73
73
  /**
74
- * A scan run's ids come from startAccessibilityScan; a build's id is printed by the SDK at
75
- * the end of its run. Nothing here lists builds or reports, but the tool takes a report's
76
- * dashboard link, or an Automate link, and looks the ids up itself.
74
+ * A scan run's ids come from startAccessibilityScan. Nothing here lists builds or reports,
75
+ * but the tool takes a report's dashboard link and looks the ids up itself.
77
76
  */
78
77
  export const NEEDS_A11Y_SCAN_ID = " Ids: startAccessibilityScan or a dashboard link; nothing here lists reports.";
79
78
  /** Auth-config ids are not listable by any tool here. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@browserstack/mcp-server",
3
- "version": "2.2.6-beta.2",
3
+ "version": "2.2.6",
4
4
  "description": "BrowserStack's Official MCP Server",
5
5
  "mcpName": "io.github.browserstack/mcp-server",
6
6
  "main": "dist/index.js",
@@ -1,6 +0,0 @@
1
- /**
2
- * Which product checks what for accessibility, said once to every client, since the tools
3
- * alone do not tell an agent that a web page and a mobile app are scanned differently. An
4
- * app with no tests is a path too: the agent writes them, in the user's choice of framework.
5
- */
6
- export declare const ACCESSIBILITY_ROUTING_INSTRUCTION = "Accessibility checks: a web page or site \u2192 startAccessibilityScan (Website Scanner); a multi-step web flow \u2192 Automate tests with `accessibility: true` in browserstack.yml (setupBrowserStackAutomateTests); a mobile app \u2192 its tests on App Automate with accessibility on (setupBrowserStackAppAutomateTests for Appium, runAppTestsOnBrowserStack for Espresso/XCUITest). An app with no tests yet: offer to write them, in the framework the user picks (Appium in any language the SDK supports, Espresso or XCUITest); if they leave it to you, pick one and say which. Then read the issues with fetchAccessibilityIssues.";
@@ -1,6 +0,0 @@
1
- /**
2
- * Which product checks what for accessibility, said once to every client, since the tools
3
- * alone do not tell an agent that a web page and a mobile app are scanned differently. An
4
- * app with no tests is a path too: the agent writes them, in the user's choice of framework.
5
- */
6
- export const ACCESSIBILITY_ROUTING_INSTRUCTION = "Accessibility checks: a web page or site → startAccessibilityScan (Website Scanner); a multi-step web flow → Automate tests with `accessibility: true` in browserstack.yml (setupBrowserStackAutomateTests); a mobile app → its tests on App Automate with accessibility on (setupBrowserStackAppAutomateTests for Appium, runAppTestsOnBrowserStack for Espresso/XCUITest). An app with no tests yet: offer to write them, in the framework the user picks (Appium in any language the SDK supports, Espresso or XCUITest); if they leave it to you, pick one and say which. Then read the issues with fetchAccessibilityIssues.";
@@ -1,412 +0,0 @@
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 {};