@kkeve/suite 0.0.15 → 0.0.17

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 (115) hide show
  1. package/dist/bin/keve.js +2 -1
  2. package/dist/commands/clean.js +2 -2
  3. package/dist/commands/config.js +7 -7
  4. package/dist/commands/init.js +2 -2
  5. package/dist/commands/report.js +7 -7
  6. package/dist/commands/run.js +12 -11
  7. package/dist/commands/test.js +7 -7
  8. package/dist/config.js +7 -7
  9. package/dist/core/action-log-writer.js +4 -1
  10. package/dist/core/decorator/keve-decorators.d.ts +128 -0
  11. package/dist/core/decorator/keve-decorators.js +254 -0
  12. package/dist/core/decorator/keve-host.d.ts +40 -0
  13. package/dist/core/decorator/keve-host.js +33 -0
  14. package/dist/core/{keve-registry.d.ts → decorator/keve-registry.d.ts} +19 -0
  15. package/dist/core/{keve-registry.js → decorator/keve-registry.js} +13 -1
  16. package/dist/core/generateReport/report.d.ts +1 -1
  17. package/dist/core/generateReport/report.js +2 -2
  18. package/dist/core/generateReport/reportData.d.ts +3 -0
  19. package/dist/core/generateReport/reportData.js +49 -15
  20. package/dist/core/judge/confidence.d.ts +119 -0
  21. package/dist/core/judge/confidence.js +295 -0
  22. package/dist/core/judge/goal-heuristics.d.ts +32 -0
  23. package/dist/core/judge/goal-heuristics.js +128 -0
  24. package/dist/core/judge/pngCodec.d.ts +23 -0
  25. package/dist/core/judge/pngCodec.js +215 -0
  26. package/dist/core/judge/screenshotDiff.d.ts +112 -0
  27. package/dist/core/judge/screenshotDiff.js +420 -0
  28. package/dist/core/page-object/definePage.d.ts +95 -0
  29. package/dist/core/page-object/definePage.js +62 -0
  30. package/dist/core/page-object/elementResolver.d.ts +32 -0
  31. package/dist/core/page-object/elementResolver.js +236 -0
  32. package/dist/core/page-object/engine-types.d.ts +140 -0
  33. package/dist/core/page-object/engine-types.js +34 -0
  34. package/dist/core/sso-cookie.d.ts +18 -0
  35. package/dist/core/sso-cookie.js +10 -0
  36. package/dist/dsl/index.d.ts +15 -0
  37. package/dist/dsl/index.js +29 -0
  38. package/dist/dsl/locatorSource.d.ts +25 -0
  39. package/dist/dsl/locatorSource.js +323 -0
  40. package/dist/dsl/ops.d.ts +46 -0
  41. package/dist/dsl/ops.js +95 -0
  42. package/dist/dsl/toDecorator.d.ts +98 -0
  43. package/dist/dsl/toDecorator.js +747 -0
  44. package/dist/engine-cypress/adapter.d.ts +108 -0
  45. package/dist/engine-cypress/adapter.js +514 -0
  46. package/dist/engine-cypress/agent-page.d.ts +159 -0
  47. package/dist/engine-cypress/agent-page.js +566 -0
  48. package/dist/engine-cypress/agentDom.d.ts +22 -0
  49. package/dist/engine-cypress/agentDom.js +590 -0
  50. package/dist/engine-cypress/bridge.d.ts +39 -0
  51. package/dist/engine-cypress/bridge.js +598 -0
  52. package/dist/engine-cypress/cdp.d.ts +78 -0
  53. package/dist/engine-cypress/cdp.js +339 -0
  54. package/dist/engine-cypress/host.d.ts +22 -0
  55. package/dist/engine-cypress/host.js +480 -0
  56. package/dist/engine-cypress/index.d.ts +26 -0
  57. package/dist/engine-cypress/index.js +58 -0
  58. package/dist/engine-cypress/keveGoal.d.ts +43 -0
  59. package/dist/engine-cypress/keveGoal.js +265 -0
  60. package/dist/engine-cypress/pageOps.d.ts +41 -0
  61. package/dist/engine-cypress/pageOps.js +439 -0
  62. package/dist/engine-cypress/reporter.d.ts +20 -0
  63. package/dist/engine-cypress/reporter.js +128 -0
  64. package/dist/engine-cypress/setup.d.ts +21 -0
  65. package/dist/engine-cypress/setup.js +27 -0
  66. package/dist/engine-cypress/shotBuffer.d.ts +40 -0
  67. package/dist/engine-cypress/shotBuffer.js +41 -0
  68. package/dist/engine-cypress/state.d.ts +56 -0
  69. package/dist/engine-cypress/state.js +81 -0
  70. package/dist/engine-playwright/engineAdapter.d.ts +78 -0
  71. package/dist/engine-playwright/engineAdapter.js +371 -0
  72. package/dist/engine-playwright/global-setup.d.ts +28 -0
  73. package/dist/engine-playwright/global-setup.js +142 -0
  74. package/dist/{core → engine-playwright}/keve-report.d.ts +0 -1
  75. package/dist/engine-playwright/keve-report.js +137 -0
  76. package/dist/{core → engine-playwright}/keve-test.d.ts +10 -8
  77. package/dist/{core → engine-playwright}/keve-test.js +204 -200
  78. package/dist/{core → engine-playwright}/pw-config.js +8 -7
  79. package/dist/index.d.ts +13 -8
  80. package/dist/index.js +43 -28
  81. package/dist/page-agent/agent.d.ts +82 -7
  82. package/dist/page-agent/agent.js +252 -88
  83. package/dist/page-agent/diagnostics.d.ts +184 -0
  84. package/dist/page-agent/diagnostics.js +377 -0
  85. package/dist/page-agent/hooks.d.ts +3 -2
  86. package/dist/page-agent/hooks.js +4 -3
  87. package/dist/page-agent/page-like.d.ts +116 -0
  88. package/dist/page-agent/page-like.js +14 -0
  89. package/dist/page-agent/playwright-page.d.ts +20 -0
  90. package/dist/page-agent/playwright-page.js +98 -0
  91. package/dist/page-agent/system-prompt.d.ts +7 -0
  92. package/dist/page-agent/system-prompt.js +10 -0
  93. package/dist/page-agent/tools.d.ts +1 -1
  94. package/dist/page-agent/tools.js +144 -8
  95. package/package.json +24 -11
  96. package/scripts/gen-system-prompt.mjs +36 -0
  97. package/scripts/run-dsl-task.mjs +619 -0
  98. package/scripts/runtime/cypress-preprocessor.mjs +44 -0
  99. package/scripts/runtime/cypress.config.mjs +35 -0
  100. package/scripts/runtime/playwright.config.mjs +41 -0
  101. package/scripts/verify-shot-diff.mjs +243 -0
  102. package/dist/commands/auth-update.d.ts +0 -16
  103. package/dist/commands/auth-update.js +0 -88
  104. package/dist/core/auth.d.ts +0 -17
  105. package/dist/core/auth.js +0 -224
  106. package/dist/core/cdp-resolver.d.ts +0 -5
  107. package/dist/core/cdp-resolver.js +0 -93
  108. package/dist/core/global-setup.d.ts +0 -6
  109. package/dist/core/global-setup.js +0 -123
  110. package/dist/core/keve-decorators.d.ts +0 -51
  111. package/dist/core/keve-decorators.js +0 -95
  112. package/dist/core/keve-report.js +0 -376
  113. /package/dist/core/{keve-aspect.d.ts → decorator/keve-aspect.d.ts} +0 -0
  114. /package/dist/core/{keve-aspect.js → decorator/keve-aspect.js} +0 -0
  115. /package/dist/{core → engine-playwright}/pw-config.d.ts +0 -0
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * global-setup — 登录态装配(纯数据准备,不启动浏览器)
4
+ *
5
+ * 设计调整(与平台执行链路对齐):
6
+ * - 不再由测试侧启动 chromium,也不再通过 CDP 接管已开浏览器。
7
+ * - 登录态由**服务端**解析(eve-backend account-resolver → SSO cookies),
8
+ * 执行前以环境变量下发,这里只负责把 cookie 写成 Playwright storageState。
9
+ *
10
+ * 环境变量:
11
+ * KEVE_SSO_COOKIES — JSON 字符串化的 SsoCookie[](服务端解析结果,首选)
12
+ * KEVE_STORAGE_STATE — storageState 输出路径(默认 ./.auth/storage-state.json)
13
+ * KEVE_TARGET_URL — 目标站点 URL(用于派生 cookie domain,缺省 kuaishou.com)
14
+ *
15
+ * 兼容:KEVE_SSO_COOKIES_FILE 指向一个包含同样 JSON 的文件。
16
+ */
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.resolveStorageStatePath = resolveStorageStatePath;
52
+ exports.deriveCookieDomain = deriveCookieDomain;
53
+ exports.readInjectedCookies = readInjectedCookies;
54
+ exports.writeStorageState = writeStorageState;
55
+ exports.default = default_1;
56
+ const fs = __importStar(require("node:fs"));
57
+ const path = __importStar(require("node:path"));
58
+ /** 由 storageState 路径解析(默认 .auth/storage-state.json) */
59
+ function resolveStorageStatePath() {
60
+ return path.resolve(process.cwd(), process.env.KEVE_STORAGE_STATE || path.join('.auth', 'storage-state.json'));
61
+ }
62
+ /** 从 cookie 派生 Playwright cookie 所需的 domain / path */
63
+ function toPlaywrightCookie(cookie, fallbackDomain) {
64
+ const domain = cookie.domain || fallbackDomain;
65
+ return {
66
+ name: cookie.name,
67
+ value: cookie.value,
68
+ domain,
69
+ path: cookie.path || '/',
70
+ expires: typeof cookie.expires === 'number' ? cookie.expires : -1,
71
+ httpOnly: !!cookie.httpOnly,
72
+ secure: cookie.secure !== false,
73
+ sameSite: (cookie.sameSite || 'Lax'),
74
+ };
75
+ }
76
+ /** 目标站点派生 cookie domain:https://foo.kuaishou.com/x → .kuaishou.com */
77
+ function deriveCookieDomain(targetUrl) {
78
+ const fallback = '.kuaishou.com';
79
+ if (!targetUrl)
80
+ return fallback;
81
+ try {
82
+ const host = new URL(targetUrl).hostname;
83
+ const parts = host.split('.');
84
+ if (parts.length < 2)
85
+ return host;
86
+ return `.${parts.slice(-2).join('.')}`;
87
+ }
88
+ catch {
89
+ return fallback;
90
+ }
91
+ }
92
+ /** 读取服务端下发的 cookies(环境变量优先,其次文件) */
93
+ function readInjectedCookies() {
94
+ const raw = process.env.KEVE_SSO_COOKIES
95
+ || readCookieFile(process.env.KEVE_SSO_COOKIES_FILE);
96
+ if (!raw)
97
+ return [];
98
+ try {
99
+ const parsed = JSON.parse(raw);
100
+ return Array.isArray(parsed) ? parsed : [];
101
+ }
102
+ catch (err) {
103
+ console.warn(`[keve global-setup] KEVE_SSO_COOKIES 解析失败:${err?.message || err}`);
104
+ return [];
105
+ }
106
+ }
107
+ function readCookieFile(file) {
108
+ if (!file)
109
+ return '';
110
+ try {
111
+ return fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
112
+ }
113
+ catch {
114
+ return '';
115
+ }
116
+ }
117
+ /**
118
+ * 写出 storageState(只写文件,不启动浏览器)。
119
+ * 返回实际写入的 cookie 数,供执行侧日志/断言使用。
120
+ */
121
+ function writeStorageState(storageStatePath) {
122
+ const cookies = readInjectedCookies();
123
+ const domain = deriveCookieDomain(process.env.KEVE_TARGET_URL);
124
+ const state = {
125
+ cookies: cookies.map((c) => toPlaywrightCookie(c, domain)),
126
+ origins: [],
127
+ };
128
+ fs.mkdirSync(path.dirname(storageStatePath), { recursive: true });
129
+ fs.writeFileSync(storageStatePath, JSON.stringify(state, null, 2));
130
+ return state.cookies.length;
131
+ }
132
+ async function default_1() {
133
+ const storageStatePath = resolveStorageStatePath();
134
+ const count = writeStorageState(storageStatePath);
135
+ if (count > 0) {
136
+ console.log(`[keve global-setup] 注入服务端 cookies ${count} 条 → ${storageStatePath}`);
137
+ }
138
+ else {
139
+ console.warn(`[keve global-setup] 未收到服务端 cookies(KEVE_SSO_COOKIES 为空),`
140
+ + `写入空 storageState → ${storageStatePath}`);
141
+ }
142
+ }
@@ -19,7 +19,6 @@ declare class KeveReporter implements Reporter {
19
19
  private outputPath;
20
20
  private resultDir;
21
21
  onBegin(config: FullConfig, suite: Suite): void;
22
- private static CONFIDENCE_MAP;
23
22
  onTestEnd(test: TestCase, result: TestResult): Promise<void>;
24
23
  onEnd(result: FullResult): Promise<void>;
25
24
  private appendRecord;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ /**
3
+ * keve-report: Playwright Reporter that collects test execution data
4
+ *
5
+ * After EACH test completes (onTestEnd), records test result metadata
6
+ * including step results, error category, AI exploration steps, and diagnostics.
7
+ * Results are appended to confidence-data.jsonl (one line per test).
8
+ *
9
+ * After ALL tests complete (onEnd), generates report-data.json directly,
10
+ * eliminating the need for a separate `keve report` command.
11
+ *
12
+ * Usage in playwright config:
13
+ * reporter: [
14
+ * ['list'],
15
+ * ['@kkeve/suite/keve-report'],
16
+ * ]
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ const fs = __importStar(require("node:fs"));
53
+ const path = __importStar(require("node:path"));
54
+ const reportData_js_1 = require("../core/generateReport/reportData.js");
55
+ const confidence_js_1 = require("../core/judge/confidence.js");
56
+ class KeveReporter {
57
+ outputPath = '';
58
+ resultDir = '';
59
+ onBegin(config, suite) {
60
+ // Resolve resultDir: 优先 runner 注入的 KEVE_RESULT_DIR(<taskRoot>/reports/round-N),
61
+ // 缺失时回退旧布局 taskDir/test-artifacts/round-N。
62
+ const taskDir = process.env.KEVE_TASK_DIR || '.keve';
63
+ const round = process.env.KEVE_ROUND || 'latest';
64
+ this.resultDir = process.env.KEVE_RESULT_DIR
65
+ ? path.resolve(process.env.KEVE_RESULT_DIR)
66
+ : path.join(taskDir, 'test-artifacts', `round-${round}`);
67
+ this.outputPath = path.join(this.resultDir, 'confidence-data.jsonl');
68
+ if (!fs.existsSync(this.resultDir)) {
69
+ fs.mkdirSync(this.resultDir, { recursive: true });
70
+ }
71
+ console.log(`[keve-reporter] Confidence evaluation will be saved to: ${this.outputPath}`);
72
+ }
73
+ async onTestEnd(test, result) {
74
+ // 分类逻辑统一收敛在 core/confidence.ts,Cypress 侧复用同一实现,避免两端报告漂移
75
+ const { record, log } = (0, confidence_js_1.buildConfidenceRecord)({
76
+ title: test.title,
77
+ status: result.status,
78
+ error: result.error ? { message: result.error.message || String(result.error), name: result.error?.name } : null,
79
+ steps: (0, confidence_js_1.parseStepsFromAttachments)(result.attachments),
80
+ attachments: result.attachments,
81
+ });
82
+ this.appendRecord(record);
83
+ console.log(`[keve-reporter] ${test.title}: ${log}`);
84
+ }
85
+ async onEnd(result) {
86
+ console.log(`[keve-reporter] All tests completed. Generating report-data.json...`);
87
+ // ── 直接生成 report-data.json(不再需要 keve report 命令) ──
88
+ try {
89
+ const taskDir = process.env.KEVE_TASK_DIR || '.keve';
90
+ const projectRoot = taskDir;
91
+ // 找到 test-results.json(Playwright JSON Reporter 写入)
92
+ const testResultsPath = path.join(this.resultDir, 'test-results.json');
93
+ const confidencePath = this.outputPath;
94
+ if (fs.existsSync(testResultsPath) && fs.existsSync(confidencePath)) {
95
+ // YAML 用例文件在 {taskDir}/cases/test-cases.yaml
96
+ const casesYamlPath = path.join(taskDir, 'cases', 'test-cases.yaml');
97
+ const reportData = await (0, reportData_js_1.generateReportData)({
98
+ projectRoot,
99
+ resultsPath: testResultsPath,
100
+ confidencePath,
101
+ casesPath: fs.existsSync(casesYamlPath) ? casesYamlPath : undefined,
102
+ });
103
+ // 写入 report-data.json
104
+ const reportDataPath = path.join(this.resultDir, 'report-data.json');
105
+ fs.writeFileSync(reportDataPath, JSON.stringify(reportData, null, 2));
106
+ // 更新 latest 目录 → symlink 指向最新 round(避免重复拷贝 34MB+)
107
+ const latestDir = path.join(path.dirname(this.resultDir), 'latest');
108
+ if (latestDir !== this.resultDir) {
109
+ try {
110
+ if (fs.existsSync(latestDir)) {
111
+ const stat = fs.lstatSync(latestDir);
112
+ if (stat.isSymbolicLink()) {
113
+ fs.unlinkSync(latestDir);
114
+ }
115
+ else {
116
+ fs.rmSync(latestDir, { recursive: true, force: true });
117
+ }
118
+ }
119
+ fs.symlinkSync(path.basename(this.resultDir), latestDir, 'junction');
120
+ }
121
+ catch { /* ignore latest symlink error */ }
122
+ }
123
+ console.log(`[keve-reporter] report-data.json generated at: ${reportDataPath}`);
124
+ }
125
+ else {
126
+ console.log(`[keve-reporter] Skipped report-data.json generation (missing test-results.json or confidence-data.jsonl)`);
127
+ }
128
+ }
129
+ catch (err) {
130
+ console.error(`[keve-reporter] Failed to generate report-data.json: ${err.message}`);
131
+ }
132
+ }
133
+ appendRecord(record) {
134
+ fs.appendFileSync(this.outputPath, JSON.stringify((0, confidence_js_1.sanitizeRecord)(record)) + '\n');
135
+ }
136
+ }
137
+ exports.default = KeveReporter;
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * keve-test — Playwright test fixture: keveGoal (唯一操作原语)
3
3
  *
