2024-08-15 17:59:43 +08:00
|
|
|
import { randomUUID } from 'node:crypto';
|
|
|
|
import { readFileSync } from 'node:fs';
|
2024-08-04 08:28:19 +08:00
|
|
|
import { tmpdir } from 'node:os';
|
2025-01-14 21:07:03 +08:00
|
|
|
import {
|
|
|
|
extractJSONFromCodeBlock,
|
|
|
|
safeParseJson,
|
|
|
|
} from '@/ai-model/service-caller';
|
2024-08-04 08:28:19 +08:00
|
|
|
import {
|
2024-08-15 17:59:43 +08:00
|
|
|
getLogDir,
|
2024-08-04 08:28:19 +08:00
|
|
|
getTmpDir,
|
|
|
|
getTmpFile,
|
|
|
|
overlapped,
|
2024-11-05 11:49:21 +08:00
|
|
|
reportHTMLContent,
|
2024-08-15 17:59:43 +08:00
|
|
|
setLogDir,
|
|
|
|
writeDumpReport,
|
2024-08-04 08:28:19 +08:00
|
|
|
} from '@/utils';
|
|
|
|
import { describe, expect, it } from 'vitest';
|
2024-07-23 16:25:11 +08:00
|
|
|
|
|
|
|
describe('utils', () => {
|
|
|
|
it('tmpDir', () => {
|
|
|
|
const testDir = getTmpDir();
|
|
|
|
expect(typeof testDir).toBe('string');
|
2024-08-04 08:28:19 +08:00
|
|
|
|
2024-07-23 16:25:11 +08:00
|
|
|
const testFile = getTmpFile('txt');
|
2024-10-28 11:04:40 +08:00
|
|
|
expect(testFile!.endsWith('.txt')).toBe(true);
|
2024-07-23 16:25:11 +08:00
|
|
|
});
|
|
|
|
|
2024-08-15 17:59:43 +08:00
|
|
|
it('log dir', () => {
|
|
|
|
const dumpDir = getLogDir();
|
2024-07-23 16:25:11 +08:00
|
|
|
expect(dumpDir).toBeTruthy();
|
|
|
|
|
2024-08-15 17:59:43 +08:00
|
|
|
setLogDir(tmpdir());
|
|
|
|
const dumpDir2 = getLogDir();
|
2024-07-23 16:25:11 +08:00
|
|
|
expect(dumpDir2).toBe(tmpdir());
|
|
|
|
});
|
|
|
|
|
2024-08-15 17:59:43 +08:00
|
|
|
it('write report file', () => {
|
|
|
|
const content = randomUUID();
|
|
|
|
const reportPath = writeDumpReport('test', content);
|
|
|
|
expect(reportPath).toBeTruthy();
|
2024-11-05 11:49:21 +08:00
|
|
|
const reportContent = readFileSync(reportPath!, 'utf-8');
|
2024-08-15 17:59:43 +08:00
|
|
|
expect(reportContent).contains(content);
|
|
|
|
});
|
|
|
|
|
2024-08-31 08:17:50 +08:00
|
|
|
it('write report file with empty dump', () => {
|
|
|
|
const reportPath = writeDumpReport('test', []);
|
|
|
|
expect(reportPath).toBeTruthy();
|
2024-11-05 11:49:21 +08:00
|
|
|
const reportContent = readFileSync(reportPath!, 'utf-8');
|
2024-08-31 08:17:50 +08:00
|
|
|
expect(reportContent).contains('type="midscene_web_dump"');
|
|
|
|
});
|
|
|
|
|
2024-08-15 17:59:43 +08:00
|
|
|
it('write report file with attributes', () => {
|
|
|
|
const content = randomUUID();
|
|
|
|
const reportPath = writeDumpReport('test', [
|
|
|
|
{
|
|
|
|
dumpString: content,
|
|
|
|
attributes: {
|
|
|
|
foo: 'bar',
|
|
|
|
hello: 'world',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
expect(reportPath).toBeTruthy();
|
2024-11-05 11:49:21 +08:00
|
|
|
const reportContent = readFileSync(reportPath!, 'utf-8');
|
2024-08-15 17:59:43 +08:00
|
|
|
expect(reportContent).contains(content);
|
|
|
|
expect(reportContent).contains('foo="bar"');
|
|
|
|
expect(reportContent).contains('hello="world"');
|
|
|
|
});
|
|
|
|
|
2024-07-23 16:25:11 +08:00
|
|
|
it('overlapped', () => {
|
|
|
|
const container = { left: 100, top: 100, width: 100, height: 100 };
|
|
|
|
const target = { left: 150, top: 150, width: 100, height: 100 };
|
|
|
|
expect(overlapped(container, target)).toBeTruthy();
|
|
|
|
|
|
|
|
const target2 = { left: 200, top: 200, width: 100, height: 100 };
|
|
|
|
expect(overlapped(container, target2)).toBeFalsy();
|
|
|
|
});
|
2024-11-05 11:49:21 +08:00
|
|
|
|
|
|
|
it('reportHTMLContent', () => {
|
|
|
|
const reportA = reportHTMLContent([]);
|
|
|
|
expect(reportA).toContain(
|
|
|
|
'<script type="midscene_web_dump" type="application/json"></script>',
|
|
|
|
);
|
|
|
|
|
|
|
|
const content = randomUUID();
|
|
|
|
const reportB = reportHTMLContent(content);
|
|
|
|
expect(reportB).toContain(
|
|
|
|
`<script type="midscene_web_dump" type="application/json">${content}</script>`,
|
|
|
|
);
|
|
|
|
});
|
2024-08-04 08:28:19 +08:00
|
|
|
});
|
2024-09-29 17:16:07 +08:00
|
|
|
|
|
|
|
describe('extractJSONFromCodeBlock', () => {
|
|
|
|
it('should extract JSON from a direct JSON object', () => {
|
|
|
|
const input = '{ "key": "value" }';
|
|
|
|
const result = extractJSONFromCodeBlock(input);
|
|
|
|
expect(result).toBe('{ "key": "value" }');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should extract JSON from a code block with json language specifier', () => {
|
|
|
|
const input = '```json\n{ "key": "value" }\n```';
|
|
|
|
const result = extractJSONFromCodeBlock(input);
|
|
|
|
expect(result).toBe('{ "key": "value" }');
|
2024-12-20 15:18:52 +08:00
|
|
|
|
|
|
|
const input2 = ' ```JSON\n{ "key": "value" }\n```';
|
|
|
|
const result2 = extractJSONFromCodeBlock(input2);
|
|
|
|
expect(result2).toBe('{ "key": "value" }');
|
2024-09-29 17:16:07 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should extract JSON from a code block without language specifier', () => {
|
|
|
|
const input = '```\n{ "key": "value" }\n```';
|
|
|
|
const result = extractJSONFromCodeBlock(input);
|
|
|
|
expect(result).toBe('{ "key": "value" }');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should extract JSON-like structure from text', () => {
|
|
|
|
const input = 'Some text { "key": "value" } more text';
|
|
|
|
const result = extractJSONFromCodeBlock(input);
|
|
|
|
expect(result).toBe('{ "key": "value" }');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should return the original response if no JSON structure is found', () => {
|
|
|
|
const input = 'This is just plain text';
|
|
|
|
const result = extractJSONFromCodeBlock(input);
|
|
|
|
expect(result).toBe('This is just plain text');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should handle multi-line JSON objects', () => {
|
|
|
|
const input = `{
|
|
|
|
"key1": "value1",
|
|
|
|
"key2": {
|
|
|
|
"nestedKey": "nestedValue"
|
|
|
|
}
|
|
|
|
}`;
|
|
|
|
const result = extractJSONFromCodeBlock(input);
|
|
|
|
expect(result).toBe(input);
|
|
|
|
});
|
2025-01-02 21:23:30 +08:00
|
|
|
|
|
|
|
it('should handle JSON with point coordinates', () => {
|
|
|
|
const input = '(123,456)';
|
|
|
|
const result = safeParseJson(input);
|
|
|
|
expect(result).toEqual([123, 456]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should parse valid JSON string using JSON.parse', () => {
|
|
|
|
const input = '{"key": "value"}';
|
|
|
|
const result = safeParseJson(input);
|
|
|
|
expect(result).toEqual({ key: 'value' });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should parse dirty JSON using dirty-json parser', () => {
|
|
|
|
const input = "{key: 'value'}"; // Invalid JSON but valid dirty-json
|
|
|
|
const result = safeParseJson(input);
|
|
|
|
expect(result).toEqual({ key: 'value' });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should throw error for unparseable content', () => {
|
|
|
|
const input = 'not a json at all';
|
|
|
|
const result = safeParseJson(input);
|
|
|
|
expect(result).toEqual(input);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should parse JSON from code block', () => {
|
|
|
|
const input = '```json\n{"key": "value"}\n```';
|
|
|
|
const result = safeParseJson(input);
|
|
|
|
expect(result).toEqual({ key: 'value' });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should parse complex nested JSON', () => {
|
|
|
|
const input = `{
|
|
|
|
"string": "value",
|
|
|
|
"number": 123,
|
|
|
|
"boolean": true,
|
|
|
|
"array": [1, 2, 3],
|
|
|
|
"object": {
|
|
|
|
"nested": "value"
|
|
|
|
}
|
|
|
|
}`;
|
|
|
|
const result = safeParseJson(input);
|
|
|
|
expect(result).toEqual({
|
|
|
|
string: 'value',
|
|
|
|
number: 123,
|
|
|
|
boolean: true,
|
|
|
|
array: [1, 2, 3],
|
|
|
|
object: {
|
|
|
|
nested: 'value',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
2024-09-29 17:16:07 +08:00
|
|
|
});
|