Files
livedash-node/scripts/migration/trpc-endpoint-tests.ts
Kaj Kowalski dd145686e6 fix: resolve all TypeScript compilation errors and enable production build
- Fixed missing type imports in lib/api/index.ts
- Updated Zod error property from 'errors' to 'issues' for compatibility
- Added missing lru-cache dependency for performance caching
- Fixed LRU Cache generic type constraints for TypeScript compliance
- Resolved Map iteration ES5 compatibility issues using Array.from()
- Fixed Redis configuration by removing unsupported socket options
- Corrected Prisma relationship naming (auditLogs vs securityAuditLogs)
- Applied type casting for missing database schema fields
- Created missing security types file for enhanced security service
- Disabled deprecated ESLint during build (using Biome for linting)
- Removed deprecated critters dependency and disabled CSS optimization
- Achieved successful production build with all 47 pages generated
2025-07-13 11:52:53 +02:00

558 lines
14 KiB
TypeScript

/**
* tRPC Endpoint Validation Tests
*
* Comprehensive tests to validate tRPC endpoints are working correctly
* after deployment of the new architecture.
*/
import { migrationLogger } from "./migration-logger";
interface EndpointTest {
name: string;
path: string;
method: string;
payload?: unknown;
expectedStatuses: number[];
timeout: number;
critical: boolean;
}
interface TestResult {
name: string;
success: boolean;
status: number;
duration: number;
response?: unknown;
error?: Error;
}
interface TRPCTestResult {
success: boolean;
tests: TestResult[];
totalDuration: number;
passedTests: number;
failedTests: number;
criticalFailures: number;
}
export class TRPCEndpointTester {
private baseUrl: string;
private timeout: number;
constructor(baseUrl?: string, timeout: number = 30000) {
this.baseUrl =
baseUrl || process.env.NEXTAUTH_URL || "http://localhost:3000";
this.timeout = timeout;
}
/**
* Run comprehensive tRPC endpoint tests
*/
async runEndpointTests(): Promise<TRPCTestResult> {
const startTime = Date.now();
const tests: TestResult[] = [];
try {
migrationLogger.startStep(
"TRPC_TESTS",
"Running tRPC endpoint validation tests"
);
// Define test suite
const endpointTests: EndpointTest[] = [
// Authentication endpoints
{
name: "Auth - Get Session",
path: "/api/trpc/auth.getSession",
method: "POST",
payload: { json: null },
expectedStatuses: [200, 401], // 401 is OK for unauthenticated requests
timeout: 5000,
critical: true,
},
// Dashboard endpoints
{
name: "Dashboard - Get Metrics",
path: "/api/trpc/dashboard.getMetrics",
method: "POST",
payload: { json: { dateRange: "7d" } },
expectedStatuses: [200, 401, 403],
timeout: 10000,
critical: true,
},
{
name: "Dashboard - Get Sessions",
path: "/api/trpc/dashboard.getSessions",
method: "POST",
payload: {
json: {
page: 1,
pageSize: 10,
filters: {},
},
},
expectedStatuses: [200, 401, 403],
timeout: 10000,
critical: true,
},
{
name: "Dashboard - Get Session Filter Options",
path: "/api/trpc/dashboard.getSessionFilterOptions",
method: "POST",
payload: { json: null },
expectedStatuses: [200, 401, 403],
timeout: 5000,
critical: false,
},
// Admin endpoints
{
name: "Admin - Get System Health",
path: "/api/trpc/admin.getSystemHealth",
method: "POST",
payload: { json: null },
expectedStatuses: [200, 401, 403],
timeout: 15000,
critical: false,
},
{
name: "Admin - Get Processing Status",
path: "/api/trpc/admin.getProcessingStatus",
method: "POST",
payload: { json: null },
expectedStatuses: [200, 401, 403],
timeout: 10000,
critical: false,
},
// Batch request endpoints (if available)
{
name: "Admin - Get Batch Requests",
path: "/api/trpc/admin.getBatchRequests",
method: "POST",
payload: { json: { page: 1, pageSize: 10 } },
expectedStatuses: [200, 401, 403, 404], // 404 OK if endpoint doesn't exist yet
timeout: 10000,
critical: false,
},
// Test invalid endpoint (should return 404)
{
name: "Invalid Endpoint Test",
path: "/api/trpc/nonexistent.invalidMethod",
method: "POST",
payload: { json: null },
expectedStatuses: [404, 400],
timeout: 5000,
critical: false,
},
];
// Run all tests
for (const test of endpointTests) {
const result = await this.runSingleTest(test);
tests.push(result);
}
const totalDuration = Date.now() - startTime;
const passedTests = tests.filter((t) => t.success).length;
const failedTests = tests.filter((t) => !t.success).length;
const criticalFailures = tests.filter(
(t) =>
!t.success && endpointTests.find((et) => et.name === t.name)?.critical
).length;
const result: TRPCTestResult = {
success: criticalFailures === 0,
tests,
totalDuration,
passedTests,
failedTests,
criticalFailures,
};
if (result.success) {
migrationLogger.completeStep("TRPC_TESTS");
} else {
migrationLogger.failStep(
"TRPC_TESTS",
new Error(`${criticalFailures} critical tRPC tests failed`)
);
}
return result;
} catch (error) {
migrationLogger.error(
"TRPC_TESTS",
"tRPC test suite failed",
error as Error
);
throw error;
}
}
private async runSingleTest(test: EndpointTest): Promise<TestResult> {
const startTime = Date.now();
try {
migrationLogger.debug("TRPC_TEST", `Testing: ${test.name}`);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), test.timeout);
const url = `${this.baseUrl}${test.path}`;
const response = await fetch(url, {
method: test.method,
headers: {
"Content-Type": "application/json",
},
body: test.payload ? JSON.stringify(test.payload) : null,
signal: controller.signal,
});
clearTimeout(timeoutId);
const duration = Date.now() - startTime;
// Check if status is expected
const success = test.expectedStatuses.includes(response.status);
let responseData: unknown;
try {
responseData = await response.json();
} catch {
// Response might not be JSON, that's OK
responseData = await response.text();
}
const result: TestResult = {
name: test.name,
success,
status: response.status,
duration,
response: responseData,
};
if (success) {
migrationLogger.debug("TRPC_TEST", `${test.name} passed`, {
status: response.status,
duration,
});
} else {
migrationLogger.warn("TRPC_TEST", `${test.name} failed`, {
status: response.status,
expected: test.expectedStatuses,
duration,
});
}
return result;
} catch (error) {
const duration = Date.now() - startTime;
migrationLogger.error(
"TRPC_TEST",
`💥 ${test.name} crashed`,
error as Error,
{ duration }
);
return {
name: test.name,
success: false,
status: 0,
duration,
error: error as Error,
};
}
}
/**
* Test tRPC batch requests
*/
async testBatchRequests(): Promise<TestResult> {
const startTime = Date.now();
try {
migrationLogger.info("TRPC_BATCH", "Testing tRPC batch requests");
// Create a batch request with multiple calls
const batchPayload = [
{
id: 1,
jsonrpc: "2.0",
method: "query",
params: {
path: "auth.getSession",
input: { json: null },
},
},
{
id: 2,
jsonrpc: "2.0",
method: "query",
params: {
path: "dashboard.getMetrics",
input: { json: { dateRange: "7d" } },
},
},
];
const response = await fetch(`${this.baseUrl}/api/trpc`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(batchPayload),
});
const duration = Date.now() - startTime;
const responseData = await response.json();
// Batch requests should return an array of responses
const success =
response.ok && Array.isArray(responseData) && responseData.length === 2;
return {
name: "tRPC Batch Requests",
success,
status: response.status,
duration,
response: responseData,
};
} catch (error) {
const duration = Date.now() - startTime;
return {
name: "tRPC Batch Requests",
success: false,
status: 0,
duration,
error: error as Error,
};
}
}
/**
* Test tRPC subscription endpoints (if available)
*/
async testSubscriptions(): Promise<TestResult> {
const startTime = Date.now();
try {
migrationLogger.info("TRPC_SUBSCRIPTIONS", "Testing tRPC subscriptions");
// Test if WebSocket connection is available for subscriptions
const wsUrl = this.baseUrl.replace(/^https?/, "ws") + "/api/trpc";
return new Promise<TestResult>((resolve) => {
try {
const ws = new WebSocket(wsUrl);
const timeout = setTimeout(() => {
ws.close();
resolve({
name: "tRPC Subscriptions",
success: false,
status: 0,
duration: Date.now() - startTime,
error: new Error("WebSocket connection timeout"),
});
}, 5000);
ws.onopen = () => {
clearTimeout(timeout);
ws.close();
resolve({
name: "tRPC Subscriptions",
success: true,
status: 200,
duration: Date.now() - startTime,
});
};
ws.onerror = (error) => {
clearTimeout(timeout);
resolve({
name: "tRPC Subscriptions",
success: false,
status: 0,
duration: Date.now() - startTime,
error: new Error("WebSocket connection failed"),
});
};
} catch (error) {
resolve({
name: "tRPC Subscriptions",
success: false,
status: 0,
duration: Date.now() - startTime,
error: error as Error,
});
}
});
} catch (error) {
const duration = Date.now() - startTime;
return {
name: "tRPC Subscriptions",
success: false,
status: 0,
duration,
error: error as Error,
};
}
}
/**
* Generate test report
*/
generateTestReport(result: TRPCTestResult): string {
const report = `
# tRPC Endpoint Test Report
**Overall Status**: ${result.success ? "✅ All Critical Tests Passed" : "❌ Critical Tests Failed"}
**Total Duration**: ${result.totalDuration}ms
**Passed Tests**: ${result.passedTests}/${result.tests.length}
**Failed Tests**: ${result.failedTests}/${result.tests.length}
**Critical Failures**: ${result.criticalFailures}
## Test Results
${result.tests
.map(
(test) => `
### ${test.name}
- **Status**: ${test.success ? "✅ Pass" : "❌ Fail"}
- **HTTP Status**: ${test.status}
- **Duration**: ${test.duration}ms
${test.error ? `- **Error**: ${test.error.message}` : ""}
${test.response && typeof test.response === "object" ? `- **Response**: \`\`\`json\n${JSON.stringify(test.response, null, 2)}\n\`\`\`` : ""}
`
)
.join("")}
## Summary
${
result.success
? "🎉 All critical tRPC endpoints are working correctly!"
: `⚠️ ${result.criticalFailures} critical endpoint(s) failed. Please review and fix the issues above.`
}
## Recommendations
${
result.failedTests > 0
? `
### Failed Tests Analysis
${result.tests
.filter((t) => !t.success)
.map(
(test) => `
- **${test.name}**: ${test.error?.message || `HTTP ${test.status}`}
`
)
.join("")}
### Next Steps
1. Check server logs for detailed error information
2. Verify tRPC router configuration
3. Ensure all required dependencies are installed
4. Validate environment configuration
5. Test endpoints manually if needed
`
: `
### Optimization Opportunities
1. Monitor response times for performance optimization
2. Consider implementing caching for frequently accessed endpoints
3. Add monitoring and alerting for endpoint health
4. Implement rate limiting if not already in place
`
}
---
*Generated at ${new Date().toISOString()}*
`;
return report;
}
}
// CLI interface
if (import.meta.url === `file://${process.argv[1]}`) {
const baseUrl = process.argv[2];
const tester = new TRPCEndpointTester(baseUrl);
const generateReport = process.argv.includes("--report");
const testBatch = process.argv.includes("--batch");
const testSubscriptions = process.argv.includes("--subscriptions");
const runTests = async () => {
// Run main endpoint tests
const result = await tester.runEndpointTests();
// Run additional tests if requested
if (testBatch) {
const batchResult = await tester.testBatchRequests();
result.tests.push(batchResult);
if (!batchResult.success) {
result.failedTests++;
} else {
result.passedTests++;
}
}
if (testSubscriptions) {
const subscriptionResult = await tester.testSubscriptions();
result.tests.push(subscriptionResult);
if (!subscriptionResult.success) {
result.failedTests++;
} else {
result.passedTests++;
}
}
return result;
}
runTests()
.then((result) => {
console.log("\n=== tRPC ENDPOINT TEST RESULTS ===");
console.log(`Overall Success: ${result.success ? "✅" : "❌"}`);
console.log(`Total Duration: ${result.totalDuration}ms`);
console.log(`Passed Tests: ${result.passedTests}/${result.tests.length}`);
console.log(`Failed Tests: ${result.failedTests}/${result.tests.length}`);
console.log(`Critical Failures: ${result.criticalFailures}`);
console.log("\n=== INDIVIDUAL TEST RESULTS ===");
for (const test of result.tests) {
const status = test.success ? "✅" : "❌";
console.log(
`${status} ${test.name} (HTTP ${test.status}, ${test.duration}ms)`
);
if (test.error) {
console.log(` Error: ${test.error.message}`);
}
}
if (generateReport) {
const report = tester.generateTestReport(result);
const fs = require("node:fs");
const reportPath = `trpc-test-report-${Date.now()}.md`;
fs.writeFileSync(reportPath, report);
console.log(`\n📋 Test report saved to: ${reportPath}`);
}
process.exit(result.success ? 0 : 1);
})
.catch((error) => {
console.error("tRPC endpoint tests failed:", error);
process.exit(1);
});
}