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.
Files changed (85) hide show
  1. package/README.md +2 -2
  2. package/bin/commands/inspect.mjs +361 -12
  3. package/bin/commands/test-init.mjs +190 -118
  4. package/bin/commands/test.mjs +12 -1
  5. package/bin/lib/eval/eval-runner.mjs +7 -1
  6. package/bin/lib/inspect/inspect-config.mjs +17 -2
  7. package/bin/lib/inspect/inspect-server.d.mts +32 -0
  8. package/bin/lib/inspect/inspect-server.mjs +11 -0
  9. package/bin/lib/live/live-config.d.mts +10 -0
  10. package/bin/lib/live/live-config.mjs +34 -2
  11. package/bin/lib/resolve-bin.mjs +39 -0
  12. package/bin/lib/test/base-config.mjs +6 -3
  13. package/bin/lib/test/matchers.mjs +2 -2
  14. package/bin/lib/test/test-config.mjs +19 -8
  15. package/bin/lib/test/test-fixtures.d.mts +52 -92
  16. package/bin/lib/test/test-fixtures.mjs +174 -147
  17. package/dist/chatgpt/index.cjs +1 -1
  18. package/dist/chatgpt/index.js +1 -1
  19. package/dist/claude/index.cjs +1 -1
  20. package/dist/claude/index.js +1 -1
  21. package/dist/host/chatgpt/index.cjs +1 -1
  22. package/dist/host/chatgpt/index.js +1 -1
  23. package/dist/index.cjs +4 -4
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.js +3 -3
  26. package/dist/index.js.map +1 -1
  27. package/dist/inspector/index.cjs +1 -1
  28. package/dist/inspector/index.js +1 -1
  29. package/dist/{inspector-D5DckQuU.js → inspector-BBDa5yCm.js} +57 -23
  30. package/dist/inspector-BBDa5yCm.js.map +1 -0
  31. package/dist/{inspector-jY9O18z9.cjs → inspector-DAA1Wiyh.cjs} +58 -24
  32. package/dist/inspector-DAA1Wiyh.cjs.map +1 -0
  33. package/dist/lib/discovery-cli.cjs +1 -1
  34. package/dist/mcp/index.cjs +22 -25
  35. package/dist/mcp/index.cjs.map +1 -1
  36. package/dist/mcp/index.js +19 -22
  37. package/dist/mcp/index.js.map +1 -1
  38. package/dist/{use-app-Bfargfa3.js → use-app-Cr0auUa1.js} +2 -2
  39. package/dist/{use-app-Bfargfa3.js.map → use-app-Cr0auUa1.js.map} +1 -1
  40. package/dist/{use-app-CbsBEmwv.cjs → use-app-DPkj5Jp_.cjs} +2 -2
  41. package/dist/{use-app-CbsBEmwv.cjs.map → use-app-DPkj5Jp_.cjs.map} +1 -1
  42. package/package.json +17 -11
  43. package/template/dist/albums/albums.html +4 -4
  44. package/template/dist/albums/albums.json +1 -1
  45. package/template/dist/carousel/carousel.html +4 -4
  46. package/template/dist/carousel/carousel.json +1 -1
  47. package/template/dist/map/map.html +6 -6
  48. package/template/dist/map/map.json +1 -1
  49. package/template/dist/review/review.html +4 -4
  50. package/template/dist/review/review.json +1 -1
  51. package/template/node_modules/.bin/vite +2 -2
  52. package/template/node_modules/.bin/vitest +2 -2
  53. package/template/node_modules/.vite/deps/_metadata.json +4 -4
  54. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js +1 -1
  55. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js.map +1 -1
  56. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js +1 -1
  57. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js.map +1 -1
  58. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js +1 -1
  59. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js.map +1 -1
  60. package/template/node_modules/.vite-mcp/deps/@testing-library_react.js +4 -4
  61. package/template/node_modules/.vite-mcp/deps/@testing-library_react.js.map +1 -1
  62. package/template/node_modules/.vite-mcp/deps/_metadata.json +33 -33
  63. package/template/node_modules/.vite-mcp/deps/{client-CU1wWud4.js → client-B_5CX--u.js} +7 -7
  64. package/template/node_modules/.vite-mcp/deps/{client-CU1wWud4.js.map → client-B_5CX--u.js.map} +1 -1
  65. package/template/node_modules/.vite-mcp/deps/embla-carousel-react.js +1 -1
  66. package/template/node_modules/.vite-mcp/deps/embla-carousel-react.js.map +1 -1
  67. package/template/node_modules/.vite-mcp/deps/react-dom.js +3 -3
  68. package/template/node_modules/.vite-mcp/deps/react-dom.js.map +1 -1
  69. package/template/node_modules/.vite-mcp/deps/react-dom_client.js +1 -1
  70. package/template/node_modules/.vite-mcp/deps/react.js +3 -3
  71. package/template/node_modules/.vite-mcp/deps/react.js.map +1 -1
  72. package/template/node_modules/.vite-mcp/deps/react_jsx-dev-runtime.js +2 -2
  73. package/template/node_modules/.vite-mcp/deps/react_jsx-dev-runtime.js.map +1 -1
  74. package/template/node_modules/.vite-mcp/deps/react_jsx-runtime.js +2 -2
  75. package/template/node_modules/.vite-mcp/deps/react_jsx-runtime.js.map +1 -1
  76. package/template/node_modules/.vite-mcp/deps/vitest.js +1024 -622
  77. package/template/node_modules/.vite-mcp/deps/vitest.js.map +1 -1
  78. package/template/package.json +6 -6
  79. package/template/tests/e2e/albums.spec.ts +24 -52
  80. package/template/tests/e2e/carousel.spec.ts +36 -58
  81. package/template/tests/e2e/map.spec.ts +35 -56
  82. package/template/tests/e2e/review.spec.ts +56 -85
  83. package/template/tests/e2e/visual.spec.ts +14 -12
  84. package/dist/inspector-D5DckQuU.js.map +0 -1
  85. package/dist/inspector-jY9O18z9.cjs.map +0 -1
