@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.
- package/dist/server-factory.js +1 -6
- package/dist/tools/accessibility.js +69 -680
- package/dist/tools/accessiblity-utils/accessibility-rag.d.ts +12 -0
- package/dist/tools/accessiblity-utils/accessibility-rag.js +59 -0
- package/dist/tools/accessiblity-utils/report-fetcher.d.ts +7 -116
- package/dist/tools/accessiblity-utils/report-fetcher.js +29 -268
- package/dist/tools/accessiblity-utils/report-parser.d.ts +1 -41
- package/dist/tools/accessiblity-utils/report-parser.js +43 -142
- package/dist/tools/accessiblity-utils/scanner.d.ts +1 -15
- package/dist/tools/accessiblity-utils/scanner.js +4 -3
- package/dist/tools/appautomate-utils/appium-sdk/config-generator.d.ts +0 -2
- package/dist/tools/appautomate-utils/appium-sdk/config-generator.js +5 -15
- package/dist/tools/appautomate-utils/appium-sdk/constants.d.ts +1 -2
- package/dist/tools/appautomate-utils/appium-sdk/constants.js +1 -6
- package/dist/tools/appautomate-utils/appium-sdk/handler.js +1 -12
- package/dist/tools/appautomate-utils/appium-sdk/instructions.d.ts +1 -3
- package/dist/tools/appautomate-utils/appium-sdk/instructions.js +2 -2
- package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.d.ts +1 -3
- package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.js +6 -19
- package/dist/tools/appautomate-utils/native-execution/appautomate.d.ts +2 -7
- package/dist/tools/appautomate-utils/native-execution/appautomate.js +12 -15
- package/dist/tools/appautomate-utils/native-execution/constants.d.ts +1 -2
- package/dist/tools/appautomate-utils/native-execution/constants.js +1 -6
- package/dist/tools/appautomate.js +16 -29
- package/dist/tools/testmanagement-utils/create-testrun.d.ts +1 -1
- package/dist/tools/testmanagement-utils/update-testrun.d.ts +1 -1
- package/dist/tools/tool-handoff.d.ts +2 -3
- package/dist/tools/tool-handoff.js +2 -3
- package/package.json +1 -1
- package/dist/lib/accessibility-routing.d.ts +0 -6
- package/dist/lib/accessibility-routing.js +0 -6
- package/dist/tools/accessiblity-utils/app-report-fetcher.d.ts +0 -412
- package/dist/tools/accessiblity-utils/app-report-fetcher.js +0 -926
- package/dist/tools/accessiblity-utils/paginate.d.ts +0 -27
- package/dist/tools/accessiblity-utils/paginate.js +0 -50
- package/dist/tools/appautomate-utils/appium-sdk/languages/accessibility.d.ts +0 -4
- 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
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
|
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:
|
|
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.
|
|
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
|
|
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
|
|
127
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
|
66
|
-
* the
|
|
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
|
|
75
|
-
* the
|
|
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 +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 {};
|