UNPKG

testeranto

Version:

the AI powered BDD test framework for typescript projects

193 lines (192 loc) 10.2 kB
/* eslint-disable @typescript-eslint/no-unused-vars */ import React, { useEffect, useState } from 'react'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; import { fetchTestData } from '../../utils/api'; import { TestPageView } from '../pure/TestPageView'; export const TestPage = () => { const navigate = useNavigate(); const location = useLocation(); const [route, setRoute] = useState('results'); // Sync route with hash changes useEffect(() => { const hash = location.hash.replace('#', ''); if (hash && ['results', 'logs', 'types', 'lint', 'coverage'].includes(hash)) { setRoute(hash); } else { setRoute('results'); } }, [location.hash]); const [testName, setTestName] = useState(''); // const [testData, setTestData] = useState(null); const [logs, setLogs] = useState({}); // const [typeErrors, setTypeErrors] = useState(''); // const [lintErrors, setLintErrors] = useState(''); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [testsExist, setTestsExist] = useState(true); const [errorCounts, setErrorCounts] = useState({ typeErrors: 0, staticErrors: 0, runTimeErrors: 0 }); const [summary, setSummary] = useState(null); const { projectName, '*': splat } = useParams(); const pathParts = splat ? splat.split('/') : []; const runtime = pathParts.pop() || ''; const testPath = pathParts.join('/'); const decodedTestPath = testPath ? decodeURIComponent(testPath) : ''; useEffect(() => { if (!projectName || !testPath || !runtime) return; setTestName(testPath); const fetchData = async () => { var _a; try { const [testResponse, metafileRes] = await Promise.all([ fetchTestData(projectName, testPath, runtime), fetch(`/metafiles/${runtime}/${projectName}.json`) ]); console.log('Fetching test data for:', { projectName, testPath, runtime }); const receivedLogs = await testResponse.logs; console.log('Received logs:', Object.keys(receivedLogs)); let sourceFiles = {}; if (metafileRes.ok) { const metafile = await metafileRes.json(); if ((_a = metafile === null || metafile === void 0 ? void 0 : metafile.metafile) === null || _a === void 0 ? void 0 : _a.outputs) { // Find input files only for this test's entry point const tsSources = new Set(); const testEntryPoint = `src/${testPath}`; // First find all outputs that match this test const matchingOutputs = Object.entries(metafile.metafile.outputs) .filter(([outputPath, output]) => { const normalizedTestPath = testPath.replace(/\./g, '_'); const testFileName = testPath.split('/').pop(); const testBaseName = testFileName === null || testFileName === void 0 ? void 0 : testFileName.split('.').slice(0, -1).join('.'); return output.entryPoint === testEntryPoint || outputPath.includes(normalizedTestPath) || (testBaseName && outputPath.includes(testBaseName)); }); // Then collect all inputs from matching outputs matchingOutputs.forEach(([_, output]) => { Object.keys(output.inputs).forEach(inputPath => { // Check if this input is a TypeScript file and not in node_modules if ((inputPath.endsWith('.ts') || inputPath.endsWith('.tsx')) && !inputPath.includes('node_modules')) { // Get the full input details from metafile.inputs const inputDetails = metafile.metafile.inputs[inputPath]; if (inputDetails) { tsSources.add(inputPath); // Also include any imported TypeScript files inputDetails.imports.forEach(imp => { if ((imp.path.endsWith('.ts') || imp.path.endsWith('.tsx')) && !imp.path.includes('node_modules') && !imp.external) { tsSources.add(imp.path); } }); } } }); }); // Organize source files into directory tree structure const fileTree = {}; const filesList = await Promise.all(Array.from(tsSources).map(async (filePath) => { try { const fetchPath = filePath.startsWith('/') ? filePath : `/${filePath.replace(/^\.\//, '')}`; const res = await fetch(fetchPath); if (res.ok) { return { path: filePath, content: await res.text() }; } return null; } catch (err) { console.warn(`Failed to fetch source file ${filePath}:`, err); return null; } })); filesList.forEach(file => { if (!file) return; const parts = file.path.split('/'); let currentLevel = fileTree; parts.forEach((part, index) => { if (!currentLevel[part]) { if (index === parts.length - 1) { currentLevel[part] = { __isFile: true, content: file.content }; } else { currentLevel[part] = {}; } } currentLevel = currentLevel[part]; }); }); sourceFiles = fileTree; } } // Add source files to logs receivedLogs['source_files'] = sourceFiles; console.log('Source files structure:', sourceFiles); // Ensure tests.json is properly formatted if (receivedLogs['tests.json']) { console.log('tests.json content type:', typeof receivedLogs['tests.json']); try { // Handle both string and already-parsed JSON if (typeof receivedLogs['tests.json'] === 'string') { receivedLogs['tests.json'] = JSON.parse(receivedLogs['tests.json']); } // If it's already an object, leave it as is } catch (e) { console.error('Failed to parse tests.json:', e); // Keep the original content but don't replace it with an error object } } setLogs(receivedLogs); // setTypeErrors(testResponse.typeErrors); // setLintErrors(testResponse.lintErrors); try { const summaryResponse = await fetch(`/reports/${projectName}/summary.json`); if (!summaryResponse.ok) throw new Error('Failed to fetch summary'); const allSummaries = await summaryResponse.json(); const testSummary = allSummaries[testPath]; if (testSummary) { const counts = { typeErrors: Number(testSummary.typeErrors) || 0, staticErrors: Number(testSummary.staticErrors) || 0, runTimeErrors: Number(testSummary.runTimeErrors) || 0 }; setSummary(testSummary); setErrorCounts(counts); setTestsExist(testSummary.testsExist !== false); } } catch (err) { console.error('Failed to load summary:', err); } } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); setTestsExist(false); } finally { setLoading(false); } }; fetchData(); }, []); if (!logs) return React.createElement("div", null, "loading..."); return (React.createElement(React.Fragment, null, React.createElement(TestPageView, { route: route, setRoute: setRoute, navigate: navigate, projectName: projectName, testName: testName, decodedTestPath: decodedTestPath, runtime: runtime, logs: logs, testsExist: testsExist, errorCounts: errorCounts }))); };