@@ -11,6 +11,7 @@ import { join, dirname } from 'path';
11
11
  import { fileURLToPath } from 'url';
12
12
  import { ANTI_BOT_ARGS, CHROME_USER_AGENT } from './utils.mjs';
13
13
  import { getPortSync } from '../get-port.mjs';
14
+ import { resolveSunpeakBin } from '../resolve-bin.mjs';
14
15
 
15
16
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
17
  const GLOBAL_SETUP_PATH = join(__dirname, 'global-setup.mjs');
@@ -34,6 +35,10 @@ const GLOBAL_SETUP_PATH = join(__dirname, 'global-setup.mjs');
34
35
  * @param {string[]} [options.permissions] - Browser permissions to grant (e.g., ['geolocation'])
35
36
  * @param {boolean} [options.devOverlay=true] - Show the dev overlay (resource timestamp + tool timing) in resources
36
37
  * @param {Object} [options.use] - Additional Playwright `use` options (merged with defaults)
38
+ * @param {Object} [options.server] - External MCP server config (omit for sunpeak projects)
39
+ * @param {string} [options.server.url] - Server URL (e.g., 'http://localhost:8000/mcp')
40
+ * @param {string} [options.server.command] - Server start command
41
+ * @param {string[]} [options.server.args] - Command arguments
37
42
  */
38
43
  export function createLiveConfig(hostOptions, options = {}) {
39
44
  const { hostId, authFileName } = hostOptions;
@@ -49,6 +54,7 @@ export function createLiveConfig(hostOptions, options = {}) {
49
54
  geolocation,
50
55
  permissions,
51
56
  use: userUse,
57
+ server,
52
58
  } = options;
53
59
 
54
60
  const resolvedAuthDir = authDir || join(testDir, '.auth');
@@ -91,10 +97,36 @@ export function createLiveConfig(hostOptions, options = {}) {
91
97
  },
92
98
  ],
93
99
  webServer: {
94
- command: `SUNPEAK_LIVE_TEST=1 SUNPEAK_SANDBOX_PORT=${getPortSync(24680)}${devOverlay ? '' : ' SUNPEAK_DEV_OVERLAY=false'} pnpm dev -- --prod-resources --port ${vitePort}`,
95
- url: `http://localhost:${vitePort}/health`,
100
+ command: buildLiveWebServerCommand({ server, vitePort, devOverlay }),
101
+ url: `http://127.0.0.1:${vitePort}/health`,
96
102
  reuseExistingServer: !process.env.CI,
97
103
  timeout: 60_000,
98
104
  },
