@shadowcoderr/context-graph 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +185 -0
- package/dist/analyzers/a11y-extractor.d.ts +15 -0
- package/dist/analyzers/a11y-extractor.d.ts.map +1 -0
- package/dist/analyzers/a11y-extractor.js +148 -0
- package/dist/analyzers/a11y-extractor.js.map +1 -0
- package/dist/analyzers/dom-analyzer.d.ts +20 -0
- package/dist/analyzers/dom-analyzer.d.ts.map +1 -0
- package/dist/analyzers/dom-analyzer.js +126 -0
- package/dist/analyzers/dom-analyzer.js.map +1 -0
- package/dist/analyzers/locator-generator.d.ts +13 -0
- package/dist/analyzers/locator-generator.d.ts.map +1 -0
- package/dist/analyzers/locator-generator.js +381 -0
- package/dist/analyzers/locator-generator.js.map +1 -0
- package/dist/analyzers/network-logger.d.ts +15 -0
- package/dist/analyzers/network-logger.d.ts.map +1 -0
- package/dist/analyzers/network-logger.js +71 -0
- package/dist/analyzers/network-logger.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +155 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/defaults.d.ts +3 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +54 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/loader.d.ts +3 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +75 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +168 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +104 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/core/browser-adapter.d.ts +24 -0
- package/dist/core/browser-adapter.d.ts.map +1 -0
- package/dist/core/browser-adapter.js +208 -0
- package/dist/core/browser-adapter.js.map +1 -0
- package/dist/core/capture-engine.d.ts +52 -0
- package/dist/core/capture-engine.d.ts.map +1 -0
- package/dist/core/capture-engine.js +593 -0
- package/dist/core/capture-engine.js.map +1 -0
- package/dist/core/runtime.d.ts +38 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +648 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/prompts/init-prompt.d.ts +12 -0
- package/dist/prompts/init-prompt.d.ts.map +1 -0
- package/dist/prompts/init-prompt.js +128 -0
- package/dist/prompts/init-prompt.js.map +1 -0
- package/dist/registry/components-registry.d.ts +97 -0
- package/dist/registry/components-registry.d.ts.map +1 -0
- package/dist/registry/components-registry.js +469 -0
- package/dist/registry/components-registry.js.map +1 -0
- package/dist/registry/index.d.ts +2 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +7 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/security/patterns.d.ts +4 -0
- package/dist/security/patterns.d.ts.map +1 -0
- package/dist/security/patterns.js +65 -0
- package/dist/security/patterns.js.map +1 -0
- package/dist/security/redactor.d.ts +26 -0
- package/dist/security/redactor.d.ts.map +1 -0
- package/dist/security/redactor.js +128 -0
- package/dist/security/redactor.js.map +1 -0
- package/dist/security/validator.d.ts +11 -0
- package/dist/security/validator.d.ts.map +1 -0
- package/dist/security/validator.js +62 -0
- package/dist/security/validator.js.map +1 -0
- package/dist/storage/engine.d.ts +45 -0
- package/dist/storage/engine.d.ts.map +1 -0
- package/dist/storage/engine.js +479 -0
- package/dist/storage/engine.js.map +1 -0
- package/dist/storage/manifest.d.ts +10 -0
- package/dist/storage/manifest.d.ts.map +1 -0
- package/dist/storage/manifest.js +98 -0
- package/dist/storage/manifest.js.map +1 -0
- package/dist/storage/serializer.d.ts +9 -0
- package/dist/storage/serializer.d.ts.map +1 -0
- package/dist/storage/serializer.js +22 -0
- package/dist/storage/serializer.js.map +1 -0
- package/dist/types/capture.d.ts +206 -0
- package/dist/types/capture.d.ts.map +1 -0
- package/dist/types/capture.js +3 -0
- package/dist/types/capture.js.map +1 -0
- package/dist/types/config.d.ts +63 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +3 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/registry.d.ts +94 -0
- package/dist/types/registry.d.ts.map +1 -0
- package/dist/types/registry.js +3 -0
- package/dist/types/registry.js.map +1 -0
- package/dist/types/storage.d.ts +57 -0
- package/dist/types/storage.d.ts.map +1 -0
- package/dist/types/storage.js +3 -0
- package/dist/types/storage.js.map +1 -0
- package/dist/utils/hash.d.ts +3 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +26 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +86 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/pom-generator.d.ts +12 -0
- package/dist/utils/pom-generator.d.ts.map +1 -0
- package/dist/utils/pom-generator.js +83 -0
- package/dist/utils/pom-generator.js.map +1 -0
- package/dist/utils/validators.d.ts +7 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +51 -0
- package/dist/utils/validators.js.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 shadowcoderr
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# ContextGraph
|
|
2
|
+
|
|
3
|
+
> **A deterministic "Flight Data Recorder" for web applications** — captures rich, AI-ready context from browser sessions in restricted enterprise environments where MCP is unavailable.
|
|
4
|
+
|
|
5
|
+
[](package.json)
|
|
6
|
+
[](package.json)
|
|
7
|
+
[](tsconfig.json)
|
|
8
|
+
[](package.json)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Why ContextGraph?
|
|
14
|
+
|
|
15
|
+
IDE-based AI agents (Copilot, Cursor, etc.) are blind to your running browser. Without MCP, they cannot see the live DOM, accessibility tree, or real API traffic of the app you are testing. In enterprise environments, MCP and cloud-based recording tools are often blocked by security policy.
|
|
16
|
+
|
|
17
|
+
ContextGraph solves this by acting as a **pre-processor** — it bridges the gap between manual exploration and AI-powered test generation using only Playwright, which is already whitelisted on most QA teams' machines.
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
Your Browser Session
|
|
21
|
+
│
|
|
22
|
+
▼
|
|
23
|
+
ContextGraph ← You are here
|
|
24
|
+
(Playwright-native)
|
|
25
|
+
│
|
|
26
|
+
▼
|
|
27
|
+
Structured Output ← DOM, Locators, A11y Tree, Network
|
|
28
|
+
(Local Filesystem)
|
|
29
|
+
│
|
|
30
|
+
▼
|
|
31
|
+
AI Agent / LLM ← Receives clean, noise-free context
|
|
32
|
+
(Copilot / Cursor / Claude)
|
|
33
|
+
│
|
|
34
|
+
▼
|
|
35
|
+
Generated Tests ← Playwright .spec.ts files
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
### Prerequisites
|
|
43
|
+
|
|
44
|
+
- **Node.js** 18.0.0 or higher
|
|
45
|
+
- **Microsoft Edge** (installed — used as the capture browser)
|
|
46
|
+
- **Windows 10/11** (primary support; Linux/macOS in beta)
|
|
47
|
+
|
|
48
|
+
### Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install -g context-graph
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Verify:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
context-graph --version
|
|
58
|
+
# Context Graph v0.3.0
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Capture Your First Page (2 minutes)
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# 1. Start a capture session
|
|
65
|
+
context-graph --mode browser --url https://your-app.com
|
|
66
|
+
|
|
67
|
+
# 2. Navigate through the app — every page you visit is captured
|
|
68
|
+
# 3. Press Ctrl+C when done
|
|
69
|
+
|
|
70
|
+
# 4. Inspect results
|
|
71
|
+
cat context-graph-output/global_manifest.json
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Key Features
|
|
77
|
+
|
|
78
|
+
| Feature | Description |
|
|
79
|
+
|---|---|
|
|
80
|
+
| 🎯 **Guided Capture** | Captures only what you navigate — no autonomous crawling |
|
|
81
|
+
| 🧹 **Clean DOM Output** | Scripts, event handlers, and noise stripped before saving |
|
|
82
|
+
| 🔑 **Smart Locators** | 5+ selector strategies per element, ranked by resilience |
|
|
83
|
+
| ♿ **Accessibility Tree** | Full ARIA/role hierarchy for semantic understanding |
|
|
84
|
+
| 🌐 **Network Logging** | All HTTP traffic captured with automatic PII redaction |
|
|
85
|
+
| 🔒 **Security by Design** | Credentials, tokens, PII never touch the filesystem |
|
|
86
|
+
| 🧩 **Component Registry** | Tracks reusable UI patterns across captured pages |
|
|
87
|
+
| 📦 **100% Offline** | Zero cloud dependencies, zero telemetry, runs inside enterprise perimeter |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Operating Modes
|
|
92
|
+
|
|
93
|
+
### Browser Mode — Passive Observer
|
|
94
|
+
|
|
95
|
+
Best for: understanding app structure, feeding AI with full UI context.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
context-graph --mode browser --url https://app.example.com
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Recorder Mode — Action Capture
|
|
102
|
+
|
|
103
|
+
Best for: converting manual test walkthroughs into replayable scripts.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
context-graph --mode recorder --url https://app.example.com
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## What You Get
|
|
112
|
+
|
|
113
|
+
For each captured page, ContextGraph generates:
|
|
114
|
+
|
|
115
|
+
- **Sanitized DOM** - Clean HTML with scripts removed
|
|
116
|
+
- **Accessibility Tree** - Full ARIA hierarchy and semantic structure
|
|
117
|
+
- **Smart Locators** - Ranked Playwright selectors (Role → TestID → Label → Text)
|
|
118
|
+
- **Network Log** - HTTP traffic with automatic PII redaction
|
|
119
|
+
- **Screenshots** - Full-page visual captures
|
|
120
|
+
- **Component Registry** - Cross-page UI pattern tracking
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Feeding Output to an AI Agent
|
|
125
|
+
|
|
126
|
+
### What to Give the AI
|
|
127
|
+
|
|
128
|
+
For test generation, provide the AI these files from a single captured page:
|
|
129
|
+
|
|
130
|
+
| File | Why it Matters |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `metadata.json` | URL, page title, timing context |
|
|
133
|
+
| `a11y_tree.json` | Semantic structure — what the page *means* |
|
|
134
|
+
| `locators.json` | Ready-to-use, ranked Playwright selectors |
|
|
135
|
+
| `dom_snapshot.html` | Full structural HTML if deep context is needed |
|
|
136
|
+
| `network/traffic_log.jsonl` | What API calls the page makes |
|
|
137
|
+
|
|
138
|
+
### Example Prompt Structure
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
I am testing the following web page:
|
|
142
|
+
URL: https://app.example.com/login
|
|
143
|
+
|
|
144
|
+
Here is the accessibility tree:
|
|
145
|
+
[paste a11y_tree.json]
|
|
146
|
+
|
|
147
|
+
Here are the available locators:
|
|
148
|
+
[paste locators.json]
|
|
149
|
+
|
|
150
|
+
Here is the API traffic observed:
|
|
151
|
+
[paste relevant entries from traffic_log.jsonl]
|
|
152
|
+
|
|
153
|
+
Generate a Playwright test that:
|
|
154
|
+
1. Navigates to the login page
|
|
155
|
+
2. Enters valid credentials
|
|
156
|
+
3. Asserts the dashboard is shown
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Documentation
|
|
162
|
+
|
|
163
|
+
📖 **[Complete User Guide](docs/USER_GUIDE.md)** - Advanced configuration, CLI reference, troubleshooting, and architecture details.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Installation
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
npm install -g context-graph
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
MIT — © Shadow Coderr
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Issues & Support
|
|
182
|
+
|
|
183
|
+
🐛 **[Report Issues](https://github.com/shadowcoderr/ContextGraph/issues)** - Bug reports and feature requests
|
|
184
|
+
|
|
185
|
+
💬 **[Discussions](https://github.com/shadowcoderr/ContextGraph/discussions)** - Community support and questions
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
import { AccessibilityTree } from '../types/capture';
|
|
3
|
+
export declare class AccessibilityExtractor {
|
|
4
|
+
extract(page: Page, _includeHidden?: boolean): Promise<AccessibilityTree>;
|
|
5
|
+
/**
|
|
6
|
+
* Transform CDP accessibility tree format to our format
|
|
7
|
+
*/
|
|
8
|
+
private transformCDPSnapshot;
|
|
9
|
+
/**
|
|
10
|
+
* Build accessibility tree from DOM when Playwright accessibility API is unavailable
|
|
11
|
+
*/
|
|
12
|
+
private buildFromDOM;
|
|
13
|
+
private transformSnapshot;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=a11y-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a11y-extractor.d.ts","sourceRoot":"","sources":["../../src/analyzers/a11y-extractor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,qBAAa,sBAAsB;IAC3B,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,GAAE,OAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAwCtF;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA0C5B;;OAEG;YACW,YAAY;IA+C1B,OAAO,CAAC,iBAAiB;CAkB1B"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AccessibilityExtractor = void 0;
|
|
4
|
+
class AccessibilityExtractor {
|
|
5
|
+
async extract(page, _includeHidden = false) {
|
|
6
|
+
try {
|
|
7
|
+
// Wait for page to be ready
|
|
8
|
+
await page.waitForLoadState('domcontentloaded', { timeout: 5000 }).catch(() => { });
|
|
9
|
+
// Try to get accessibility snapshot via CDP
|
|
10
|
+
let snapshot = null;
|
|
11
|
+
try {
|
|
12
|
+
// Use CDP (Chrome DevTools Protocol) for accessibility snapshot
|
|
13
|
+
const client = await page.context().newCDPSession(page);
|
|
14
|
+
snapshot = await client.send('Accessibility.getFullAXTree');
|
|
15
|
+
if (snapshot && snapshot.nodes && snapshot.nodes.length > 0) {
|
|
16
|
+
// Transform CDP format to our format
|
|
17
|
+
return this.transformCDPSnapshot(snapshot.nodes[0], snapshot.nodes);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch (cdpError) {
|
|
21
|
+
// CDP not available, fall through to DOM-based approach
|
|
22
|
+
}
|
|
23
|
+
// Fallback: build accessibility tree from DOM
|
|
24
|
+
snapshot = await this.buildFromDOM(page);
|
|
25
|
+
return this.transformSnapshot(snapshot);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
// Final fallback: build from DOM
|
|
29
|
+
try {
|
|
30
|
+
const domSnapshot = await this.buildFromDOM(page);
|
|
31
|
+
return this.transformSnapshot(domSnapshot);
|
|
32
|
+
}
|
|
33
|
+
catch (domError) {
|
|
34
|
+
// Ultimate fallback
|
|
35
|
+
return {
|
|
36
|
+
role: 'WebArea',
|
|
37
|
+
name: await page.title().catch(() => ''),
|
|
38
|
+
children: [],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Transform CDP accessibility tree format to our format
|
|
45
|
+
*/
|
|
46
|
+
transformCDPSnapshot(rootNode, allNodes) {
|
|
47
|
+
const buildNode = (node) => {
|
|
48
|
+
const children = [];
|
|
49
|
+
if (node.childIds && node.childIds.length > 0) {
|
|
50
|
+
for (const childId of node.childIds) {
|
|
51
|
+
const childNode = allNodes.find((n) => n.nodeId === childId);
|
|
52
|
+
if (childNode) {
|
|
53
|
+
children.push(buildNode(childNode));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const result = {
|
|
58
|
+
role: node.role?.value || 'unknown',
|
|
59
|
+
name: node.name?.value || '',
|
|
60
|
+
children: children.length > 0 ? children : [],
|
|
61
|
+
value: node.value?.value,
|
|
62
|
+
required: node.properties?.find((p) => p.name === 'required')?.value?.value === true,
|
|
63
|
+
disabled: node.properties?.find((p) => p.name === 'disabled')?.value?.value === true,
|
|
64
|
+
focused: node.properties?.find((p) => p.name === 'focused')?.value?.value === true,
|
|
65
|
+
};
|
|
66
|
+
// Add optional properties only if they exist
|
|
67
|
+
const checked = node.properties?.find((p) => p.name === 'checked')?.value?.value;
|
|
68
|
+
if (checked !== undefined)
|
|
69
|
+
result.checked = checked;
|
|
70
|
+
const pressed = node.properties?.find((p) => p.name === 'pressed')?.value?.value;
|
|
71
|
+
if (pressed !== undefined)
|
|
72
|
+
result.pressed = pressed;
|
|
73
|
+
const selected = node.properties?.find((p) => p.name === 'selected')?.value?.value;
|
|
74
|
+
if (selected !== undefined)
|
|
75
|
+
result.selected = selected;
|
|
76
|
+
const expanded = node.properties?.find((p) => p.name === 'expanded')?.value?.value;
|
|
77
|
+
if (expanded !== undefined)
|
|
78
|
+
result.expanded = expanded;
|
|
79
|
+
return result;
|
|
80
|
+
};
|
|
81
|
+
return buildNode(rootNode);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Build accessibility tree from DOM when Playwright accessibility API is unavailable
|
|
85
|
+
*/
|
|
86
|
+
async buildFromDOM(page) {
|
|
87
|
+
return await page.evaluate(() => {
|
|
88
|
+
const buildA11yNode = (element) => {
|
|
89
|
+
const role = element.getAttribute('role') ||
|
|
90
|
+
(element.tagName === 'BUTTON' ? 'button' :
|
|
91
|
+
element.tagName === 'INPUT' ? 'textbox' :
|
|
92
|
+
element.tagName === 'A' ? 'link' :
|
|
93
|
+
element.tagName === 'FORM' ? 'form' :
|
|
94
|
+
element.tagName === 'HEADER' ? 'banner' :
|
|
95
|
+
element.tagName === 'NAV' ? 'navigation' :
|
|
96
|
+
element.tagName === 'MAIN' ? 'main' :
|
|
97
|
+
element.tagName === 'FOOTER' ? 'contentinfo' : 'generic');
|
|
98
|
+
const name = element.getAttribute('aria-label') ||
|
|
99
|
+
element.getAttribute('aria-labelledby') ||
|
|
100
|
+
element.innerText?.trim() ||
|
|
101
|
+
element.getAttribute('alt') ||
|
|
102
|
+
element.getAttribute('title') ||
|
|
103
|
+
'';
|
|
104
|
+
const children = [];
|
|
105
|
+
for (let i = 0; i < element.children.length; i++) {
|
|
106
|
+
const child = buildA11yNode(element.children[i]);
|
|
107
|
+
if (child)
|
|
108
|
+
children.push(child);
|
|
109
|
+
}
|
|
110
|
+
const result = {
|
|
111
|
+
role,
|
|
112
|
+
name: name.substring(0, 100), // Limit name length
|
|
113
|
+
children: children.length > 0 ? children : [],
|
|
114
|
+
disabled: element.hasAttribute('disabled'),
|
|
115
|
+
required: element.hasAttribute('required'),
|
|
116
|
+
};
|
|
117
|
+
const checked = element.checked;
|
|
118
|
+
if (checked)
|
|
119
|
+
result.checked = checked;
|
|
120
|
+
const expanded = element.getAttribute('aria-expanded') === 'true';
|
|
121
|
+
if (expanded)
|
|
122
|
+
result.expanded = expanded;
|
|
123
|
+
return result;
|
|
124
|
+
};
|
|
125
|
+
return buildA11yNode(document.documentElement);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
transformSnapshot(snapshot) {
|
|
129
|
+
return {
|
|
130
|
+
role: snapshot.role || 'unknown',
|
|
131
|
+
name: snapshot.name || '',
|
|
132
|
+
children: snapshot.children ? snapshot.children.map((child) => this.transformSnapshot(child)) : [],
|
|
133
|
+
value: snapshot.value,
|
|
134
|
+
required: snapshot.required,
|
|
135
|
+
disabled: snapshot.disabled,
|
|
136
|
+
focused: snapshot.focused,
|
|
137
|
+
multiline: snapshot.multiline,
|
|
138
|
+
protected: snapshot.protected,
|
|
139
|
+
checked: snapshot.checked,
|
|
140
|
+
pressed: snapshot.pressed,
|
|
141
|
+
selected: snapshot.selected,
|
|
142
|
+
expanded: snapshot.expanded,
|
|
143
|
+
level: snapshot.level,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.AccessibilityExtractor = AccessibilityExtractor;
|
|
148
|
+
//# sourceMappingURL=a11y-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a11y-extractor.js","sourceRoot":"","sources":["../../src/analyzers/a11y-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
export declare class DOMAnalyzer {
|
|
3
|
+
private serializeFrameContent;
|
|
4
|
+
analyze(page: Page): Promise<{
|
|
5
|
+
html: string;
|
|
6
|
+
frames: Array<{
|
|
7
|
+
url: string;
|
|
8
|
+
name: string;
|
|
9
|
+
content: string;
|
|
10
|
+
}>;
|
|
11
|
+
}>;
|
|
12
|
+
getPerformanceMetrics(page: Page): Promise<{
|
|
13
|
+
domNodes: number;
|
|
14
|
+
scripts: number;
|
|
15
|
+
stylesheets: number;
|
|
16
|
+
images: number;
|
|
17
|
+
totalRequests: number;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=dom-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzers/dom-analyzer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAS,MAAM,kBAAkB,CAAC;AAE/C,qBAAa,WAAW;YAGR,qBAAqB;IAyC7B,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IA4D7G,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;QAC/C,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;CAkBH"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DOMAnalyzer = void 0;
|
|
4
|
+
class DOMAnalyzer {
|
|
5
|
+
async serializeFrameContent(frame) {
|
|
6
|
+
try {
|
|
7
|
+
return await frame.evaluate(() => {
|
|
8
|
+
const serialize = (node) => {
|
|
9
|
+
if (!node)
|
|
10
|
+
return '';
|
|
11
|
+
const nodeType = node.nodeType;
|
|
12
|
+
const Node = window.Node;
|
|
13
|
+
if (nodeType === Node.DOCUMENT_NODE)
|
|
14
|
+
return '<!DOCTYPE html>' + serialize(node.documentElement);
|
|
15
|
+
if (nodeType === Node.ELEMENT_NODE) {
|
|
16
|
+
const el = node;
|
|
17
|
+
let tag = el.tagName.toLowerCase();
|
|
18
|
+
let attrs = '';
|
|
19
|
+
for (let i = 0; i < el.attributes.length; i++) {
|
|
20
|
+
const a = el.attributes[i];
|
|
21
|
+
attrs += ` ${a.name}="${a.value}"`;
|
|
22
|
+
}
|
|
23
|
+
let inner = '';
|
|
24
|
+
// Shadow DOM
|
|
25
|
+
if (el.shadowRoot) {
|
|
26
|
+
inner += '<!--cc-shadow-start-->';
|
|
27
|
+
const sr = el.shadowRoot;
|
|
28
|
+
for (let i = 0; i < sr.childNodes.length; i++) {
|
|
29
|
+
inner += serialize(sr.childNodes[i]);
|
|
30
|
+
}
|
|
31
|
+
inner += '<!--cc-shadow-end-->';
|
|
32
|
+
}
|
|
33
|
+
for (let i = 0; i < el.childNodes.length; i++) {
|
|
34
|
+
inner += serialize(el.childNodes[i]);
|
|
35
|
+
}
|
|
36
|
+
return `<${tag}${attrs}>${inner}</${tag}>`;
|
|
37
|
+
}
|
|
38
|
+
if (nodeType === Node.TEXT_NODE)
|
|
39
|
+
return node.nodeValue.replace(/</g, '<');
|
|
40
|
+
return '';
|
|
41
|
+
};
|
|
42
|
+
return serialize(document);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async analyze(page) {
|
|
50
|
+
// Get the main document serialized including shadow roots
|
|
51
|
+
const html = await page.evaluate(() => {
|
|
52
|
+
const serialize = (node) => {
|
|
53
|
+
if (!node)
|
|
54
|
+
return '';
|
|
55
|
+
const nodeType = node.nodeType;
|
|
56
|
+
const Node = window.Node;
|
|
57
|
+
if (nodeType === Node.DOCUMENT_NODE)
|
|
58
|
+
return '<!DOCTYPE html>' + serialize(node.documentElement);
|
|
59
|
+
if (nodeType === Node.ELEMENT_NODE) {
|
|
60
|
+
const el = node;
|
|
61
|
+
let tag = el.tagName.toLowerCase();
|
|
62
|
+
let attrs = '';
|
|
63
|
+
for (let i = 0; i < el.attributes.length; i++) {
|
|
64
|
+
const a = el.attributes[i];
|
|
65
|
+
attrs += ` ${a.name}="${a.value}"`;
|
|
66
|
+
}
|
|
67
|
+
let inner = '';
|
|
68
|
+
// Shadow DOM
|
|
69
|
+
if (el.shadowRoot) {
|
|
70
|
+
inner += '<!--cc-shadow-start-->';
|
|
71
|
+
const sr = el.shadowRoot;
|
|
72
|
+
for (let i = 0; i < sr.childNodes.length; i++) {
|
|
73
|
+
inner += serialize(sr.childNodes[i]);
|
|
74
|
+
}
|
|
75
|
+
inner += '<!--cc-shadow-end-->';
|
|
76
|
+
}
|
|
77
|
+
for (let i = 0; i < el.childNodes.length; i++) {
|
|
78
|
+
inner += serialize(el.childNodes[i]);
|
|
79
|
+
}
|
|
80
|
+
return `<${tag}${attrs}>${inner}</${tag}>`;
|
|
81
|
+
}
|
|
82
|
+
if (nodeType === Node.TEXT_NODE)
|
|
83
|
+
return node.nodeValue ? node.nodeValue.replace(/</g, '<') : '';
|
|
84
|
+
return '';
|
|
85
|
+
};
|
|
86
|
+
return serialize(document);
|
|
87
|
+
});
|
|
88
|
+
// Gather frames content
|
|
89
|
+
const frames = [];
|
|
90
|
+
const framesList = page.frames();
|
|
91
|
+
for (let i = 0; i < framesList.length; i++) {
|
|
92
|
+
const frame = framesList[i];
|
|
93
|
+
if (frame === page.mainFrame())
|
|
94
|
+
continue; // Skip main frame
|
|
95
|
+
const content = await this.serializeFrameContent(frame);
|
|
96
|
+
frames.push({ url: frame.url(), name: frame.name(), content });
|
|
97
|
+
}
|
|
98
|
+
// Remove script tags and inline JavaScript from main html
|
|
99
|
+
let sanitized = html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');
|
|
100
|
+
sanitized = sanitized.replace(/<script[^>]*\/\>/gi, '');
|
|
101
|
+
sanitized = sanitized.replace(/\s+on\w+="[^"]*"/gi, '');
|
|
102
|
+
sanitized = sanitized.replace(/\s+on\w+='[^']*'/gi, '');
|
|
103
|
+
// Add capture timestamp
|
|
104
|
+
const timestamp = new Date().toISOString();
|
|
105
|
+
sanitized = sanitized.replace(/<html([^>]*)>/, `<html$1 data-cc-captured="${timestamp}">`);
|
|
106
|
+
return { html: sanitized, frames };
|
|
107
|
+
}
|
|
108
|
+
async getPerformanceMetrics(page) {
|
|
109
|
+
const metrics = await page.evaluate(() => {
|
|
110
|
+
const domNodes = document.getElementsByTagName('*').length;
|
|
111
|
+
const scripts = document.querySelectorAll('script').length;
|
|
112
|
+
const stylesheets = document.querySelectorAll('link[rel="stylesheet"]').length;
|
|
113
|
+
const images = document.querySelectorAll('img').length;
|
|
114
|
+
return {
|
|
115
|
+
domNodes,
|
|
116
|
+
scripts,
|
|
117
|
+
stylesheets,
|
|
118
|
+
images,
|
|
119
|
+
totalRequests: 0, // Will be calculated from network events
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
return metrics;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.DOMAnalyzer = DOMAnalyzer;
|
|
126
|
+
//# sourceMappingURL=dom-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-analyzer.js","sourceRoot":"","sources":["../../src/analyzers/dom-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Page } from '@playwright/test';
|
|
2
|
+
import { LocatorsData } from '../types/capture';
|
|
3
|
+
export declare class LocatorGenerator {
|
|
4
|
+
generateLocators(page: Page): Promise<LocatorsData>;
|
|
5
|
+
private generateElementLocator;
|
|
6
|
+
private getRole;
|
|
7
|
+
private getAssociatedLabel;
|
|
8
|
+
/**
|
|
9
|
+
* Calculate match count and uniqueness for a locator strategy
|
|
10
|
+
*/
|
|
11
|
+
private getMatchCount;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=locator-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locator-generator.d.ts","sourceRoot":"","sources":["../../src/analyzers/locator-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAA2B,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGzE,qBAAa,gBAAgB;IACrB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;YAmG3C,sBAAsB;YAyKtB,OAAO;YAuCP,kBAAkB;IAoChC;;OAEG;YACW,aAAa;CA4C5B"}
|