@agimon-ai/browse-tool 0.2.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 +52 -0
- package/README.md +375 -0
- package/dist/cli.cjs +674 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.mts +2 -0
- package/dist/cli.mjs +434 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/extension/background.js +7248 -0
- package/dist/extension/background.js.map +1 -0
- package/dist/extension/content.js +446 -0
- package/dist/extension/content.js.map +1 -0
- package/dist/extension/manifest.json +36 -0
- package/dist/extension/offscreen.html +9 -0
- package/dist/extension/offscreen.js +137 -0
- package/dist/extension/offscreen.js.map +1 -0
- package/dist/extension/popup.html +195 -0
- package/dist/extension/popup.js +132 -0
- package/dist/extension/popup.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +309 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +310 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/playwright-test-BwI7HgW7.mjs +253 -0
- package/dist/playwright-test-BwI7HgW7.mjs.map +1 -0
- package/dist/playwright-test-CnsuVfC9.cjs +252 -0
- package/dist/stdio-BP3yiSxK.mjs +9 -0
- package/dist/stdio-BP3yiSxK.mjs.map +1 -0
- package/dist/stdio-ynNFGBY4.cjs +9 -0
- package/dist/stubs/playwright-test.cjs +1 -0
- package/dist/stubs/playwright-test.d.cts +111 -0
- package/dist/stubs/playwright-test.d.cts.map +1 -0
- package/dist/stubs/playwright-test.d.mts +111 -0
- package/dist/stubs/playwright-test.d.mts.map +1 -0
- package/dist/stubs/playwright-test.mjs +1 -0
- package/package.json +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Parameters
|
|
4
|
+
|
|
5
|
+
Licensor: AgiFlow
|
|
6
|
+
Licensed Work: @agimon-ai/public-packages
|
|
7
|
+
The Licensed Work is (c) 2026 AgiFlow.
|
|
8
|
+
Additional Use Grant: None
|
|
9
|
+
Change Date: 2030-03-06
|
|
10
|
+
Change License: Apache License, Version 2.0
|
|
11
|
+
|
|
12
|
+
Terms
|
|
13
|
+
|
|
14
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
15
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
16
|
+
Licensor may make an Additional Use Grant, above, permitting limited
|
|
17
|
+
production use.
|
|
18
|
+
|
|
19
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
20
|
+
available distribution of a specific version of the Licensed Work under this
|
|
21
|
+
License, whichever comes first, the Licensor hereby grants you rights under
|
|
22
|
+
the terms of the Change License, and the rights granted in the paragraph
|
|
23
|
+
above terminate.
|
|
24
|
+
|
|
25
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
26
|
+
currently in effect as described in this License, you must purchase a
|
|
27
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
28
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
29
|
+
|
|
30
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
31
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
32
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
33
|
+
for each version of the Licensed Work released by Licensor.
|
|
34
|
+
|
|
35
|
+
You must conspicuously display this License on each original or modified copy
|
|
36
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
37
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
38
|
+
License apply to your use of that work.
|
|
39
|
+
|
|
40
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
41
|
+
terminate your rights under this License for the current and all other
|
|
42
|
+
versions of the Licensed Work.
|
|
43
|
+
|
|
44
|
+
This License does not grant you any right in any trademark or logo of
|
|
45
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
46
|
+
Licensor as expressly required by this License).
|
|
47
|
+
|
|
48
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
49
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
50
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
51
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
52
|
+
TITLE.
|
package/README.md
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# browse-tool
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for browser automation using Playwright. Provides comprehensive browser control, profile management, and LLM-driven automation capabilities.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 37 browser automation tools for complete browser control
|
|
8
|
+
- Multi-browser support (Chromium, Firefox, WebKit)
|
|
9
|
+
- Profile management for persistent browser sessions
|
|
10
|
+
- Page registry for managing multiple tabs/windows
|
|
11
|
+
- LLM-controlled automation with pause/resume flow
|
|
12
|
+
- Session management for organized browser operations
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Development
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm dev
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Build
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm build
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Test
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pnpm test
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage with Claude Code
|
|
39
|
+
|
|
40
|
+
Add to your Claude Code configuration (`.mcp.json`):
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"browse-tool": {
|
|
46
|
+
"command": "npx",
|
|
47
|
+
"args": ["browse-tool", "mcp-serve"]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### CLI Options
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
browse-tool mcp-serve [options]
|
|
57
|
+
|
|
58
|
+
Options:
|
|
59
|
+
-t, --type <type> Transport type: stdio (default: "stdio")
|
|
60
|
+
-b, --browser <type> Default browser: chromium, firefox, webkit (default: "chromium")
|
|
61
|
+
--headless Run browsers in headless mode
|
|
62
|
+
--no-headless Run browsers in headed mode (visible window)
|
|
63
|
+
-p, --profile <name> Default profile name for browser sessions
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Tool Reference
|
|
67
|
+
|
|
68
|
+
### Input Tools (8)
|
|
69
|
+
|
|
70
|
+
| Tool | Description |
|
|
71
|
+
|------|-------------|
|
|
72
|
+
| `browser_click` | Click on an element |
|
|
73
|
+
| `browser_fill` | Fill a form field with text (clears first) |
|
|
74
|
+
| `browser_type` | Type text into an element (appends) |
|
|
75
|
+
| `browser_hover` | Hover over an element |
|
|
76
|
+
| `browser_select` | Select an option from a dropdown |
|
|
77
|
+
| `browser_drag` | Drag from one element to another |
|
|
78
|
+
| `browser_press_key` | Press a keyboard key |
|
|
79
|
+
| `browser_upload_file` | Upload a file to a file input |
|
|
80
|
+
|
|
81
|
+
### Navigation Tools (5)
|
|
82
|
+
|
|
83
|
+
| Tool | Description |
|
|
84
|
+
|------|-------------|
|
|
85
|
+
| `browser_navigate` | Navigate to a URL |
|
|
86
|
+
| `browser_go_back` | Go back in browser history |
|
|
87
|
+
| `browser_go_forward` | Go forward in browser history |
|
|
88
|
+
| `browser_reload` | Reload the current page |
|
|
89
|
+
| `browser_wait_for` | Wait for an element or condition |
|
|
90
|
+
|
|
91
|
+
### Snapshot Tools (3)
|
|
92
|
+
|
|
93
|
+
| Tool | Description |
|
|
94
|
+
|------|-------------|
|
|
95
|
+
| `browser_screenshot` | Take a screenshot |
|
|
96
|
+
| `browser_pdf` | Generate PDF of the page |
|
|
97
|
+
| `browser_snapshot` | Get accessibility tree snapshot |
|
|
98
|
+
|
|
99
|
+
### Tab/Page Management Tools (4)
|
|
100
|
+
|
|
101
|
+
| Tool | Description |
|
|
102
|
+
|------|-------------|
|
|
103
|
+
| `browser_list_pages` | List all open pages |
|
|
104
|
+
| `browser_select_page` | Switch to a specific page |
|
|
105
|
+
| `browser_new_page` | Open a new page |
|
|
106
|
+
| `browser_close_page` | Close a page |
|
|
107
|
+
|
|
108
|
+
### Dialog/Network/Console Tools (7)
|
|
109
|
+
|
|
110
|
+
| Tool | Description |
|
|
111
|
+
|------|-------------|
|
|
112
|
+
| `browser_handle_dialog` | Handle JavaScript dialogs (alert, confirm, prompt) |
|
|
113
|
+
| `browser_list_network_requests` | List captured network requests |
|
|
114
|
+
| `browser_get_network_request` | Get details of a specific network request |
|
|
115
|
+
| `browser_list_console_messages` | List console messages |
|
|
116
|
+
| `browser_evaluate_script` | Execute JavaScript in the page |
|
|
117
|
+
| `browser_resize_page` | Resize the browser viewport |
|
|
118
|
+
| `browser_emulate` | Emulate device, geolocation, or network conditions |
|
|
119
|
+
|
|
120
|
+
### Testing/Tracing Tools (3)
|
|
121
|
+
|
|
122
|
+
| Tool | Description |
|
|
123
|
+
|------|-------------|
|
|
124
|
+
| `browser_expect` | Assert conditions on elements |
|
|
125
|
+
| `browser_start_trace` | Start Playwright tracing |
|
|
126
|
+
| `browser_stop_trace` | Stop tracing and save trace file |
|
|
127
|
+
|
|
128
|
+
### Profile Management Tools (4)
|
|
129
|
+
|
|
130
|
+
| Tool | Description |
|
|
131
|
+
|------|-------------|
|
|
132
|
+
| `browser_list_profiles` | List all saved profiles |
|
|
133
|
+
| `browser_create_profile` | Create a new browser profile |
|
|
134
|
+
| `browser_delete_profile` | Delete a profile |
|
|
135
|
+
| `browser_save_profile_state` | Save current browser state to profile |
|
|
136
|
+
|
|
137
|
+
### Automation Tools (3)
|
|
138
|
+
|
|
139
|
+
| Tool | Description |
|
|
140
|
+
|------|-------------|
|
|
141
|
+
| `run_automation` | Run an automation script with optional pause |
|
|
142
|
+
| `resume_automation` | Resume a paused automation |
|
|
143
|
+
| `get_automation_status` | Get automation session status |
|
|
144
|
+
|
|
145
|
+
## Automation Script Format
|
|
146
|
+
|
|
147
|
+
Automation scripts are TypeScript/JavaScript modules that export a `run` function:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import type { AutomationFixtures } from 'browse-tool';
|
|
151
|
+
|
|
152
|
+
export async function run({ page, context, browser, pauseCheck }: AutomationFixtures) {
|
|
153
|
+
// Navigate to a page
|
|
154
|
+
await page.goto('https://example.com');
|
|
155
|
+
|
|
156
|
+
// Create a pause checkpoint for LLM intervention
|
|
157
|
+
await pauseCheck('after-navigation', 'Page loaded, ready for inspection');
|
|
158
|
+
|
|
159
|
+
// Continue with automation
|
|
160
|
+
await page.click('#login-button');
|
|
161
|
+
|
|
162
|
+
// Another pause point
|
|
163
|
+
await pauseCheck('after-login-click', 'Login button clicked');
|
|
164
|
+
|
|
165
|
+
// Fill form
|
|
166
|
+
await page.fill('#username', 'testuser');
|
|
167
|
+
await page.fill('#password', 'password123');
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Fixtures Available
|
|
172
|
+
|
|
173
|
+
| Fixture | Type | Description |
|
|
174
|
+
|---------|------|-------------|
|
|
175
|
+
| `page` | `Page` | Playwright Page instance |
|
|
176
|
+
| `context` | `BrowserContext` | Playwright BrowserContext |
|
|
177
|
+
| `browser` | `Browser` | Playwright Browser instance |
|
|
178
|
+
| `pauseCheck` | `Function` | Create pause checkpoints for LLM control |
|
|
179
|
+
|
|
180
|
+
### Using pauseCheck
|
|
181
|
+
|
|
182
|
+
The `pauseCheck` function allows the automation to pause at specific points, giving the LLM control to inspect the page, interact manually, and then resume:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
await pauseCheck(stepName: string, reason?: string): Promise<void>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
When paused:
|
|
189
|
+
1. The automation waits for `resume_automation` to be called
|
|
190
|
+
2. All browser tools remain available for LLM interaction
|
|
191
|
+
3. The LLM can inspect page state, take screenshots, etc.
|
|
192
|
+
4. Once resumed, automation continues from where it paused
|
|
193
|
+
|
|
194
|
+
## Profile Management
|
|
195
|
+
|
|
196
|
+
Profiles allow you to persist browser state (cookies, localStorage, etc.) across sessions.
|
|
197
|
+
|
|
198
|
+
### Create a Profile
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"tool": "browser_create_profile",
|
|
203
|
+
"arguments": {
|
|
204
|
+
"name": "my-profile",
|
|
205
|
+
"browser": "chromium",
|
|
206
|
+
"headless": false
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Use a Profile with Automation
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"tool": "run_automation",
|
|
216
|
+
"arguments": {
|
|
217
|
+
"scriptPath": "/path/to/script.ts",
|
|
218
|
+
"browserOptions": {
|
|
219
|
+
"profile": "my-profile"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Save Profile State
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
{
|
|
229
|
+
"tool": "browser_save_profile_state",
|
|
230
|
+
"arguments": {
|
|
231
|
+
"sessionId": "automation-1",
|
|
232
|
+
"profileName": "my-profile"
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## LLM-Controlled Automation Flow
|
|
238
|
+
|
|
239
|
+
The unique feature of browse-tool is the ability to run automation scripts with LLM intervention points:
|
|
240
|
+
|
|
241
|
+
1. **Start Automation with Pause**
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"tool": "run_automation",
|
|
245
|
+
"arguments": {
|
|
246
|
+
"scriptPath": "/path/to/script.ts",
|
|
247
|
+
"pauseAtStart": true
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
2. **Automation Pauses** - Returns `automationId` and `pageIds`
|
|
253
|
+
|
|
254
|
+
3. **LLM Interacts** - Use browser tools (`browser_click`, `browser_fill`, etc.) on the paused pages
|
|
255
|
+
|
|
256
|
+
4. **Resume Automation**
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"tool": "resume_automation",
|
|
260
|
+
"arguments": {
|
|
261
|
+
"automationId": "automation-1"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
5. **Script Continues** - Until next `pauseCheck` or completion
|
|
267
|
+
|
|
268
|
+
6. **Check Status**
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"tool": "get_automation_status",
|
|
272
|
+
"arguments": {
|
|
273
|
+
"automationId": "automation-1"
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Configuration
|
|
279
|
+
|
|
280
|
+
### Environment Variables
|
|
281
|
+
|
|
282
|
+
| Variable | Default | Description |
|
|
283
|
+
|----------|---------|-------------|
|
|
284
|
+
| `PLAYWRIGHT_PROFILES_DIR` | `~/.browse-tool/profiles` | Directory for storing browser profiles |
|
|
285
|
+
| `PLAYWRIGHT_REGISTRY_DIR` | `.agiflow/registry` | Directory for HTTP server registry |
|
|
286
|
+
| `PLAYWRIGHT_PIDS_DIR` | `.pids` | Directory for tracking server PIDs |
|
|
287
|
+
| `NODE_ENV` | `development` | Runtime environment (`development`, `production`) |
|
|
288
|
+
|
|
289
|
+
### CLI Flags vs Environment Variables
|
|
290
|
+
|
|
291
|
+
CLI flags take precedence over environment variables. For example, `--profiles-dir /custom/path` overrides `PLAYWRIGHT_PROFILES_DIR`.
|
|
292
|
+
|
|
293
|
+
## Error Handling
|
|
294
|
+
|
|
295
|
+
### Common Failure Modes
|
|
296
|
+
|
|
297
|
+
| Failure | Cause | Recovery |
|
|
298
|
+
|---------|-------|----------|
|
|
299
|
+
| Browser launch failure | Missing browser binary or incompatible version | Run `npx playwright install chromium` to install browsers |
|
|
300
|
+
| Navigation timeout | Page took too long to load | Increase timeout via `browser_wait_for` or check network connectivity |
|
|
301
|
+
| Element not found | Selector did not match any element | Use `browser_snapshot` to inspect the current DOM tree |
|
|
302
|
+
| Profile not found | Referenced profile does not exist | Use `browser_list_profiles` to list available profiles |
|
|
303
|
+
| Session expired | Browser context was closed or crashed | Launch a new browser session with `browser_navigate` |
|
|
304
|
+
| Spec bundler build error | Syntax errors or unresolvable imports in spec file | Check the spec file for errors; see `SpecBundlerBuildError.recovery` |
|
|
305
|
+
| Spec bundler CLI error | `bun` not installed or not in PATH | Install bun: `curl -fsSL https://bun.sh/install \| bash` |
|
|
306
|
+
|
|
307
|
+
### Error Codes
|
|
308
|
+
|
|
309
|
+
All structured errors include a `code` field for programmatic handling and a `recovery` field with suggested resolution steps.
|
|
310
|
+
|
|
311
|
+
## Spec Bundler
|
|
312
|
+
|
|
313
|
+
The `SpecBundlerService` bundles Playwright spec files before execution, replacing `@playwright/test` imports with a lightweight stub module so specs can run inside the MCP server.
|
|
314
|
+
|
|
315
|
+
### Runtime Requirements
|
|
316
|
+
|
|
317
|
+
- **Bun runtime** (preferred): When the MCP server runs under Bun, `Bun.build()` is used directly.
|
|
318
|
+
- **Node.js runtime** (fallback): When running under Node.js, the service spawns `bun` as a CLI subprocess. Ensure `bun` is installed and accessible in `PATH`:
|
|
319
|
+
```bash
|
|
320
|
+
curl -fsSL https://bun.sh/install | bash
|
|
321
|
+
# or
|
|
322
|
+
npm i -g bun
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Programmatic Usage
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
import { SpecBundlerService } from 'browse-tool';
|
|
329
|
+
|
|
330
|
+
const bundler = new SpecBundlerService();
|
|
331
|
+
const { outputPath, cleanup } = await bundler.bundle('/path/to/my-spec.ts');
|
|
332
|
+
try {
|
|
333
|
+
// Use the bundled output at outputPath
|
|
334
|
+
} finally {
|
|
335
|
+
await cleanup();
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Error Handling
|
|
340
|
+
|
|
341
|
+
| Error Class | Code | When |
|
|
342
|
+
|-------------|------|------|
|
|
343
|
+
| `SpecBundlerBuildError` | `SPEC_BUNDLER_BUILD_FAILED` | Bundler reports syntax or resolution errors |
|
|
344
|
+
| `SpecBundlerNoOutputError` | `SPEC_BUNDLER_NO_OUTPUT` | Bundling produces no output file |
|
|
345
|
+
| `SpecBundlerCliError` | `SPEC_BUNDLER_CLI_FAILED` | `bun` CLI subprocess fails to execute |
|
|
346
|
+
|
|
347
|
+
## Architecture
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
browse-tool/
|
|
351
|
+
├── src/
|
|
352
|
+
│ ├── commands/ # CLI commands (mcp-serve)
|
|
353
|
+
│ ├── container/ # InversifyJS IoC container
|
|
354
|
+
│ ├── server/ # MCP server factory
|
|
355
|
+
│ ├── services/ # Core services
|
|
356
|
+
│ │ ├── AutomationRunner.ts # Script execution
|
|
357
|
+
│ │ ├── BrowserService.ts # Browser lifecycle
|
|
358
|
+
│ │ ├── PageRegistry.ts # Page tracking
|
|
359
|
+
│ │ ├── PauseController.ts # Pause/resume flow
|
|
360
|
+
│ │ ├── ProfileService.ts # Profile management
|
|
361
|
+
│ │ └── SessionService.ts # Session tracking
|
|
362
|
+
│ ├── tools/ # MCP tool implementations
|
|
363
|
+
│ ├── transports/ # Transport handlers (stdio)
|
|
364
|
+
│ └── types/ # TypeScript type definitions
|
|
365
|
+
├── tests/
|
|
366
|
+
│ ├── services/ # Service unit tests
|
|
367
|
+
│ ├── tools/ # Tool unit tests
|
|
368
|
+
│ ├── integration/ # Integration tests
|
|
369
|
+
│ └── fixtures/ # Test fixtures
|
|
370
|
+
└── README.md
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## License
|
|
374
|
+
|
|
375
|
+
MIT
|