99
105
  };
100
106
  }
107
+
108
+ /**
109
+ * Build the webServer command for live tests.
110
+ * Uses `sunpeak inspect` for external servers, `pnpm dev` for sunpeak projects.
111
+ */
112
+ function buildLiveWebServerCommand({ server, vitePort, devOverlay }) {
113
+ const sandboxPort = getPortSync(24680);
114
+ const envPrefix = `SUNPEAK_LIVE_TEST=1 SUNPEAK_SANDBOX_PORT=${sandboxPort}${devOverlay ? '' : ' SUNPEAK_DEV_OVERLAY=false'}`;
115
+
116
+ if (server) {
117
+ // External MCP server — launch sunpeak inspect
118
+ const bin = resolveSunpeakBin();
119
+ if (server.url) {
120
+ return `${envPrefix} ${bin} inspect --server ${server.url} --port ${vitePort}`;
121
+ }
122
+ if (server.command) {
123
+ const cmd = server.args
124
+ ? `${server.command} ${server.args.join(' ')}`
125
+ : server.command;
126
+ return `${envPrefix} ${bin} inspect --server "${cmd}" --port ${vitePort}`;
127
+ }
128
+ }
129
+
130
+ // sunpeak framework project — use pnpm dev
131
+ return `${envPrefix} pnpm dev -- --prod-resources --port ${vitePort}`;
132
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Resolve the sunpeak CLI binary path.
3
+ *
4
+ * When sunpeak is installed as a local dependency (e.g., in tests/sunpeak/
5
+ * for non-JS projects), the bare `sunpeak` command won't be on PATH.
6
+ * This utility checks for the local .bin entry first, then falls back
7
+ * to the bare command name for global installs.
8
+ */
9
+ import { existsSync } from 'fs';
10
+ import { join, dirname } from 'path';
11
+ import { fileURLToPath } from 'url';
12
+
13
+ /**
14
+ * Find the sunpeak binary, preferring the local node_modules/.bin entry.
15
+ *
16
+ * Checks in order:
17
+ * 1. process.cwd() (works when running from the test directory directly)
18
+ * 2. The directory containing this file's package (works when the config is
19
+ * loaded from a parent directory, e.g., `sunpeak test` run from project root
20
+ * with config at tests/sunpeak/playwright.config.ts)
21
+ *
22
+ * @returns {string} Path to the sunpeak binary, or bare 'sunpeak' as fallback
23
+ */
24
+ export function resolveSunpeakBin() {
25
+ // Check cwd first (covers `cd tests/sunpeak && sunpeak test`)
26
+ const cwdBin = join(process.cwd(), 'node_modules', '.bin', 'sunpeak');
27
+ if (existsSync(cwdBin)) return cwdBin;
28
+
29
+ // Check the directory containing this module's package, which is the
30
+ // sunpeak package root. Walk up from bin/lib/ to find node_modules/.bin/.
31
+ // This covers running from a parent dir (e.g., project root) where sunpeak
32
+ // is installed in a subdirectory (tests/sunpeak/node_modules/sunpeak/).
33
+ const __dirname = dirname(fileURLToPath(import.meta.url));
34
+ const pkgRoot = join(__dirname, '..', '..');
35
+ const pkgBin = join(pkgRoot, '..', '.bin', 'sunpeak');
36
+ if (existsSync(pkgBin)) return pkgBin;
37
+
38
+ return 'sunpeak';
39
+ }
@@ -15,9 +15,10 @@ import { getPortSync } from '../get-port.mjs';
15
15
  * @param {number} options.port - Inspector port
16
16
  * @param {Object} [options.use] - Additional Playwright `use` options
17
17
  * @param {string} [options.globalSetup] - Global setup file path
18
+ * @param {number} [options.timeout] - WebServer startup timeout in ms (default: 60000)
18
19
  * @returns {import('@playwright/test').PlaywrightTestConfig}
19
20
  */
20
- export function createBaseConfig({ hosts, testDir, webServer, port, use, globalSetup, visual }) {
21
+ export function createBaseConfig({ hosts, testDir, webServer, port, use, globalSetup, visual, timeout }) {
21
22
  // Separate snapshot path from other visual options passed to expect.toHaveScreenshot
22
23
  const { snapshotPathTemplate, ...toHaveScreenshotDefaults } = visual ?? {};
23
24
 
@@ -43,7 +44,9 @@ export function createBaseConfig({ hosts, testDir, webServer, port, use, globalS
43
44
  ? { expect: { toHaveScreenshot: toHaveScreenshotDefaults } }
44
45
  : {}),
45
46
  use: {
46
- baseURL: `http://localhost:${port}`,
47
+ // Use 127.0.0.1 instead of localhost to avoid IPv4/IPv6 resolution
48
+ // ambiguity that causes ECONNREFUSED flakes on macOS.
49
+ baseURL: `http://127.0.0.1:${port}`,
47
50
  trace: 'on-first-retry',
48
51
  ...use,
49
52
  },
@@ -52,7 +55,7 @@ export function createBaseConfig({ hosts, testDir, webServer, port, use, globalS
52
55
  command: webServer.command,
53
56
  url: webServer.healthUrl,
54
57
  reuseExistingServer: !process.env.CI,
55
- timeout: 60_000,
58
+ timeout: timeout ?? 60_000,
56
59
  },
57
60
  };
58
61
  }
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * MCP-native custom matchers for Playwright's expect.
3
3
  *
4
- * These matchers operate on ToolResult objects returned by mcp.callTool()
5
- * and provide MCP-concept-native assertions.
4
+ * These matchers operate on tool results from mcp.callTool() or
5
+ * InspectorResult from inspector.renderTool().
6
6
  */
7
7
 
8
8
  /**
@@ -18,6 +18,7 @@
18
18
  import { existsSync, readFileSync } from 'fs';
19
19
  import { join } from 'path';
20
20
  import { createBaseConfig, resolvePorts } from './base-config.mjs';
21
+ import { resolveSunpeakBin } from '../resolve-bin.mjs';
21
22
 
22
23
  /**
23
24
  * @param {Object} [options]
@@ -26,11 +27,13 @@ import { createBaseConfig, resolvePorts } from './base-config.mjs';
26
27
  * @param {string[]} [options.server.args] - Command arguments
27
28
  * @param {string} [options.server.url] - HTTP server URL (alternative to command)
28
29
  * @param {Record<string, string>} [options.server.env] - Environment variables
30
+ * @param {string} [options.server.cwd] - Working directory for the server process
29
31
  * @param {string[]} [options.hosts] - Host shells to test (default: ['chatgpt', 'claude'])
30
32
  * @param {string} [options.testDir] - Test directory
31
33
  * @param {string} [options.simulationsDir] - Simulations directory for mock data
32
34
  * @param {string} [options.globalSetup] - Global setup file path
33
35
  * @param {Object} [options.use] - Additional Playwright `use` options
36
+ * @param {number} [options.timeout] - Server startup timeout in ms (default: 60000)
34
37
  * @returns {import('@playwright/test').PlaywrightTestConfig}
35
38
  */
36
39
  export function defineConfig(options = {}) {
@@ -42,6 +45,7 @@ export function defineConfig(options = {}) {
42
45
  globalSetup,
43
46
  use: userUse,
44
47
  visual,
48
+ timeout,
45
49
  } = options;
46
50
 
47
51
  const { port, sandboxPort } = resolvePorts();
@@ -69,9 +73,10 @@ export function defineConfig(options = {}) {
69
73
  use: userUse,
70
74
  globalSetup,
71
75
  visual,
76
+ timeout,
72
77
  webServer: {
73
78
  command,
74
- healthUrl: `http://localhost:${port}/health`,
79
+ healthUrl: `http://127.0.0.1:${port}/health`,
75
80
  },
76
81
  });
77
82
  }
@@ -97,13 +102,7 @@ function detectSunpeakProject() {
97
102
  function buildInspectCommand({ server, port, sandboxPort, simulationsDir }) {
98
103
  const parts = [`SUNPEAK_SANDBOX_PORT=${sandboxPort}`];
99
104
 
100
- if (server.env) {
101
- for (const [key, value] of Object.entries(server.env)) {
102
- parts.push(`${key}=${value}`);
103
- }
104
- }
105
-
106
- parts.push('sunpeak inspect');
105
+ parts.push(`${resolveSunpeakBin()} inspect`);
107
106
 
108
107
  if (server.url) {
109
108
  parts.push(`--server ${server.url}`);
@@ -115,6 +114,18 @@ function buildInspectCommand({ server, port, sandboxPort, simulationsDir }) {
115
114
  parts.push(`--server "${cmd}"`);
116
115
  }
117
116
 
117
+ // Pass environment variables as --env KEY=VALUE flags (stdio servers only).
118
+ if (server.env) {
119
+ for (const [key, value] of Object.entries(server.env)) {
120
+ const pair = `${key}=${value}`;
121
+ parts.push(pair.includes(' ') ? `--env "${pair}"` : `--env ${pair}`);
122
+ }
123
+ }
124
+
125
+ if (server.cwd) {
126
+ parts.push(server.cwd.includes(' ') ? `--cwd "${server.cwd}"` : `--cwd ${server.cwd}`);
127
+ }
128
+
118
129
  if (simulationsDir) {
119
130
  parts.push(`--simulations ${simulationsDir}`);
120
131
  }
@@ -7,46 +7,40 @@ import type {
7
7
  PageAssertionsToHaveScreenshotOptions,
8
8
  } from '@playwright/test';
9
9
 
10
- /**
11
- * Result from calling an MCP tool via the inspector.
12
- */
13
- export interface ToolResult {
14
- /** Raw MCP content items from the tool response. */
15
- content: Array<{ type: string; text?: string; [key: string]: unknown }>;
16
- /** Structured content from the tool response. */
10
+ // ── MCP Protocol Types ──
11
+
12
+ export interface Tool {
13
+ name: string;
14
+ description?: string;
15
+ inputSchema: Record<string, unknown>;
16
+ title?: string;
17
+ annotations?: Record<string, unknown>;
18
+ _meta?: Record<string, unknown>;
19
+ }
20
+
21
+ export interface Resource {
22
+ uri: string;
23
+ name: string;
24
+ mimeType?: string;
25
+ description?: string;
26
+ _meta?: Record<string, unknown>;
27
+ }
28
+
29
+ export interface CallToolResult {
30
+ content?: Array<{ type: string; text?: string; [key: string]: unknown }>;
17
31
  structuredContent?: unknown;
18
- /** Whether the tool returned an error. */
19
- isError: boolean;
20
- /**
21
- * Get a FrameLocator for the rendered resource UI.
22
- * Handles the double-iframe traversal automatically.
23
- */
24
- app(): FrameLocator;
32
+ isError?: boolean;
25
33
  }
26
34
 
27
- /**
28
- * Options for callTool().
29
- */
30
- export interface CallToolOptions {
31
- /** Color theme for the inspector. */
35
+ // ── sunpeak Inspector Types ──
36
+
37
+ export interface RenderToolOptions {
32
38
  theme?: 'light' | 'dark';
33
- /** Display mode for the resource. */
34
39
  displayMode?: 'inline' | 'pip' | 'fullscreen';
35
- /** Use production resource builds instead of HMR. */
36
- prodResources?: boolean;
37
- /** Additional inspector URL parameters. */
40
+ timeout?: number;
38
41
  [key: string]: unknown;
39
42
  }
40
43
 
41
- /**
42
- * Options for screenshot().
43
- *
44
- * Extends Playwright's toHaveScreenshot() options with sunpeak-specific
45
- * `target` and `element` fields. All standard Playwright options (threshold,
46
- * maxDiffPixelRatio, maxDiffPixels, mask, maskColor, animations, caret,
47
- * fullPage, clip, scale, stylePath, omitBackground, timeout, etc.)
48
- * are passed through directly.
49
- */
50
44
  export interface ScreenshotOptions extends PageAssertionsToHaveScreenshotOptions {
51
45
  /** What to screenshot: 'app' (inner iframe content) or 'page' (full inspector). Default: 'app'. */
52
46
  target?: 'app' | 'page';
@@ -54,76 +48,42 @@ export interface ScreenshotOptions extends PageAssertionsToHaveScreenshotOptions
54
48
  element?: Locator;
55
49
  }
56
50
 
57
- /**
58
- * MCP test fixture for testing MCP servers via the inspector.
59
- */
51
+ export interface InspectorResult {
52
+ content: Array<{ type: string; text?: string; [key: string]: unknown }>;
53
+ structuredContent?: unknown;
54
+ isError: boolean;
55
+ source: 'fixture' | 'server';
56
+ app(): FrameLocator;
57
+ screenshot(options?: ScreenshotOptions): Promise<void>;
58
+ screenshot(name?: string, options?: ScreenshotOptions): Promise<void>;
59
+ }
60
+
61
+ // ── Fixtures ──
62
+
63
+ /** MCP protocol fixture. Maps 1:1 to MCP protocol operations. */
60
64
  export interface McpFixture {
61
- /** The underlying Playwright Page. */
62
- page: Page;
63
- /** Current host ID (from Playwright project name). */
64
- host: string;
65
+ listTools(): Promise<Tool[]>;
66
+ callTool(name: string, input?: Record<string, unknown>): Promise<CallToolResult>;
67
+ listResources(): Promise<Resource[]>;
68
+ readResource(uri: string): Promise<string>;
69
+ }
65
70
 
66
- /**
67
- * Call a tool and get the rendered result.
68
- * Navigates the inspector, waits for the resource to render,
69
- * and returns a ToolResult for assertions.
70
- */
71
- callTool(
71
+ /** sunpeak inspector fixture. Renders tools in simulated host environments. */
72
+ export interface InspectorFixture {
73
+ host: string;
74
+ page: Page;
75
+ renderTool(
72
76
  name: string,
73
77
  input?: Record<string, unknown>,
74
- options?: CallToolOptions
75
- ): Promise<ToolResult>;
76
-
77
- /**
78
- * Navigate to a tool with no mock data ("Press Run" state).
79
- */
80
- openTool(name: string, options?: { theme?: 'light' | 'dark' }): Promise<void>;
81
-
82
- /**
83
- * Click the Run button and return the rendered result.
84
- */
85
- runTool(): Promise<ToolResult>;
86
-
87
- /** Change the theme via the sidebar toggle. */
88
- setTheme(theme: 'light' | 'dark'): Promise<void>;
89
-
90
- /** Change the display mode via the sidebar buttons. */
91
- setDisplayMode(mode: 'inline' | 'pip' | 'fullscreen'): Promise<void>;
92
-
93
- /**
94
- * Take a screenshot and compare against a baseline.
95
- * Only performs the comparison when visual testing is enabled
96
- * (`sunpeak test --visual`). Silently skips otherwise.
97
- *
98
- * @param name - Snapshot name (auto-generated from test title if omitted)
99
- * @param options - Screenshot and comparison options
100
- */
101
- screenshot(name?: string, options?: ScreenshotOptions): Promise<void>;
78
+ options?: RenderToolOptions
79
+ ): Promise<InspectorResult>;
102
80
  }
103
81
 
104
- /**
105
- * Extended Playwright test with `mcp` fixture.
106
- */
107
- export declare const test: TestType<{ mcp: McpFixture }, {}>;
82
+ export declare const test: TestType<{ mcp: McpFixture; inspector: InspectorFixture }, {}>;
108
83
 
109
- /**
110
- * Extended Playwright expect with MCP-native matchers.
111
- */
112
84
  export declare const expect: Expect<{
113
- /**
114
- * Assert that a tool result is an error.
115
- */
116
85
  toBeError(): void;
117
- /**
118
- * Assert that any content item's text contains the given string.
119
- */
120
86
  toHaveTextContent(text: string): void;
121
- /**
122
- * Assert that structuredContent matches the expected shape.
123
- */
124
87
  toHaveStructuredContent(shape: unknown): void;
125
- /**
126
- * Assert that content array contains an item of the given type.
127
- */
128
88
  toHaveContentType(type: string): void;
129
89
  }>;