sunpeak 0.19.12 → 0.20.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 +2 -2
- package/bin/commands/inspect.mjs +361 -12
- package/bin/commands/test-init.mjs +190 -118
- package/bin/commands/test.mjs +12 -1
- package/bin/lib/eval/eval-runner.mjs +7 -1
- package/bin/lib/inspect/inspect-config.mjs +17 -2
- package/bin/lib/inspect/inspect-server.d.mts +32 -0
- package/bin/lib/inspect/inspect-server.mjs +11 -0
- package/bin/lib/live/live-config.d.mts +10 -0
- package/bin/lib/live/live-config.mjs +34 -2
- package/bin/lib/resolve-bin.mjs +39 -0
- package/bin/lib/test/base-config.mjs +6 -3
- package/bin/lib/test/matchers.mjs +2 -2
- package/bin/lib/test/test-config.mjs +19 -8
- package/bin/lib/test/test-fixtures.d.mts +52 -92
- package/bin/lib/test/test-fixtures.mjs +174 -147
- package/dist/chatgpt/index.cjs +1 -1
- package/dist/chatgpt/index.js +1 -1
- package/dist/claude/index.cjs +1 -1
- package/dist/claude/index.js +1 -1
- package/dist/host/chatgpt/index.cjs +1 -1
- package/dist/host/chatgpt/index.js +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/inspector/index.cjs +1 -1
- package/dist/inspector/index.js +1 -1
- package/dist/{inspector-D5DckQuU.js → inspector-BBDa5yCm.js} +57 -23
- package/dist/inspector-BBDa5yCm.js.map +1 -0
- package/dist/{inspector-jY9O18z9.cjs → inspector-DAA1Wiyh.cjs} +58 -24
- package/dist/inspector-DAA1Wiyh.cjs.map +1 -0
- package/dist/lib/discovery-cli.cjs +1 -1
- package/dist/mcp/index.cjs +22 -25
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +19 -22
- package/dist/mcp/index.js.map +1 -1
- package/dist/{use-app-Bfargfa3.js → use-app-Cr0auUa1.js} +2 -2
- package/dist/{use-app-Bfargfa3.js.map → use-app-Cr0auUa1.js.map} +1 -1
- package/dist/{use-app-CbsBEmwv.cjs → use-app-DPkj5Jp_.cjs} +2 -2
- package/dist/{use-app-CbsBEmwv.cjs.map → use-app-DPkj5Jp_.cjs.map} +1 -1
- package/package.json +17 -11
- package/template/dist/albums/albums.html +4 -4
- package/template/dist/albums/albums.json +1 -1
- package/template/dist/carousel/carousel.html +4 -4
- package/template/dist/carousel/carousel.json +1 -1
- package/template/dist/map/map.html +6 -6
- package/template/dist/map/map.json +1 -1
- package/template/dist/review/review.html +4 -4
- package/template/dist/review/review.json +1 -1
- package/template/node_modules/.bin/vite +2 -2
- package/template/node_modules/.bin/vitest +2 -2
- package/template/node_modules/.vite/deps/_metadata.json +4 -4
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js +1 -1
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js +1 -1
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js +1 -1
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/@testing-library_react.js +4 -4
- package/template/node_modules/.vite-mcp/deps/@testing-library_react.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/_metadata.json +33 -33
- package/template/node_modules/.vite-mcp/deps/{client-CU1wWud4.js → client-B_5CX--u.js} +7 -7
- package/template/node_modules/.vite-mcp/deps/{client-CU1wWud4.js.map → client-B_5CX--u.js.map} +1 -1
- package/template/node_modules/.vite-mcp/deps/embla-carousel-react.js +1 -1
- package/template/node_modules/.vite-mcp/deps/embla-carousel-react.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/react-dom.js +3 -3
- package/template/node_modules/.vite-mcp/deps/react-dom.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/react-dom_client.js +1 -1
- package/template/node_modules/.vite-mcp/deps/react.js +3 -3
- package/template/node_modules/.vite-mcp/deps/react.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/react_jsx-dev-runtime.js +2 -2
- package/template/node_modules/.vite-mcp/deps/react_jsx-dev-runtime.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/react_jsx-runtime.js +2 -2
- package/template/node_modules/.vite-mcp/deps/react_jsx-runtime.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/vitest.js +1024 -622
- package/template/node_modules/.vite-mcp/deps/vitest.js.map +1 -1
- package/template/package.json +6 -6
- package/template/tests/e2e/albums.spec.ts +24 -52
- package/template/tests/e2e/carousel.spec.ts +36 -58
- package/template/tests/e2e/map.spec.ts +35 -56
- package/template/tests/e2e/review.spec.ts +56 -85
- package/template/tests/e2e/visual.spec.ts +14 -12
- package/dist/inspector-D5DckQuU.js.map +0 -1
- package/dist/inspector-jY9O18z9.cjs.map +0 -1
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Playwright fixtures for testing MCP servers.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Two fixtures, cleanly separated:
|
|
5
|
+
* - `mcp` — MCP protocol primitives (callTool, listTools, listResources, readResource)
|
|
6
|
+
* - `inspector` — sunpeak inspector for rendering and visual testing (renderTool, host)
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* import { test, expect } from 'sunpeak/test';
|
|
10
10
|
*
|
|
11
|
-
* test('
|
|
12
|
-
* const
|
|
13
|
-
*
|
|
14
|
-
* expect(result).
|
|
11
|
+
* test('protocol test', async ({ mcp }) => {
|
|
12
|
+
* const tools = await mcp.listTools();
|
|
13
|
+
* const result = await mcp.callTool('search', { query: 'headphones' });
|
|
14
|
+
* expect(result.isError).toBeFalsy();
|
|
15
|
+
* });
|
|
15
16
|
*
|
|
16
|
-
*
|
|
17
|
-
* await
|
|
17
|
+
* test('UI test', async ({ inspector }) => {
|
|
18
|
+
* const result = await inspector.renderTool('search', { query: 'headphones' });
|
|
19
|
+
* expect(result).not.toBeError();
|
|
20
|
+
* await expect(result.app().getByText('headphones')).toBeVisible();
|
|
21
|
+
* await result.screenshot('search-results');
|
|
18
22
|
* });
|
|
19
23
|
*/
|
|
20
24
|
import { resolvePlaywrightESM } from '../live/utils.mjs';
|
|
@@ -26,10 +30,8 @@ const { test: base, expect } = await resolvePlaywrightESM(projectRoot);
|
|
|
26
30
|
// Register MCP-native matchers
|
|
27
31
|
registerMatchers(expect);
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
* Inlined to avoid importing from dist (which pulls in React).
|
|
32
|
-
*/
|
|
33
|
+
// ── Helpers ──
|
|
34
|
+
|
|
33
35
|
function buildInspectorUrl(params) {
|
|
34
36
|
const sp = new URLSearchParams();
|
|
35
37
|
for (const [key, value] of Object.entries(params)) {
|
|
@@ -37,15 +39,11 @@ function buildInspectorUrl(params) {
|
|
|
37
39
|
sp.set(key, String(value));
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
|
-
// Always disable dev overlay in tests
|
|
41
42
|
sp.set('devOverlay', 'false');
|
|
42
43
|
const qs = sp.toString();
|
|
43
44
|
return qs ? `/?${qs}` : '/';
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
/**
|
|
47
|
-
* Resolve the host ID from the Playwright project name.
|
|
48
|
-
*/
|
|
49
47
|
function resolveHostId(projectName) {
|
|
50
48
|
if (!projectName) return 'chatgpt';
|
|
51
49
|
if (projectName.startsWith('chatgpt')) return 'chatgpt';
|
|
@@ -53,57 +51,186 @@ function resolveHostId(projectName) {
|
|
|
53
51
|
return projectName;
|
|
54
52
|
}
|
|
55
53
|
|
|
54
|
+
async function fetchJson(page, path) {
|
|
55
|
+
const baseURL = page.context()._options?.baseURL || '';
|
|
56
|
+
const response = await page.request.get(`${baseURL}${path}`);
|
|
57
|
+
if (!response.ok()) {
|
|
58
|
+
throw new Error(`${path} returned ${response.status()}: ${await response.text()}`);
|
|
59
|
+
}
|
|
60
|
+
return response.json();
|
|
61
|
+
}
|
|
62
|
+
|
|
56
63
|
/**
|
|
57
|
-
*
|
|
64
|
+
* Read the tool result from the inspector's <script id="__tool-result"> element.
|
|
58
65
|
*/
|
|
59
|
-
function
|
|
66
|
+
async function readToolResult(page, timeout) {
|
|
67
|
+
try {
|
|
68
|
+
const script = page.locator('#__tool-result');
|
|
69
|
+
await script.waitFor({ state: 'attached', timeout: Math.min(timeout, 5_000) });
|
|
70
|
+
const json = await script.evaluate(
|
|
71
|
+
(el, t) =>
|
|
72
|
+
new Promise((resolve) => {
|
|
73
|
+
const check = () => {
|
|
74
|
+
const text = el.textContent?.trim();
|
|
75
|
+
if (text && text !== 'null') return resolve(text);
|
|
76
|
+
let timer;
|
|
77
|
+
const observer = new MutationObserver(() => {
|
|
78
|
+
const updated = el.textContent?.trim();
|
|
79
|
+
if (updated && updated !== 'null') {
|
|
80
|
+
observer.disconnect();
|
|
81
|
+
clearTimeout(timer);
|
|
82
|
+
resolve(updated);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
observer.observe(el, { childList: true, characterData: true, subtree: true });
|
|
86
|
+
timer = setTimeout(() => { observer.disconnect(); resolve(null); }, t);
|
|
87
|
+
};
|
|
88
|
+
check();
|
|
89
|
+
}),
|
|
90
|
+
Math.min(timeout, 10_000)
|
|
91
|
+
);
|
|
92
|
+
if (json) {
|
|
93
|
+
const parsed = JSON.parse(json);
|
|
94
|
+
return {
|
|
95
|
+
content: parsed?.content || [],
|
|
96
|
+
structuredContent: parsed?.structuredContent,
|
|
97
|
+
isError: parsed?.isError || false,
|
|
98
|
+
source: parsed?.source || 'server',
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
// Fall back to empty
|
|
103
|
+
}
|
|
104
|
+
return { content: [], structuredContent: undefined, isError: false, source: 'server' };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Create an InspectorResult from the rendered state.
|
|
109
|
+
*/
|
|
110
|
+
function createInspectorResult(page, resultData) {
|
|
60
111
|
return {
|
|
61
112
|
content: resultData?.content || [],
|
|
62
113
|
structuredContent: resultData?.structuredContent,
|
|
63
114
|
isError: resultData?.isError || false,
|
|
115
|
+
source: resultData?.source || 'server',
|
|
64
116
|
|
|
65
|
-
/**
|
|
66
|
-
* Get a FrameLocator for the rendered resource UI.
|
|
67
|
-
* Handles the double-iframe traversal (outer sandbox proxy + inner app).
|
|
68
|
-
* Returns the locator regardless — Playwright will throw with a clear
|
|
69
|
-
* error if no iframe exists when you interact with it.
|
|
70
|
-
*/
|
|
117
|
+
/** Get a FrameLocator for the rendered resource UI (handles double-iframe). */
|
|
71
118
|
app() {
|
|
72
119
|
return page.frameLocator('iframe').frameLocator('iframe');
|
|
73
120
|
},
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Take a screenshot and compare against a baseline.
|
|
124
|
+
* Only runs when visual testing is enabled (`sunpeak test --visual`).
|
|
125
|
+
* Silently skips otherwise.
|
|
126
|
+
*
|
|
127
|
+
* @param {string} [name] - Snapshot name (auto-generated if omitted)
|
|
128
|
+
* @param {Object} [options] - Playwright toHaveScreenshot options
|
|
129
|
+
*/
|
|
130
|
+
async screenshot(name, options = {}) {
|
|
131
|
+
if (process.env.SUNPEAK_VISUAL !== 'true') return;
|
|
132
|
+
|
|
133
|
+
if (typeof name === 'object' && name !== null) {
|
|
134
|
+
options = name;
|
|
135
|
+
name = undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const { target = 'app', element, ...playwrightOptions } = options;
|
|
139
|
+
let locator;
|
|
140
|
+
if (element) {
|
|
141
|
+
locator = element;
|
|
142
|
+
} else if (target === 'page') {
|
|
143
|
+
locator = page.locator('#root');
|
|
144
|
+
} else {
|
|
145
|
+
locator = page.frameLocator('iframe').frameLocator('iframe').locator('body');
|
|
146
|
+
}
|
|
147
|
+
const fullName = name && !name.endsWith('.png') ? `${name}.png` : name;
|
|
148
|
+
const args = fullName ? [fullName, playwrightOptions] : [playwrightOptions];
|
|
149
|
+
await expect(locator).toHaveScreenshot(...args);
|
|
150
|
+
},
|
|
74
151
|
};
|
|
75
152
|
}
|
|
76
153
|
|
|
154
|
+
// ── Fixtures ──
|
|
155
|
+
|
|
77
156
|
const test = base.extend({
|
|
78
|
-
|
|
157
|
+
/**
|
|
158
|
+
* MCP protocol fixture. Maps 1:1 to MCP protocol operations.
|
|
159
|
+
* No rendering, no inspector UI, no sunpeak concepts.
|
|
160
|
+
*/
|
|
161
|
+
mcp: async ({ page }, use) => {
|
|
162
|
+
const fixture = {
|
|
163
|
+
async listTools() {
|
|
164
|
+
const result = await fetchJson(page, '/__sunpeak/list-tools');
|
|
165
|
+
return result.tools || [];
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
async callTool(name, input) {
|
|
169
|
+
const baseURL = page.context()._options?.baseURL || '';
|
|
170
|
+
const response = await page.request.post(`${baseURL}/__sunpeak/call-tool`, {
|
|
171
|
+
data: { name, arguments: input || {} },
|
|
172
|
+
});
|
|
173
|
+
if (!response.ok()) {
|
|
174
|
+
throw new Error(`callTool(${name}) returned ${response.status()}: ${await response.text()}`);
|
|
175
|
+
}
|
|
176
|
+
return response.json();
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
async listResources() {
|
|
180
|
+
const result = await fetchJson(page, '/__sunpeak/list-resources');
|
|
181
|
+
return result.resources || [];
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
async readResource(uri) {
|
|
185
|
+
const baseURL = page.context()._options?.baseURL || '';
|
|
186
|
+
const response = await page.request.get(
|
|
187
|
+
`${baseURL}/__sunpeak/read-resource?uri=${encodeURIComponent(uri)}`
|
|
188
|
+
);
|
|
189
|
+
if (!response.ok()) {
|
|
190
|
+
throw new Error(`readResource(${uri}) returned ${response.status()}: ${await response.text()}`);
|
|
191
|
+
}
|
|
192
|
+
return response.text();
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
await use(fixture);
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* sunpeak inspector fixture. Renders tools in simulated host environments.
|
|
201
|
+
* Built on top of the inspector, not the MCP protocol.
|
|
202
|
+
*/
|
|
203
|
+
inspector: async ({ page }, use, testInfo) => {
|
|
79
204
|
const host = resolveHostId(testInfo.project.name);
|
|
80
205
|
|
|
81
206
|
const fixture = {
|
|
82
|
-
|
|
207
|
+
/** Current host ID ('chatgpt' or 'claude') from Playwright project. */
|
|
83
208
|
host,
|
|
84
209
|
|
|
210
|
+
/** The underlying Playwright Page (for advanced assertions). */
|
|
211
|
+
page,
|
|
212
|
+
|
|
85
213
|
/**
|
|
86
|
-
*
|
|
214
|
+
* Render a tool in the inspector and return the result.
|
|
87
215
|
*
|
|
88
|
-
*
|
|
89
|
-
* fixture data
|
|
90
|
-
* For external servers: navigates to the matching simulation created by
|
|
91
|
-
* inspectServer from discovered tools.
|
|
216
|
+
* With `input`, the tool is called on the real server (bypasses fixtures).
|
|
217
|
+
* Without `input`, simulation fixture data is used when available.
|
|
92
218
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* data provides the tool input for rendering.
|
|
96
|
-
*
|
|
97
|
-
* @param {string} name - Tool/simulation name (e.g., 'show-albums')
|
|
98
|
-
* @param {Record<string, unknown>} [_input] - Reserved for future use
|
|
219
|
+
* @param {string} name - Tool name
|
|
220
|
+
* @param {Record<string, unknown>} [input] - Tool arguments (real server call)
|
|
99
221
|
* @param {Object} [options] - Display options
|
|
100
|
-
* @
|
|
222
|
+
* @param {'light' | 'dark'} [options.theme]
|
|
223
|
+
* @param {'inline' | 'pip' | 'fullscreen'} [options.displayMode]
|
|
224
|
+
* @param {number} [options.timeout] - Timeout in ms (default: 15s or mcpTimeout from config)
|
|
225
|
+
* @returns {Promise<InspectorResult>}
|
|
101
226
|
*/
|
|
102
|
-
async
|
|
103
|
-
const { theme, displayMode, ...rest } = options;
|
|
227
|
+
async renderTool(name, input, options = {}) {
|
|
228
|
+
const { theme, displayMode, timeout: callTimeout, ...rest } = options;
|
|
104
229
|
|
|
230
|
+
const hasInput = input != null && Object.keys(input).length > 0;
|
|
105
231
|
const params = {
|
|
106
|
-
simulation: name,
|
|
232
|
+
...(hasInput ? { tool: name, toolInput: JSON.stringify(input) } : { simulation: name }),
|
|
233
|
+
autoRun: 'true',
|
|
107
234
|
host,
|
|
108
235
|
...(theme && { theme }),
|
|
109
236
|
...(displayMode && { displayMode }),
|
|
@@ -112,116 +239,16 @@ const test = base.extend({
|
|
|
112
239
|
|
|
113
240
|
await page.goto(buildInspectorUrl(params));
|
|
114
241
|
|
|
115
|
-
|
|
242
|
+
const resolvedTimeout = callTimeout ?? testInfo.project.use?.mcpTimeout ?? 15_000;
|
|
116
243
|
try {
|
|
117
244
|
const frame = page.frameLocator('iframe').frameLocator('iframe');
|
|
118
|
-
await frame.locator('body').waitFor({ state: 'attached', timeout:
|
|
245
|
+
await frame.locator('body').waitFor({ state: 'attached', timeout: resolvedTimeout });
|
|
119
246
|
} catch {
|
|
120
247
|
// Tool may not have a resource (no UI)
|
|
121
248
|
}
|
|
122
249
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
structuredContent: undefined,
|
|
126
|
-
isError: false,
|
|
127
|
-
});
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Navigate to a tool with no mock data ("Press Run" state).
|
|
132
|
-
* Use for testing the empty/loading state before a tool is executed.
|
|
133
|
-
*/
|
|
134
|
-
async openTool(name, options = {}) {
|
|
135
|
-
const { theme, ...rest } = options;
|
|
136
|
-
const params = {
|
|
137
|
-
tool: name,
|
|
138
|
-
host,
|
|
139
|
-
...(theme && { theme }),
|
|
140
|
-
...rest,
|
|
141
|
-
};
|
|
142
|
-
await page.goto(buildInspectorUrl(params));
|
|
143
|
-
await page.locator('#root').waitFor({ state: 'attached' });
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Click the Run button and wait for the resource to render.
|
|
148
|
-
* Use after openTool() in Prod Tools mode.
|
|
149
|
-
*/
|
|
150
|
-
async runTool() {
|
|
151
|
-
await page.locator('button:has-text("Run")').click();
|
|
152
|
-
await page.locator('iframe').waitFor({ state: 'attached', timeout: 30_000 });
|
|
153
|
-
return createToolResult(page, {
|
|
154
|
-
content: [],
|
|
155
|
-
structuredContent: undefined,
|
|
156
|
-
isError: false,
|
|
157
|
-
});
|
|
158
|
-
},
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Change the theme via the sidebar toggle.
|
|
162
|
-
*/
|
|
163
|
-
async setTheme(theme) {
|
|
164
|
-
const label = theme === 'light' ? 'Light' : 'Dark';
|
|
165
|
-
const button = page.locator(`button:has-text("${label}")`);
|
|
166
|
-
if (await button.isVisible().catch(() => false)) {
|
|
167
|
-
await button.click();
|
|
168
|
-
// Wait for theme to propagate to the iframe
|
|
169
|
-
await page.waitForTimeout(300);
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Change the display mode via the sidebar buttons.
|
|
175
|
-
*/
|
|
176
|
-
async setDisplayMode(mode) {
|
|
177
|
-
const labels = { inline: 'Inline', pip: 'PiP', fullscreen: 'Full' };
|
|
178
|
-
const label = labels[mode] || mode;
|
|
179
|
-
await page.locator(`button:has-text("${label}")`).click();
|
|
180
|
-
// Wait for display mode transition
|
|
181
|
-
await page.waitForTimeout(500);
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Take a screenshot and compare against a baseline.
|
|
186
|
-
* Only performs the comparison when visual testing is enabled
|
|
187
|
-
* (`sunpeak test --visual`). Silently skips otherwise, so tests
|
|
188
|
-
* that include screenshot() calls still pass during normal runs.
|
|
189
|
-
*
|
|
190
|
-
* Accepts all Playwright toHaveScreenshot() options (threshold,
|
|
191
|
-
* maxDiffPixelRatio, maxDiffPixels, mask, animations, caret,
|
|
192
|
-
* fullPage, clip, scale, stylePath, etc.) and passes them through.
|
|
193
|
-
*
|
|
194
|
-
* @param {string} [name] - Snapshot name (auto-generated from test title if omitted)
|
|
195
|
-
* @param {Object} [options] - Screenshot and comparison options
|
|
196
|
-
* @param {'app' | 'page'} [options.target='app'] - What to screenshot
|
|
197
|
-
* @param {import('@playwright/test').Locator} [options.element] - Specific locator to screenshot
|
|
198
|
-
*/
|
|
199
|
-
async screenshot(name, options = {}) {
|
|
200
|
-
if (process.env.SUNPEAK_VISUAL !== 'true') return;
|
|
201
|
-
|
|
202
|
-
// Support screenshot(options) without a name
|
|
203
|
-
if (typeof name === 'object' && name !== null) {
|
|
204
|
-
options = name;
|
|
205
|
-
name = undefined;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const { target = 'app', element, ...playwrightOptions } = options;
|
|
209
|
-
|
|
210
|
-
let locator;
|
|
211
|
-
if (element) {
|
|
212
|
-
locator = element;
|
|
213
|
-
} else if (target === 'page') {
|
|
214
|
-
locator = page.locator('#root');
|
|
215
|
-
} else {
|
|
216
|
-
locator = page.frameLocator('iframe').frameLocator('iframe').locator('body');
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const fullName = name && !name.endsWith('.png') ? `${name}.png` : name;
|
|
220
|
-
const args = fullName
|
|
221
|
-
? [fullName, playwrightOptions]
|
|
222
|
-
: [playwrightOptions];
|
|
223
|
-
|
|
224
|
-
await expect(locator).toHaveScreenshot(...args);
|
|
250
|
+
const resultData = await readToolResult(page, resolvedTimeout);
|
|
251
|
+
return createInspectorResult(page, resultData);
|
|
225
252
|
},
|
|
226
253
|
};
|
|
227
254
|
|
package/dist/chatgpt/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("../chunk-9hOWP6kD.cjs");
|
|
3
|
-
const require_inspector = require("../inspector-
|
|
3
|
+
const require_inspector = require("../inspector-DAA1Wiyh.cjs");
|
|
4
4
|
const require_inspector_url = require("../inspector-url-C3LTKgXt.cjs");
|
|
5
5
|
const require_discovery = require("../discovery-Clu4uHp1.cjs");
|
|
6
6
|
//#region src/chatgpt/index.ts
|
package/dist/chatgpt/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as __exportAll } from "../chunk-D6g4UhsZ.js";
|
|
2
|
-
import { _ as McpAppHost, d as ThemeProvider, f as useThemeContext, g as extractResourceCSP, h as IframeResource, n as resolveServerToolResult, t as Inspector, v as SCREEN_WIDTHS } from "../inspector-
|
|
2
|
+
import { _ as McpAppHost, d as ThemeProvider, f as useThemeContext, g as extractResourceCSP, h as IframeResource, n as resolveServerToolResult, t as Inspector, v as SCREEN_WIDTHS } from "../inspector-BBDa5yCm.js";
|
|
3
3
|
import { t as createInspectorUrl } from "../inspector-url-CyQcuBI9.js";
|
|
4
4
|
import { c as toPascalCase, i as findResourceKey, n as extractSimulationKey, r as findResourceDirs, s as getComponentName, t as extractResourceKey } from "../discovery-Cgoegt62.js";
|
|
5
5
|
//#region src/chatgpt/index.ts
|
package/dist/claude/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../chunk-9hOWP6kD.cjs");
|
|
3
|
-
const require_inspector = require("../inspector-
|
|
3
|
+
const require_inspector = require("../inspector-DAA1Wiyh.cjs");
|
|
4
4
|
exports.Inspector = require_inspector.Inspector;
|
package/dist/claude/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as Inspector } from "../inspector-
|
|
1
|
+
import { t as Inspector } from "../inspector-BBDa5yCm.js";
|
|
2
2
|
export { Inspector };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../../chunk-9hOWP6kD.cjs");
|
|
3
|
-
const require_use_app = require("../../use-app-
|
|
3
|
+
const require_use_app = require("../../use-app-DPkj5Jp_.cjs");
|
|
4
4
|
let react = require("react");
|
|
5
5
|
//#region src/host/chatgpt/openai-types.ts
|
|
6
6
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("./chunk-9hOWP6kD.cjs");
|
|
3
3
|
const require_protocol = require("./protocol-C8pFDmcy.cjs");
|
|
4
|
-
const require_use_app = require("./use-app-
|
|
5
|
-
const require_inspector = require("./inspector-
|
|
4
|
+
const require_use_app = require("./use-app-DPkj5Jp_.cjs");
|
|
5
|
+
const require_inspector = require("./inspector-DAA1Wiyh.cjs");
|
|
6
6
|
const require_host_index = require("./host/index.cjs");
|
|
7
7
|
const require_inspector_index = require("./inspector/index.cjs");
|
|
8
8
|
const require_chatgpt_index = require("./chatgpt/index.cjs");
|
|
9
9
|
let react = require("react");
|
|
10
|
-
react = require_chunk.__toESM(react);
|
|
10
|
+
react = require_chunk.__toESM(react, 1);
|
|
11
11
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
12
|
-
//#region ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.5.0_@modelcontextprotocol+sdk@1.29.0_zod@4.3.6__react-
|
|
12
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.5.0_@modelcontextprotocol+sdk@1.29.0_zod@4.3.6__react-_a8a8e071c354e7dd6f62871eadf46f99/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.js
|
|
13
13
|
var m = require_protocol.union([require_protocol.literal("light"), require_protocol.literal("dark")]).describe("Color theme preference for the host environment."), N$1 = require_protocol.union([
|
|
14
14
|
require_protocol.literal("inline"),
|
|
15
15
|
require_protocol.literal("fullscreen"),
|