4
- * keveGoal 执行 fn 后 → 截图+fn逻辑+expected → AI判断是否一致
5
- * 一致 → 通过
6
- * 不一致 → AI 告诉你还差什么 → Re-Act 探索 → 探索成功
4
+ * keveGoal 执行 fn 后 → 截图+fn逻辑+expected → Agent Re-Act 观察页面后给最终结论
7
5
  * fn 无 → Re-Act 直接探索
6
+ * fn 成功 → 仍进 Re-Act,确认预期达成并产出推理轨迹
8
7
  * fn 异常 → Re-Act 自愈
8
+ * 确定性事实(环境阻断 / 页面已关闭 / 截图差异超阈值)→ 短路,不烧 token
9
9
  *
10
10
  * keveAssert 已被吸收:keveGoal 的 expected 即断言语义
11
11
  *
@@ -23,11 +23,11 @@
23
23
  */
24
24
  import { expect } from '@playwright/test';
25
25
  export { expect };
26
- export { keveModel, keveScene, getModelScenes } from './keve-decorators';
27
- export type { KeveSceneMeta } from './keve-decorators';
28
- export { sceneCodeMap, sceneEvalMetaMap } from './keve-registry';
29
- export type { KeveEvalMeta, ErrorCategory } from './keve-registry';
30
- export { sceneGoalsMap, type KeveGoalMeta } from './keve-registry';
26
+ export { keveModel, keveScene, getModelScenes } from '../core/decorator/keve-decorators.js';
27
+ export type { KeveSceneMeta, KeveModelOptions, KeveSceneOptions } from '../core/decorator/keve-decorators.js';
28
+ export { sceneCodeMap, sceneEvalMetaMap, sceneMetaMap } from '../core/decorator/keve-registry.js';
29
+ export type { KeveEvalMeta, ErrorCategory, KeveSceneStaticMeta } from '../core/decorator/keve-registry.js';
30
+ export { sceneGoalsMap, type KeveGoalMeta } from '../core/decorator/keve-registry.js';
31
31
  export interface KeveGoalCallOptions {
32
32
  precondition?: string;
33
33
  step: string;
@@ -39,6 +39,8 @@ type KeveFixture = {
39
39
  noImages?: boolean;
40
40
  outputPath?: string;
41
41
  }) => Promise<any>;
42
+ /** 引擎适配器:engine.click/type/hover/assertVisible 等,引擎无关操作 */
43
+ engine: import('./engineAdapter.js').EngineAdapter;
42
44
  /** 将内置 testInfo 包装为可解构 fixture,允许脚本直接写 { page, keveGoal, testInfo } */
43
45
  testInfo: import('@playwright/test').TestInfo;
44
46
  };