Files
voidraft/frontend/src/views/editor/extensions/httpclient/language/http.grammar.response.test.ts
2025-11-03 22:15:45 +08:00

264 lines
6.6 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { EditorState } from '@codemirror/state';
import { httpLanguage } from './index';
import { syntaxTree } from '@codemirror/language';
/**
* 创建测试用的 EditorState
*/
function createTestState(content: string): EditorState {
return EditorState.create({
doc: content,
extensions: [httpLanguage]
});
}
/**
* 检查节点是否存在
*/
function hasNode(state: EditorState, nodeName: string): boolean {
const tree = syntaxTree(state);
let found = false;
tree.iterate({
enter: (node) => {
if (node.name === nodeName) {
found = true;
return false;
}
}
});
return found;
}
/**
* 获取节点文本
*/
function getNodeText(state: EditorState, nodeName: string): string | null {
const tree = syntaxTree(state);
let text: string | null = null;
tree.iterate({
enter: (node) => {
if (node.name === nodeName) {
text = state.doc.sliceString(node.from, node.to);
return false;
}
}
});
return text;
}
describe('HTTP Grammar - @response 响应语法', () => {
it('✅ 成功响应 - 完整格式', () => {
const content = `@response 200 123ms 2025-10-31T10:30:31 {
"message": "success",
"data": [1, 2, 3]
}`;
const state = createTestState(content);
expect(hasNode(state, 'ResponseDeclaration')).toBe(true);
expect(hasNode(state, 'ResponseStatus')).toBe(true);
expect(hasNode(state, 'ResponseTime')).toBe(true);
expect(hasNode(state, 'ResponseTimestamp')).toBe(true);
expect(hasNode(state, 'ResponseBlock')).toBe(true);
});
it('✅ 错误响应 - error 关键字', () => {
const content = `@response error 0ms 2025-10-31T10:30:31 {
"error": "Network timeout"
}`;
const state = createTestState(content);
expect(hasNode(state, 'ResponseDeclaration')).toBe(true);
expect(hasNode(state, 'ErrorStatus')).toBe(true);
expect(hasNode(state, 'TimeValue')).toBe(true);
});
it('✅ 响应与请求结合', () => {
const content = `GET "https://api.example.com/users" {}
@response 200 123ms 2025-10-31T10:30:31 {
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}`;
const state = createTestState(content);
expect(hasNode(state, 'RequestStatement')).toBe(true);
expect(hasNode(state, 'ResponseDeclaration')).toBe(true);
});
it('✅ 多个请求和响应', () => {
const content = `GET "https://api.example.com/users" {}
@response 200 100ms 2025-10-31T10:30:31 {
"users": []
}
POST "https://api.example.com/users" {
@json { "name": "Alice" }
}
@response 201 50ms 2025-10-31T10:30:32 {
"id": 1,
"name": "Alice"
}`;
const state = createTestState(content);
const tree = syntaxTree(state);
// 统计 ResponseDeclaration 数量
let responseCount = 0;
tree.iterate({
enter: (node) => {
if (node.name === 'ResponseDeclaration') {
responseCount++;
}
}
});
expect(responseCount).toBe(2);
});
it('✅ 响应状态码类型', () => {
const testCases = [
{ status: '200', shouldParse: true },
{ status: '201', shouldParse: true },
{ status: '404', shouldParse: true },
{ status: '500', shouldParse: true },
{ status: 'error', shouldParse: true }
];
testCases.forEach(({ status, shouldParse }) => {
const content = `@response ${status} 0ms 2025-10-31T10:30:31 { "data": null }`;
const state = createTestState(content);
expect(hasNode(state, 'ResponseDeclaration')).toBe(shouldParse);
});
});
it('✅ 响应时间单位', () => {
const content = `@response 200 12345ms 2025-10-31T10:30:31 {
"data": "test"
}`;
const state = createTestState(content);
expect(hasNode(state, 'TimeValue')).toBe(true);
expect(getNodeText(state, 'TimeValue')).toBe('12345ms');
});
it('✅ 响应块包含复杂 JSON', () => {
const content = `@response 200 150ms 2025-10-31T10:30:31 {
"status": "success",
"data": {
"users": [
{
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"active": true
},
{
"id": 2,
"name": "Bob",
"email": "bob@example.com",
"active": false
}
],
"pagination": {
"page": 1,
"pageSize": 10,
"total": 100
}
}
}`;
const state = createTestState(content);
expect(hasNode(state, 'ResponseDeclaration')).toBe(true);
expect(hasNode(state, 'JsonObject')).toBe(true);
expect(hasNode(state, 'JsonArray')).toBe(true);
});
it('✅ 空响应体', () => {
const content = `@response 204 50ms 2025-10-31T10:30:31 {}`;
const state = createTestState(content);
expect(hasNode(state, 'ResponseDeclaration')).toBe(true);
expect(hasNode(state, 'ResponseBlock')).toBe(true);
});
it('✅ 响应体为数组', () => {
const content = `@response 200 80ms 2025-10-31T10:30:31 [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]`;
const state = createTestState(content);
expect(hasNode(state, 'ResponseDeclaration')).toBe(true);
expect(hasNode(state, 'JsonArray')).toBe(true);
});
it('✅ 时间戳格式', () => {
const testCases = [
'2025-10-31T10:30:31',
'2025-01-01T00:00:00',
'2025-12-31T23:59:59'
];
testCases.forEach(timestamp => {
const content = `@response 200 100ms ${timestamp} { "data": null }`;
const state = createTestState(content);
expect(hasNode(state, 'ResponseTimestamp')).toBe(true);
});
});
it('❌ 缺少必填字段应该有错误', () => {
const invalidCases = [
'@response 200 { "data": null }', // 缺少时间和时间戳
'@response 200 100ms { "data": null }', // 缺少时间戳
];
invalidCases.forEach(content => {
const state = createTestState(content);
const tree = syntaxTree(state);
// 检查是否有错误节点
let hasError = false;
tree.iterate({
enter: (node) => {
if (node.name === '⚠') {
hasError = true;
return false;
}
}
});
expect(hasError).toBe(true);
});
});
it('✅ 与变量结合', () => {
const content = `@var {
apiUrl: "https://api.example.com"
}
GET "https://api.example.com/users" {}
@response 200 123ms 2025-10-31T10:30:31 {
"users": []
}`;
const state = createTestState(content);
expect(hasNode(state, 'VarDeclaration')).toBe(true);
expect(hasNode(state, 'RequestStatement')).toBe(true);
expect(hasNode(state, 'ResponseDeclaration')).toBe(true);
});
});