264 lines
6.6 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
|