feat: 增强 expect 规则系统,支持多种 body 校验方法和操作符
- 新增 body 分组校验:contains、regex、json(JSONPath)、css(CSS选择器)、xpath - 新增操作符系统:equals、contains、match、empty、exists、gte、lte、gt、lt - 新增 headers 响应头校验 - 引入 cheerio、xpath、@xmldom/xmldom 依赖 - BREAKING: expect.bodyContains 迁移至 expect.body.contains
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import type { CheckResult, ExpectConfig, ResolvedTarget } from "./types";
|
||||
import { checkBodyExpect } from "./body-expect";
|
||||
|
||||
export async function fetchTarget(target: ResolvedTarget): Promise<CheckResult> {
|
||||
const timestamp = new Date().toISOString();
|
||||
@@ -17,8 +18,9 @@ export async function fetchTarget(target: ResolvedTarget): Promise<CheckResult>
|
||||
|
||||
const latencyMs = Math.round(performance.now() - start);
|
||||
const body = await response.text();
|
||||
const responseHeaders = headersToRecord(response.headers);
|
||||
|
||||
const matched = checkExpect(response.status, body, latencyMs, target.expect);
|
||||
const matched = checkExpect(response.status, body, latencyMs, responseHeaders, target.expect);
|
||||
|
||||
return {
|
||||
targetName: target.name,
|
||||
@@ -38,7 +40,7 @@ export async function fetchTarget(target: ResolvedTarget): Promise<CheckResult>
|
||||
success: false,
|
||||
statusCode: null,
|
||||
latencyMs: null,
|
||||
error: isTimeout ? `请求超时 (${target.timeoutMs}ms)` : (error instanceof Error ? error.message : String(error)),
|
||||
error: isTimeout ? `请求超时 (${target.timeoutMs}ms)` : error instanceof Error ? error.message : String(error),
|
||||
matched: false,
|
||||
};
|
||||
} finally {
|
||||
@@ -46,14 +48,37 @@ export async function fetchTarget(target: ResolvedTarget): Promise<CheckResult>
|
||||
}
|
||||
}
|
||||
|
||||
export function checkExpect(statusCode: number, body: string, latencyMs: number, expect?: ExpectConfig): boolean {
|
||||
function headersToRecord(headers: Headers): Record<string, string> {
|
||||
const result: Record<string, string> = {};
|
||||
headers.forEach((value, key) => {
|
||||
result[key] = value;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
export function checkExpect(
|
||||
statusCode: number,
|
||||
body: string,
|
||||
latencyMs: number,
|
||||
responseHeaders: Record<string, string>,
|
||||
expect?: ExpectConfig,
|
||||
): boolean {
|
||||
if (!expect) return true;
|
||||
|
||||
if (expect.status && !expect.status.includes(statusCode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expect.bodyContains && !body.includes(expect.bodyContains)) {
|
||||
if (expect.headers) {
|
||||
for (const [key, expectedValue] of Object.entries(expect.headers)) {
|
||||
const actualValue = responseHeaders[key.toLowerCase()];
|
||||
if (!actualValue || actualValue !== expectedValue) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkBodyExpect(body, expect.body)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user