@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.
- package/dist/bin/keve.js +2 -1
- package/dist/commands/clean.js +2 -2
- package/dist/commands/config.js +7 -7
- package/dist/commands/init.js +2 -2
- package/dist/commands/report.js +7 -7
- package/dist/commands/run.js +12 -11
- package/dist/commands/test.js +7 -7
- package/dist/config.js +7 -7
- package/dist/core/action-log-writer.js +4 -1
- package/dist/core/decorator/keve-decorators.d.ts +128 -0
- package/dist/core/decorator/keve-decorators.js +254 -0
- package/dist/core/decorator/keve-host.d.ts +40 -0
- package/dist/core/decorator/keve-host.js +33 -0
- package/dist/core/{keve-registry.d.ts → decorator/keve-registry.d.ts} +19 -0
- package/dist/core/{keve-registry.js → decorator/keve-registry.js} +13 -1
- package/dist/core/generateReport/report.d.ts +1 -1
- package/dist/core/generateReport/report.js +2 -2
- package/dist/core/generateReport/reportData.d.ts +3 -0
- package/dist/core/generateReport/reportData.js +49 -15
- package/dist/core/judge/confidence.d.ts +119 -0
- package/dist/core/judge/confidence.js +295 -0
- package/dist/core/judge/goal-heuristics.d.ts +32 -0
- package/dist/core/judge/goal-heuristics.js +128 -0
- package/dist/core/judge/pngCodec.d.ts +23 -0
- package/dist/core/judge/pngCodec.js +215 -0
- package/dist/core/judge/screenshotDiff.d.ts +112 -0
- package/dist/core/judge/screenshotDiff.js +420 -0
- package/dist/core/page-object/definePage.d.ts +95 -0
- package/dist/core/page-object/definePage.js +62 -0
- package/dist/core/page-object/elementResolver.d.ts +32 -0
- package/dist/core/page-object/elementResolver.js +236 -0
- package/dist/core/page-object/engine-types.d.ts +140 -0
- package/dist/core/page-object/engine-types.js +34 -0
- package/dist/core/sso-cookie.d.ts +18 -0
- package/dist/core/sso-cookie.js +10 -0
- package/dist/dsl/index.d.ts +15 -0
- package/dist/dsl/index.js +29 -0
- package/dist/dsl/locatorSource.d.ts +25 -0
- package/dist/dsl/locatorSource.js +323 -0
- package/dist/dsl/ops.d.ts +46 -0
- package/dist/dsl/ops.js +95 -0
- package/dist/dsl/toDecorator.d.ts +98 -0
- package/dist/dsl/toDecorator.js +747 -0
- package/dist/engine-cypress/adapter.d.ts +108 -0
- package/dist/engine-cypress/adapter.js +514 -0
- package/dist/engine-cypress/agent-page.d.ts +159 -0
- package/dist/engine-cypress/agent-page.js +566 -0
- package/dist/engine-cypress/agentDom.d.ts +22 -0
- package/dist/engine-cypress/agentDom.js +590 -0
- package/dist/engine-cypress/bridge.d.ts +39 -0
- package/dist/engine-cypress/bridge.js +598 -0
- package/dist/engine-cypress/cdp.d.ts +78 -0
- package/dist/engine-cypress/cdp.js +339 -0
- package/dist/engine-cypress/host.d.ts +22 -0
- package/dist/engine-cypress/host.js +480 -0
- package/dist/engine-cypress/index.d.ts +26 -0
- package/dist/engine-cypress/index.js +58 -0
- package/dist/engine-cypress/keveGoal.d.ts +43 -0
- package/dist/engine-cypress/keveGoal.js +265 -0
- package/dist/engine-cypress/pageOps.d.ts +41 -0
- package/dist/engine-cypress/pageOps.js +439 -0
- package/dist/engine-cypress/reporter.d.ts +20 -0
- package/dist/engine-cypress/reporter.js +128 -0
- package/dist/engine-cypress/setup.d.ts +21 -0
- package/dist/engine-cypress/setup.js +27 -0
- package/dist/engine-cypress/shotBuffer.d.ts +40 -0
- package/dist/engine-cypress/shotBuffer.js +41 -0
- package/dist/engine-cypress/state.d.ts +56 -0
- package/dist/engine-cypress/state.js +81 -0
- package/dist/engine-playwright/engineAdapter.d.ts +78 -0
- package/dist/engine-playwright/engineAdapter.js +371 -0
- package/dist/engine-playwright/global-setup.d.ts +28 -0
- package/dist/engine-playwright/global-setup.js +142 -0
- package/dist/{core → engine-playwright}/keve-report.d.ts +0 -1
- package/dist/engine-playwright/keve-report.js +137 -0
- package/dist/{core → engine-playwright}/keve-test.d.ts +10 -8
- package/dist/{core → engine-playwright}/keve-test.js +204 -200
- package/dist/{core → engine-playwright}/pw-config.js +8 -7
- package/dist/index.d.ts +13 -8
- package/dist/index.js +43 -28
- package/dist/page-agent/agent.d.ts +82 -7
- package/dist/page-agent/agent.js +252 -88
- package/dist/page-agent/diagnostics.d.ts +184 -0
- package/dist/page-agent/diagnostics.js +377 -0
- package/dist/page-agent/hooks.d.ts +3 -2
- package/dist/page-agent/hooks.js +4 -3
- package/dist/page-agent/page-like.d.ts +116 -0
- package/dist/page-agent/page-like.js +14 -0
- package/dist/page-agent/playwright-page.d.ts +20 -0
- package/dist/page-agent/playwright-page.js +98 -0
- package/dist/page-agent/system-prompt.d.ts +7 -0
- package/dist/page-agent/system-prompt.js +10 -0
- package/dist/page-agent/tools.d.ts +1 -1
- package/dist/page-agent/tools.js +144 -8
- package/package.json +24 -11
- package/scripts/gen-system-prompt.mjs +36 -0
- package/scripts/run-dsl-task.mjs +619 -0
- package/scripts/runtime/cypress-preprocessor.mjs +44 -0
- package/scripts/runtime/cypress.config.mjs +35 -0
- package/scripts/runtime/playwright.config.mjs +41 -0
- package/scripts/verify-shot-diff.mjs +243 -0
- package/dist/commands/auth-update.d.ts +0 -16
- package/dist/commands/auth-update.js +0 -88
- package/dist/core/auth.d.ts +0 -17
- package/dist/core/auth.js +0 -224
- package/dist/core/cdp-resolver.d.ts +0 -5
- package/dist/core/cdp-resolver.js +0 -93
- package/dist/core/global-setup.d.ts +0 -6
- package/dist/core/global-setup.js +0 -123
- package/dist/core/keve-decorators.d.ts +0 -51
- package/dist/core/keve-decorators.js +0 -95
- package/dist/core/keve-report.js +0 -376
- /package/dist/core/{keve-aspect.d.ts → decorator/keve-aspect.d.ts} +0 -0
- /package/dist/core/{keve-aspect.js → decorator/keve-aspect.js} +0 -0
- /package/dist/{core → engine-playwright}/pw-config.d.ts +0 -0
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.resolveCdpWsUrl = resolveCdpWsUrl;
|
|
37
|
-
const fs = __importStar(require("node:fs"));
|
|
38
|
-
const os = __importStar(require("node:os"));
|
|
39
|
-
const path = __importStar(require("node:path"));
|
|
40
|
-
const node_child_process_1 = require("node:child_process");
|
|
41
|
-
// TODO: consolidate doc-reading logic into keve-suite/spec
|
|
42
|
-
function getChromeUserDataDir() {
|
|
43
|
-
const p = os.platform();
|
|
44
|
-
const h = os.homedir();
|
|
45
|
-
if (p === 'darwin')
|
|
46
|
-
return path.join(h, 'Library', 'Application Support', 'Google', 'Chrome');
|
|
47
|
-
if (p === 'win32')
|
|
48
|
-
return path.join(h, 'AppData', 'Local', 'Google', 'Chrome', 'User Data');
|
|
49
|
-
return path.join(h, '.config', 'google-chrome');
|
|
50
|
-
}
|
|
51
|
-
function getChromeWsUrlFromPort() {
|
|
52
|
-
const portFile = path.join(getChromeUserDataDir(), 'DevToolsActivePort');
|
|
53
|
-
if (!fs.existsSync(portFile))
|
|
54
|
-
return null;
|
|
55
|
-
try {
|
|
56
|
-
const [portStr, wsPath] = fs.readFileSync(portFile, 'utf8').trim().split('\n').map(l => l.trim()).filter(Boolean);
|
|
57
|
-
const port = parseInt(portStr, 10);
|
|
58
|
-
if (!port || !wsPath)
|
|
59
|
-
return null;
|
|
60
|
-
try {
|
|
61
|
-
(0, node_child_process_1.execSync)(`lsof -P -i TCP:${port} 2>/dev/null | grep LISTEN`, { encoding: 'utf8' });
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
return `ws://127.0.0.1:${port}${wsPath}`;
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
async function fetchWsUrlFromHttpEndpoint(endpoint) {
|
|
73
|
-
try {
|
|
74
|
-
const url = endpoint.replace(/\/$/, '') + '/json/version';
|
|
75
|
-
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
|
|
76
|
-
const data = await res.json();
|
|
77
|
-
return data.webSocketDebuggerUrl || null;
|
|
78
|
-
}
|
|
79
|
-
catch (e) {
|
|
80
|
-
console.warn(`[cdp-resolver] Failed to fetch from ${endpoint}: ${e.message}`);
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
async function resolveCdpWsUrl(options) {
|
|
85
|
-
if (options.wsEndpoint)
|
|
86
|
-
return options.wsEndpoint;
|
|
87
|
-
if (options.endpoint) {
|
|
88
|
-
const wsUrl = await fetchWsUrlFromHttpEndpoint(options.endpoint);
|
|
89
|
-
if (wsUrl)
|
|
90
|
-
return wsUrl;
|
|
91
|
-
}
|
|
92
|
-
return getChromeWsUrlFromPort();
|
|
93
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
declare global {
|
|
2
|
-
var __keve_cdp_browser: import('@playwright/test').Browser | undefined;
|
|
3
|
-
}
|
|
4
|
-
export declare function getCdpBrowser(): Promise<import('@playwright/test').Browser | null>;
|
|
5
|
-
export declare function isCdpMode(): boolean;
|
|
6
|
-
export default function (): Promise<void>;
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.getCdpBrowser = getCdpBrowser;
|
|
37
|
-
exports.isCdpMode = isCdpMode;
|
|
38
|
-
exports.default = default_1;
|
|
39
|
-
const fs = __importStar(require("node:fs"));
|
|
40
|
-
const path = __importStar(require("node:path"));
|
|
41
|
-
const auth_1 = require("./auth");
|
|
42
|
-
async function getCdpBrowser() {
|
|
43
|
-
// 如果已有共享的 browser 对象,直接复用
|
|
44
|
-
if (globalThis.__keve_cdp_browser && globalThis.__keve_cdp_browser.isConnected()) {
|
|
45
|
-
return globalThis.__keve_cdp_browser;
|
|
46
|
-
}
|
|
47
|
-
const { chromium } = await Promise.resolve().then(() => __importStar(require('@playwright/test')));
|
|
48
|
-
let wsUrl = process.env.KEVE_CDP_WS_ENDPOINT;
|
|
49
|
-
// 如果只提供了 HTTP endpoint,自动获取 WebSocket URL
|
|
50
|
-
if (!wsUrl && process.env.KEVE_CDP_ENDPOINT) {
|
|
51
|
-
const httpUrl = process.env.KEVE_CDP_ENDPOINT.replace(/\/$/, '');
|
|
52
|
-
try {
|
|
53
|
-
const resp = await fetch(`${httpUrl}/json/version`, { signal: AbortSignal.timeout(5000) });
|
|
54
|
-
const data = await resp.json();
|
|
55
|
-
wsUrl = data.webSocketDebuggerUrl;
|
|
56
|
-
console.log(`[keve CDP] Resolved WS endpoint: ${wsUrl}`);
|
|
57
|
-
}
|
|
58
|
-
catch (e) {
|
|
59
|
-
console.warn(`[keve CDP] Failed to resolve CDP WebSocket URL from ${httpUrl}: ${e.message} — falling back to non-CDP mode`);
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
if (!wsUrl) {
|
|
64
|
-
console.warn(`[keve CDP] No CDP endpoint configured — falling back to non-CDP mode`);
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
try {
|
|
68
|
-
const browser = await chromium.connectOverCDP(wsUrl, { timeout: 15000 });
|
|
69
|
-
console.log(`[keve CDP] Connected via ${wsUrl}`);
|
|
70
|
-
globalThis.__keve_cdp_browser = browser;
|
|
71
|
-
return browser;
|
|
72
|
-
}
|
|
73
|
-
catch (connectErr) {
|
|
74
|
-
console.warn(`[keve CDP] connectOverCDP failed: ${connectErr.message} — falling back to non-CDP mode`);
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
function isCdpMode() {
|
|
79
|
-
return !!process.env.KEVE_CDP_WS_ENDPOINT || !!process.env.KEVE_CDP_ENDPOINT;
|
|
80
|
-
}
|
|
81
|
-
async function default_1() {
|
|
82
|
-
const projectRoot = path.resolve(process.cwd());
|
|
83
|
-
const storageStatePath = path.resolve(projectRoot, '.auth/storage-state.json');
|
|
84
|
-
const cdpEndpoint = process.env.KEVE_CDP_ENDPOINT || process.env.KEVE_CDP_WS_ENDPOINT;
|
|
85
|
-
if (cdpEndpoint) {
|
|
86
|
-
console.log(`[keve global-setup] CDP endpoint detected: ${cdpEndpoint}`);
|
|
87
|
-
// CDP 模式:在 global-setup 中提前连接一次,缓存 Browser 对象
|
|
88
|
-
// getCdpBrowser() 失败时返回 null 并清除 CDP 环境变量 → 后续 fixture 自动 fallback
|
|
89
|
-
const browser = await getCdpBrowser();
|
|
90
|
-
if (browser) {
|
|
91
|
-
const contexts = browser.contexts();
|
|
92
|
-
const pages = contexts.length > 0 ? contexts[0].pages() : [];
|
|
93
|
-
console.log(`[keve global-setup] CDP connected. contexts=${contexts.length}, pages=${pages.length}`);
|
|
94
|
-
if (pages.length > 0) {
|
|
95
|
-
console.log(`[keve global-setup] Existing tabs: ${pages.map(p => p.url()).join(', ')}`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
console.warn(`[keve global-setup] CDP connection failed — tests will use non-CDP fallback (chromium.launch)`);
|
|
100
|
-
}
|
|
101
|
-
if (!fs.existsSync(storageStatePath)) {
|
|
102
|
-
const authDir = path.dirname(storageStatePath);
|
|
103
|
-
if (!fs.existsSync(authDir))
|
|
104
|
-
fs.mkdirSync(authDir, { recursive: true });
|
|
105
|
-
fs.writeFileSync(storageStatePath, JSON.stringify({ cookies: [], origins: [] }));
|
|
106
|
-
}
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
console.log(`[keve global-setup] Acquiring fresh auth state...`);
|
|
110
|
-
const success = await (0, auth_1.acquireStorageState)({
|
|
111
|
-
logPrefix: '[keve global-setup]',
|
|
112
|
-
});
|
|
113
|
-
if (!success) {
|
|
114
|
-
console.warn(`[keve global-setup] Auth acquisition failed. Tests may fail due to auth issues.`);
|
|
115
|
-
if (!fs.existsSync(storageStatePath)) {
|
|
116
|
-
const authDir = path.dirname(storageStatePath);
|
|
117
|
-
if (!fs.existsSync(authDir))
|
|
118
|
-
fs.mkdirSync(authDir, { recursive: true });
|
|
119
|
-
fs.writeFileSync(storageStatePath, JSON.stringify({ cookies: [], origins: [] }));
|
|
120
|
-
console.log(`[keve global-setup] Created empty storage state → ${storageStatePath}`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* keve-decorators — @keveModel + @keveScene 装饰器
|
|
3
|
-
*
|
|
4
|
-
* 使用 TC39 Stage 3 装饰器 API (Playwright 1.58+ 默认支持)
|
|
5
|
-
*
|
|
6
|
-
* 执行顺序(TC39 Stage 3 规范):
|
|
7
|
-
* 1. Method decorator 函数调用 → 注册 addInitializer
|
|
8
|
-
* 2. Class decorator 函数调用 → 注册 addInitializer
|
|
9
|
-
* 3. Method addInitializers 执行 → @keveScene 注册场景到 WeakMap
|
|
10
|
-
* 4. Class addInitializer 执行 → @keveModel 读取 WeakMap 并调用 test.describe
|
|
11
|
-
*
|
|
12
|
-
* 两层装饰器 + 函数调用:
|
|
13
|
-
* Model (模块) → test.describe → @keveModel
|
|
14
|
-
* Scene (场景) → test → @keveScene (fn.toString() 捕获完整脚本)
|
|
15
|
-
* Goal (步骤) → 步骤元数据 → keveGoal() 函数调用(在方法体内)
|
|
16
|
-
*/
|
|
17
|
-
import { type KeveGoalMeta } from './keve-registry';
|
|
18
|
-
/** Called by keve-test.ts to register the extended test instance */
|
|
19
|
-
export declare function setKeveTest(t: any): void;
|
|
20
|
-
/** Get the current keve test instance (extended with fixtures) */
|
|
21
|
-
export declare function getKeveTest(): any;
|
|
22
|
-
export type { KeveGoalMeta, KeveEvalMeta, ErrorCategory } from './keve-registry';
|
|
23
|
-
export interface KeveSceneMeta {
|
|
24
|
-
id: string;
|
|
25
|
-
description: string;
|
|
26
|
-
title: string;
|
|
27
|
-
code: string;
|
|
28
|
-
goals: KeveGoalMeta[];
|
|
29
|
-
fn: Function;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* @keveModel(name) — Class decorator (模块层)
|
|
33
|
-
* Uses context.addInitializer to defer test.describe() registration
|
|
34
|
-
* until AFTER all @keveScene addInitializers have run.
|
|
35
|
-
*/
|
|
36
|
-
export declare function keveModel(id: string, description: string): <T extends {
|
|
37
|
-
new (...args: any[]): {};
|
|
38
|
-
}>(ctor: T, context: ClassDecoratorContext) => T;
|
|
39
|
-
/**
|
|
40
|
-
* @keveScene(title) — Method decorator (场景层, static methods only)
|
|
41
|
-
* Captures fn.toString() as the complete scene script.
|
|
42
|
-
* Wraps fn with try-catch-finally to classify errors and decide skipAI.
|
|
43
|
-
* Registers scene metadata to both WeakMap and global Map.
|
|
44
|
-
*
|
|
45
|
-
* The wrapper preserves the original function's destructuring signature by
|
|
46
|
-
* extracting the parameter text from fn.toString() and constructing a wrapper
|
|
47
|
-
* via new Function(), so Playwright can correctly resolve fixture dependencies.
|
|
48
|
-
*/
|
|
49
|
-
export declare function keveScene(id: string, description: string): (fn: Function, context: ClassMethodDecoratorContext) => Function;
|
|
50
|
-
/** 获取 Model 下注册的所有 Scene */
|
|
51
|
-
export declare function getModelScenes(ctor: Function): KeveSceneMeta[] | null;
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* keve-decorators — @keveModel + @keveScene 装饰器
|
|
4
|
-
*
|
|
5
|
-
* 使用 TC39 Stage 3 装饰器 API (Playwright 1.58+ 默认支持)
|
|
6
|
-
*
|
|
7
|
-
* 执行顺序(TC39 Stage 3 规范):
|
|
8
|
-
* 1. Method decorator 函数调用 → 注册 addInitializer
|
|
9
|
-
* 2. Class decorator 函数调用 → 注册 addInitializer
|
|
10
|
-
* 3. Method addInitializers 执行 → @keveScene 注册场景到 WeakMap
|
|
11
|
-
* 4. Class addInitializer 执行 → @keveModel 读取 WeakMap 并调用 test.describe
|
|
12
|
-
*
|
|
13
|
-
* 两层装饰器 + 函数调用:
|
|
14
|
-
* Model (模块) → test.describe → @keveModel
|
|
15
|
-
* Scene (场景) → test → @keveScene (fn.toString() 捕获完整脚本)
|
|
16
|
-
* Goal (步骤) → 步骤元数据 → keveGoal() 函数调用(在方法体内)
|
|
17
|
-
*/
|
|
18
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.setKeveTest = setKeveTest;
|
|
20
|
-
exports.getKeveTest = getKeveTest;
|
|
21
|
-
exports.keveModel = keveModel;
|
|
22
|
-
exports.keveScene = keveScene;
|
|
23
|
-
exports.getModelScenes = getModelScenes;
|
|
24
|
-
const test_1 = require("@playwright/test");
|
|
25
|
-
const keve_registry_1 = require("./keve-registry");
|
|
26
|
-
// ─── Configurable test reference ────────────────────────────────────
|
|
27
|
-
// keveModel needs to call test.describe / test — but it must use the EXTENDED test
|
|
28
|
-
// (with keveGoal/keveAssert fixtures), not the base @playwright/test.
|
|
29
|
-
// keve-test.ts calls setKeveTest() after creating the extended test.
|
|
30
|
-
let _keveTest = test_1.test;
|
|
31
|
-
/** Called by keve-test.ts to register the extended test instance */
|
|
32
|
-
function setKeveTest(t) { _keveTest = t; }
|
|
33
|
-
/** Get the current keve test instance (extended with fixtures) */
|
|
34
|
-
function getKeveTest() { return _keveTest; }
|
|
35
|
-
// ─── Internal Registry (WeakMap per Model constructor) ─────────────
|
|
36
|
-
/** Model → Scene 列表:每个 @keveModel 类下注册的 @keveScene 列表 */
|
|
37
|
-
const modelScenesMap = new WeakMap();
|
|
38
|
-
// ─── Error Classification ──────────────────────────────────────────
|
|
39
|
-
// Error classification moved to keve-report.ts onTestEnd —
|
|
40
|
-
// onTestEnd has access to result.error and result.status, which is more reliable
|
|
41
|
-
// than try-catch in the decorator (async rejections, test-level timeouts can bypass decorator catch).
|
|
42
|
-
// ─── TC39 Stage 3 Decorators ──────────────────────────────────────
|
|
43
|
-
/**
|
|
44
|
-
* @keveModel(name) — Class decorator (模块层)
|
|
45
|
-
* Uses context.addInitializer to defer test.describe() registration
|
|
46
|
-
* until AFTER all @keveScene addInitializers have run.
|
|
47
|
-
*/
|
|
48
|
-
function keveModel(id, description) {
|
|
49
|
-
return (ctor, context) => {
|
|
50
|
-
context.addInitializer(function () {
|
|
51
|
-
const ctor = this;
|
|
52
|
-
const scenes = modelScenesMap.get(ctor) || [];
|
|
53
|
-
_keveTest.describe(`${id}: ${description}`, () => {
|
|
54
|
-
for (const scene of scenes) {
|
|
55
|
-
_keveTest(scene.title, scene.fn);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
return ctor;
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* @keveScene(title) — Method decorator (场景层, static methods only)
|
|
64
|
-
* Captures fn.toString() as the complete scene script.
|
|
65
|
-
* Wraps fn with try-catch-finally to classify errors and decide skipAI.
|
|
66
|
-
* Registers scene metadata to both WeakMap and global Map.
|
|
67
|
-
*
|
|
68
|
-
* The wrapper preserves the original function's destructuring signature by
|
|
69
|
-
* extracting the parameter text from fn.toString() and constructing a wrapper
|
|
70
|
-
* via new Function(), so Playwright can correctly resolve fixture dependencies.
|
|
71
|
-
*/
|
|
72
|
-
function keveScene(id, description) {
|
|
73
|
-
return (fn, context) => {
|
|
74
|
-
const code = fn.toString(); // Capture original code BEFORE wrapping
|
|
75
|
-
const title = `${id}: ${description}`;
|
|
76
|
-
// Register the original function directly — Playwright resolves fixture dependencies
|
|
77
|
-
// by parsing fn.toString() / AST. Wrapping with new Function() breaks this resolution.
|
|
78
|
-
// Error classification is handled in onTestEnd (keve-report.ts), not here.
|
|
79
|
-
context.addInitializer(function () {
|
|
80
|
-
const ctor = this;
|
|
81
|
-
if (!modelScenesMap.has(ctor))
|
|
82
|
-
modelScenesMap.set(ctor, []);
|
|
83
|
-
const scene = { id, description, title, code, goals: [], fn };
|
|
84
|
-
modelScenesMap.get(ctor).push(scene);
|
|
85
|
-
// Register to global maps for Reporter access
|
|
86
|
-
keve_registry_1.sceneCodeMap.set(title, code); // Stores ORIGINAL code, not wrapped
|
|
87
|
-
});
|
|
88
|
-
return fn; // Return original function unchanged — preserves fixture parameter signature
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
// ─── Utility ───────────────────────────────────────────────────────
|
|
92
|
-
/** 获取 Model 下注册的所有 Scene */
|
|
93
|
-
function getModelScenes(ctor) {
|
|
94
|
-
return modelScenesMap.get(ctor) || null;
|
|
95
|
-
}
|