/
weylin
/
WtDev
Обзор
Документация
Войти
/
weylin
/
WtDev
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
dev
src/testing.ts
360 строк
8 KB
Weylin
Сделан вывод алертов и ошибок из тестов в лог vscode
28 июн 2025, 20:47
28 июн 2025, 20:47
b889853
Код
Авторство
О чём код?
import * as vscode from "vscode"; import fs, { promises as fsa } from "fs"; import path from "path"; import { getDefaultServer, getRootFolder, getSrcFolder, PreparedFile, prepareFileUpload, sendApiRequest, } from "./upload"; type PreparedTestFile = PreparedFile & { url?: string; }; type PreparedTest = { id: string; url: string; }; type RunTestResult = { ok: boolean; message?: string; testResults: TestResult[]; }; type TestResult = { id: string; url: string; passed: boolean; errored: boolean; message?: string; duration: number; output: string; }; type CustomTestData = { isFile: boolean; isCase: boolean; uid: string; }; const testData = new WeakMap<vscode.TestItem, CustomTestData>(); class WtTest { readonly controller: vscode.TestController; constructor() { this.controller = vscode.tests.createTestController( "WtTestController", "WtTest" ); this.discoverTests(); } async discoverTests() { const rootFolderPath = getRootFolder(); const srcFolderPath = await getSrcFolder(); const rootFolderName = path.basename(rootFolderPath); const testItem = this.controller.createTestItem( "root", rootFolderName, vscode.Uri.file(srcFolderPath) ); testItem.children.replace(await this.findTestsInFolder(srcFolderPath)); this.controller.items.replace([testItem]); //this.controller.items.add(testItem); const runProfile = this.controller.createRunProfile( "Run", vscode.TestRunProfileKind.Run, this.runHandler ); } runHandler = async ( request: vscode.TestRunRequest, token: vscode.CancellationToken ) => { console.log("test request: ", request); console.log("this.controller :>> ", this.controller); const run = this.controller.createTestRun(request); let testItems: vscode.TestItem[] = []; /*if (request.include) { request.include.forEach((test) => testItems.push(test)); } else { //this.controller.items.forEach((test) => queue.push(test)); console.log("No include in request!!!!!!!!!!!!!"); }*/ if (!request.include) { return; } for (const testItem of request.include) { if (token.isCancellationRequested) { break; } if (request.exclude?.includes(testItem)) { continue; } testItems.push(testItem); run.started(testItem); testItems = [ ...testItems, ...this.getSubTests(testItem.children, run, token), ]; } const filePaths = new Set<string>(); let preparedFiles: PreparedTestFile[] = []; const preparedTests: PreparedTest[] = []; for (const testItem of testItems) { const testDataEntry = testData.get(testItem); if (!testDataEntry) { continue; } if (testItem.uri?.fsPath) { filePaths.add(testItem.uri.fsPath); if (testDataEntry.isCase) { preparedTests.push({ id: testItem.id, url: testItem.uri.fsPath, }); } } } for (const filePath of filePaths) { const prepFiles: PreparedTestFile[] = await prepareFileUpload(filePath); for (const prepFile of prepFiles) { prepFile.url = filePath; } preparedFiles = [...preparedFiles, ...prepFiles]; } const postData = { action: "RunTests", files: preparedFiles, tests: preparedTests, }; const server = await getDefaultServer(); // TODO выбор сервера const runTestResult = await sendApiRequest<RunTestResult>(postData, server); if (runTestResult.ok) { for (const testItem of testItems) { this.applyTestResults(testItem, runTestResult.testResults, run); } } // TODO проставлять статусы папок и файлов??? run.end(); }; applyTestResults( testItem: vscode.TestItem, testResults: TestResult[], run: vscode.TestRun ) { const testResult = testResults.find( (tr) => tr.id === testItem.id && tr.url === testItem.uri?.fsPath ); if (!testResult) { run.skipped(testItem); return; } if (testResult.passed) { run.passed(testItem, testResult.duration); } else if (!testResult.errored) { run.failed( testItem, new vscode.TestMessage(testResult.message ?? "Something gone wrong"), testResult.duration ); } else if (testResult.errored) { run.errored( testItem, new vscode.TestMessage(testResult.message ?? "Some error happened"), testResult.duration ); } if (testItem.uri && testItem.range && testResult.output) { run.appendOutput( testResult.output, new vscode.Location(testItem.uri, testItem.range), testItem ); } } getSubTests( testItemCollection: vscode.TestItemCollection, run: vscode.TestRun, token: vscode.CancellationToken ) { let subTestItems: vscode.TestItem[] = []; testItemCollection.forEach((testItem) => { if (token.isCancellationRequested) { return; } subTestItems.push(testItem); run.started(testItem); subTestItems = [ ...subTestItems, ...this.getSubTests(testItem.children, run, token), ]; }); return subTestItems; } async findTestsInFolder(folderPath: string) { const folderName = path.basename(folderPath); const testItem = this.controller.createTestItem( folderName, folderName, vscode.Uri.file(folderPath) ); const filenames = await fsa.readdir(folderPath); let childTestItems: vscode.TestItem[] = []; for (let filename of filenames) { const filePath = path.resolve(folderPath, filename); //console.log('filePath: '+filePath); const stat = await fsa.lstat(filePath); if (stat.isFile()) { if (!isTestFile(filename)) { continue; } const testItems = await this.parseTestFile(filePath); childTestItems = [...childTestItems, ...testItems]; } else if (stat.isDirectory()) { const testItems = await this.findTestsInFolder(filePath); childTestItems = [...childTestItems, ...testItems]; } } testItem.children.replace(childTestItems); return childTestItems.length > 0 ? [testItem] : []; } async parseTestFile(filePath: string) { const filename = path.basename(filePath); const testItem = this.controller.createTestItem( filename, filename, vscode.Uri.file(filePath) ); testData.set(testItem, { isFile: true, isCase: false, uid: filePath, }); const data = await fsa.readFile(filePath); const lines = data.toString().split("\n"); for (let lineNumber = 0; lineNumber < lines.length; lineNumber++) { const line = lines[lineNumber]; const matches = line.matchAll(/function\s+(test_[\w\d]+)\s*\(/g); //console.log("matches :>> ", Array.from(matches)); for (const match of matches) { if (match.length < 2) { continue; } console.log("match[1] :>> ", match[1]); const testFuncName = match[1]; const funcTestItem = this.controller.createTestItem( testFuncName, testFuncName, vscode.Uri.file(filePath) ); funcTestItem.range = new vscode.Range( new vscode.Position(lineNumber, 0), new vscode.Position(lineNumber, line.length) ); testData.set(funcTestItem, { isFile: false, isCase: true, uid: `${filePath}#${testFuncName}`, }); testItem.children.add(funcTestItem); } } return [testItem]; } async createFileWatcher() { const srcFolderPath = await getSrcFolder(); const pattern = new vscode.RelativePattern(srcFolderPath, "**/*_test.js"); // TODO add .ts const watcher = vscode.workspace.createFileSystemWatcher(pattern); watcher.onDidChange(() => { this.discoverTests(); }); watcher.onDidCreate(() => { this.discoverTests(); }); watcher.onDidDelete(() => { this.discoverTests(); }); return watcher; } } function isTestFile(filename: string) { return /.+_test\.(js|ts)/.test(filename); } export { WtTest };