@diegosouzacdv/jev-browser-mcp 0.6.1 → 0.6.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.
- package/README.md +126 -55
- package/config/ui-testing.json +10 -2
- package/docs/jev-browser-mcp.md +126 -55
- package/mcp_servers/jev-browser-npm/src/accessibility.mjs +18 -9
- package/mcp_servers/jev-browser-npm/src/config.mjs +28 -7
- package/mcp_servers/jev-browser-npm/src/flow.mjs +736 -314
- package/mcp_servers/jev-browser-npm/src/server.mjs +82 -28
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ export const ACCESSIBILITY_STANDARDS = Object.freeze({
|
|
|
4
4
|
wcag2aa: Object.freeze(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]),
|
|
5
5
|
});
|
|
6
6
|
|
|
7
|
-
export async function runAccessibilityAudit(page, standard, settings) {
|
|
7
|
+
export async function runAccessibilityAudit(page, standard, settings, { scope, failOnImpact } = {}) {
|
|
8
8
|
const tags = ACCESSIBILITY_STANDARDS[standard];
|
|
9
9
|
if (!tags) throw new JevBrowserError("audit_accessibility standard must be wcag2aa");
|
|
10
10
|
|
|
@@ -15,17 +15,26 @@ export async function runAccessibilityAudit(page, standard, settings) {
|
|
|
15
15
|
throw new JevBrowserError("accessibility auditing requires the installed @axe-core/playwright dependency");
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
let results;
|
|
19
|
-
try {
|
|
20
|
-
|
|
18
|
+
let results;
|
|
19
|
+
try {
|
|
20
|
+
let audit = new AxeBuilder({ page }).withTags([...tags]);
|
|
21
|
+
if (scope) audit = audit.include(scope);
|
|
22
|
+
results = await audit.analyze();
|
|
21
23
|
} catch {
|
|
22
24
|
throw new JevBrowserError("axe-core could not complete the accessibility audit");
|
|
23
25
|
}
|
|
24
|
-
const violations = Array.isArray(results?.violations) ? results.violations : [];
|
|
25
|
-
const incomplete = Array.isArray(results?.incomplete) ? results.incomplete : [];
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
const violations = Array.isArray(results?.violations) ? results.violations : [];
|
|
27
|
+
const incomplete = Array.isArray(results?.incomplete) ? results.incomplete : [];
|
|
28
|
+
const impactOrder = ["minor", "moderate", "serious", "critical"];
|
|
29
|
+
const threshold = impactOrder.indexOf(failOnImpact || settings.browser.accessibilityFailOnImpactDefault);
|
|
30
|
+
if (threshold < 0) throw new JevBrowserError("accessibility fail_on_impact must be minor, moderate, serious, or critical");
|
|
31
|
+
const blockingViolations = violations.filter((violation) => impactOrder.indexOf(violation.impact) >= threshold);
|
|
32
|
+
return {
|
|
33
|
+
standard,
|
|
34
|
+
...(scope ? { scope } : {}),
|
|
35
|
+
fail_on_impact: impactOrder[threshold],
|
|
36
|
+
violations_count: violations.length,
|
|
37
|
+
blocking_violations_count: blockingViolations.length,
|
|
29
38
|
violations_truncated: violations.length > settings.jev.maxAccessibilityViolations,
|
|
30
39
|
violations: violations.slice(0, settings.jev.maxAccessibilityViolations).map((violation) => ({
|
|
31
40
|
id: String(violation.id || "unknown").slice(0, 100),
|
|
@@ -32,8 +32,15 @@ const CONFIG_KEYS = {
|
|
|
32
32
|
"snapshot_include_hidden_default",
|
|
33
33
|
"visibility_poll_interval_ms_default",
|
|
34
34
|
"capture_network_error_bodies_default",
|
|
35
|
-
"max_network_error_body_bytes",
|
|
36
|
-
"max_network_error_message_chars",
|
|
35
|
+
"max_network_error_body_bytes",
|
|
36
|
+
"max_network_error_message_chars",
|
|
37
|
+
"max_network_history_events",
|
|
38
|
+
"max_tool_response_bytes",
|
|
39
|
+
"max_viewport_width",
|
|
40
|
+
"max_viewport_height",
|
|
41
|
+
"accessibility_fail_on_impact_default",
|
|
42
|
+
"record_video_width",
|
|
43
|
+
"record_video_height",
|
|
37
44
|
"max_upload_files",
|
|
38
45
|
"max_upload_path_chars",
|
|
39
46
|
"max_upload_file_bytes",
|
|
@@ -48,7 +55,8 @@ const CONFIG_KEYS = {
|
|
|
48
55
|
"max_frame_snapshots",
|
|
49
56
|
"fast_path_single_plan_default",
|
|
50
57
|
"screenshot_on_failure_default",
|
|
51
|
-
"trace_on_failure_default",
|
|
58
|
+
"trace_on_failure_default",
|
|
59
|
+
"trace_on_success_default",
|
|
52
60
|
"capture_console_errors_default",
|
|
53
61
|
"capture_network_errors_default",
|
|
54
62
|
"block_trackers_default",
|
|
@@ -259,9 +267,12 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
259
267
|
browserOptions.login_text_default,
|
|
260
268
|
"jev_browser_mcp.browser.login_text_default",
|
|
261
269
|
);
|
|
262
|
-
if (!new Set(["none", "diff", "full"]).has(browserOptions.return_snapshot_default)) {
|
|
270
|
+
if (!new Set(["none", "diff", "full"]).has(browserOptions.return_snapshot_default)) {
|
|
263
271
|
throw new JevBrowserError("config/ui-testing.json return_snapshot_default must be none, diff, or full");
|
|
264
|
-
}
|
|
272
|
+
}
|
|
273
|
+
if (!new Set(["minor", "moderate", "serious", "critical"]).has(browserOptions.accessibility_fail_on_impact_default)) {
|
|
274
|
+
throw new JevBrowserError("config/ui-testing.json accessibility_fail_on_impact_default must be minor, moderate, serious, or critical");
|
|
275
|
+
}
|
|
265
276
|
const maxReadyTimeoutSeconds = positiveNumber(browserOptions.max_ready_timeout_seconds, "jev_browser_mcp.browser.max_ready_timeout_seconds");
|
|
266
277
|
const readyTimeoutSecondsDefault = positiveNumber(browserOptions.ready_timeout_seconds_default, "jev_browser_mcp.browser.ready_timeout_seconds_default");
|
|
267
278
|
const maxReadyStableMs = positiveNumber(browserOptions.max_ready_stable_ms, "jev_browser_mcp.browser.max_ready_stable_ms", true);
|
|
@@ -297,7 +308,16 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
297
308
|
keyDelayMs: positiveNumber(browserOptions.key_delay_ms_default, "jev_browser_mcp.browser.key_delay_ms_default", true),
|
|
298
309
|
visibilityPollMs: positiveNumber(browserOptions.visibility_poll_interval_ms_default, "jev_browser_mcp.browser.visibility_poll_interval_ms_default", true),
|
|
299
310
|
maxNetworkErrorBodyBytes: positiveNumber(browserOptions.max_network_error_body_bytes, "jev_browser_mcp.browser.max_network_error_body_bytes", true),
|
|
300
|
-
maxNetworkErrorMessageChars: positiveNumber(browserOptions.max_network_error_message_chars, "jev_browser_mcp.browser.max_network_error_message_chars", true),
|
|
311
|
+
maxNetworkErrorMessageChars: positiveNumber(browserOptions.max_network_error_message_chars, "jev_browser_mcp.browser.max_network_error_message_chars", true),
|
|
312
|
+
maxNetworkHistoryEvents: positiveNumber(browserOptions.max_network_history_events, "jev_browser_mcp.browser.max_network_history_events", true),
|
|
313
|
+
maxToolResponseBytes: positiveNumber(browserOptions.max_tool_response_bytes, "jev_browser_mcp.browser.max_tool_response_bytes", true),
|
|
314
|
+
maxViewportWidth: positiveNumber(browserOptions.max_viewport_width, "jev_browser_mcp.browser.max_viewport_width", true),
|
|
315
|
+
maxViewportHeight: positiveNumber(browserOptions.max_viewport_height, "jev_browser_mcp.browser.max_viewport_height", true),
|
|
316
|
+
accessibilityFailOnImpactDefault: browserOptions.accessibility_fail_on_impact_default,
|
|
317
|
+
recordVideoSize: Object.freeze({
|
|
318
|
+
width: positiveNumber(browserOptions.record_video_width, "jev_browser_mcp.browser.record_video_width", true),
|
|
319
|
+
height: positiveNumber(browserOptions.record_video_height, "jev_browser_mcp.browser.record_video_height", true),
|
|
320
|
+
}),
|
|
301
321
|
maxUploadFiles: positiveNumber(browserOptions.max_upload_files, "jev_browser_mcp.browser.max_upload_files", true),
|
|
302
322
|
maxUploadPathChars: positiveNumber(browserOptions.max_upload_path_chars, "jev_browser_mcp.browser.max_upload_path_chars", true),
|
|
303
323
|
maxUploadFileBytes: positiveNumber(browserOptions.max_upload_file_bytes, "jev_browser_mcp.browser.max_upload_file_bytes", true),
|
|
@@ -312,7 +332,8 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
312
332
|
defaults: Object.freeze({
|
|
313
333
|
fastPath: booleanValue(browserOptions.fast_path_single_plan_default, "jev_browser_mcp.browser.fast_path_single_plan_default"),
|
|
314
334
|
screenshotOnFailure: booleanValue(browserOptions.screenshot_on_failure_default, "jev_browser_mcp.browser.screenshot_on_failure_default"),
|
|
315
|
-
traceOnFailure: booleanValue(browserOptions.trace_on_failure_default, "jev_browser_mcp.browser.trace_on_failure_default"),
|
|
335
|
+
traceOnFailure: booleanValue(browserOptions.trace_on_failure_default, "jev_browser_mcp.browser.trace_on_failure_default"),
|
|
336
|
+
traceOnSuccess: booleanValue(browserOptions.trace_on_success_default, "jev_browser_mcp.browser.trace_on_success_default"),
|
|
316
337
|
captureConsoleErrors: booleanValue(browserOptions.capture_console_errors_default, "jev_browser_mcp.browser.capture_console_errors_default"),
|
|
317
338
|
captureNetworkErrors: booleanValue(browserOptions.capture_network_errors_default, "jev_browser_mcp.browser.capture_network_errors_default"),
|
|
318
339
|
captureNetworkErrorBodies: booleanValue(browserOptions.capture_network_error_bodies_default, "jev_browser_mcp.browser.capture_network_error_bodies_default"),
|