autosite / api-test-script.js
samihalawa's picture
Sync changes - automated commit
144940a
/**
* API Test Script for AutoSite Application
*
* This script provides functions to test the backend API endpoints
* that support the AskAI component functionality.
*/
// Configuration
const API_BASE_URL = 'http://localhost:3000';
const TEST_HTML = `<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<h1>Hello World</h1>
<p>This is a test page.</p>
</body>
</html>`;
// Test prompts for different scenarios
const TEST_PROMPTS = {
initial: "Create a simple landing page with a header and footer",
followUp: "Add a contact form to the page",
complex: "Create a responsive portfolio page with navigation, hero section, project gallery, and contact form"
};
// Helper function for making API requests
async function makeRequest(endpoint, method = 'GET', body = null) {
const options = {
method,
headers: {
'Content-Type': 'application/json'
}
};
if (body) {
options.body = JSON.stringify(body);
}
try {
const response = await fetch(`${API_BASE_URL}${endpoint}`, options);
const contentType = response.headers.get('Content-Type');
// Log response headers for debugging
console.log('Response headers:', {
'Content-Type': contentType,
'X-Response-Type': response.headers.get('X-Response-Type')
});
// Handle different response types
if (contentType && contentType.includes('application/json')) {
return {
status: response.status,
headers: response.headers,
body: await response.json()
};
} else {
return {
status: response.status,
headers: response.headers,
body: await response.text()
};
}
} catch (error) {
console.error('API request failed:', error);
return {
error: error.message
};
}
}
// Test the /api/ask-ai endpoint with initial prompt (full HTML mode)
async function testAskAiInitial() {
console.log('\n--- Testing /api/ask-ai with initial prompt ---');
const requestBody = {
prompt: TEST_PROMPTS.initial
};
console.log('Request:', requestBody);
// For streaming endpoints, we need to handle the response differently
try {
const response = await fetch(`${API_BASE_URL}/api/ask-ai`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
console.log('Response status:', response.status);
console.log('Response headers:', {
'Content-Type': response.headers.get('Content-Type'),
'X-Response-Type': response.headers.get('X-Response-Type')
});
if (!response.ok) {
const errorText = await response.text();
console.error('Error response:', errorText);
return false;
}
// Handle streaming response
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let receivedChunks = 0;
let receivedContent = '';
while (true) {
const { done, value } = await reader.read();
if (done) {
console.log('Stream complete after', receivedChunks, 'chunks');
break;
}
const chunk = decoder.decode(value, { stream: true });
receivedContent += chunk;
receivedChunks++;
// Log progress
if (receivedChunks % 5 === 0) {
console.log(`Received ${receivedChunks} chunks, total length: ${receivedContent.length}`);
}
}
// Validate response content
const hasHtmlStructure = receivedContent.includes('<!DOCTYPE html>') ||
(receivedContent.includes('<html') && receivedContent.includes('</html>'));
if (hasHtmlStructure) {
console.log('Response contains valid HTML structure');
// Log a sample of the response
console.log('Sample of response:', receivedContent.substring(0, 200) + '...');
return true;
} else {
console.error('Response does not contain valid HTML structure');
console.log('Response content:', receivedContent);
return false;
}
} catch (error) {
console.error('Test failed:', error);
return false;
}
}
// Test the /api/ask-ai endpoint with follow-up prompt (diff mode)
async function testAskAiFollowUp() {
console.log('\n--- Testing /api/ask-ai with follow-up prompt (diff mode) ---');
const requestBody = {
prompt: TEST_PROMPTS.followUp,
html: TEST_HTML,
previousPrompt: TEST_PROMPTS.initial
};
console.log('Request:', requestBody);
try {
const response = await fetch(`${API_BASE_URL}/api/ask-ai`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
console.log('Response status:', response.status);
console.log('Response headers:', {
'Content-Type': response.headers.get('Content-Type'),
'X-Response-Type': response.headers.get('X-Response-Type')
});
if (!response.ok) {
const errorText = await response.text();
console.error('Error response:', errorText);
return false;
}
// Verify response type header indicates diff mode
const responseType = response.headers.get('X-Response-Type');
if (responseType !== 'diff') {
console.warn(`Expected response type 'diff', but got '${responseType}'`);
}
// Handle streaming response
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let receivedChunks = 0;
let receivedContent = '';
while (true) {
const { done, value } = await reader.read();
if (done) {
console.log('Stream complete after', receivedChunks, 'chunks');
break;
}
const chunk = decoder.decode(value, { stream: true });
receivedContent += chunk;
receivedChunks++;
// Log progress
if (receivedChunks % 5 === 0) {
console.log(`Received ${receivedChunks} chunks, total length: ${receivedContent.length}`);
}
}
// For diff mode, check if response contains search/replace blocks
const hasDiffBlocks = receivedContent.includes('<<<<<<< SEARCH') &&
receivedContent.includes('======= REPLACE') &&
receivedContent.includes('>>>>>>> END');
if (hasDiffBlocks) {
console.log('Response contains valid diff blocks');
// Log a sample of the response
console.log('Sample of response:', receivedContent.substring(0, 200) + '...');
return true;
} else {
console.warn('Response may not contain valid diff blocks');
console.log('Response content:', receivedContent);
return false;
}
} catch (error) {
console.error('Test failed:', error);
return false;
}
}
// Test the /api/apply-diffs endpoint
async function testApplyDiffs() {
console.log('\n--- Testing /api/apply-diffs endpoint ---');
// Create a sample diff response
const sampleDiff = `Here are the changes to add a contact form:
<<<<<<< SEARCH
<p>This is a test page.</p>
</body>
======= REPLACE
<p>This is a test page.</p>
<h2>Contact Us</h2>
<form>
<div>
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
</div>
<div>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
</div>
<div>
<label for="message">Message:</label>
<textarea id="message" name="message" rows="4" required></textarea>
</div>
<button type="submit">Send</button>
</form>
</body>
>>>>>>> END`;
const requestBody = {
originalHtml: TEST_HTML,
aiResponseContent: sampleDiff
};
console.log('Request:', requestBody);
try {
const response = await fetch(`${API_BASE_URL}/api/apply-diffs`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
console.log('Response status:', response.status);
if (!response.ok) {
const errorText = await response.text();
console.error('Error response:', errorText);
return false;
}
const responseText = await response.text();
// Verify the response contains the applied changes
const hasContactForm = responseText.includes('<h2>Contact Us</h2>') &&
responseText.includes('<form>') &&
responseText.includes('</form>');
if (hasContactForm) {
console.log('Diff was successfully applied');
console.log('Modified HTML:', responseText);
return true;
} else {
console.error('Diff was not applied correctly');
console.log('Response:', responseText);
return false;
}
} catch (error) {
console.error('Test failed:', error);
return false;
}
}
// Test error handling for /api/ask-ai endpoint
async function testAskAiErrorHandling() {
console.log('\n--- Testing /api/ask-ai error handling ---');
// Test with empty prompt (should return 400)
const requestBody = {
prompt: ""
};
console.log('Request with empty prompt:', requestBody);
try {
const response = await fetch(`${API_BASE_URL}/api/ask-ai`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
console.log('Response status:', response.status);
if (response.status === 400) {
console.log('Server correctly returned 400 for empty prompt');
const errorJson = await response.json();
console.log('Error response:', errorJson);
return true;
} else {
console.error('Expected 400 status, but got', response.status);
return false;
}
} catch (error) {
console.error('Test failed:', error);
return false;
}
}
// Test error handling for /api/apply-diffs endpoint
async function testApplyDiffsErrorHandling() {
console.log('\n--- Testing /api/apply-diffs error handling ---');
// Test with malformed diff (should return 400)
const requestBody = {
originalHtml: TEST_HTML,
aiResponseContent: "This is not a valid diff format"
};
console.log('Request with invalid diff format:', requestBody);
try {
const response = await fetch(`${API_BASE_URL}/api/apply-diffs`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
});
console.log('Response status:', response.status);
// The server should either return 400 or successfully process with no changes
if (response.status === 400) {
console.log('Server correctly returned 400 for invalid diff format');
const errorJson = await response.json();
console.log('Error response:', errorJson);
return true;
} else if (response.ok) {
const responseText = await response.text();
// If server didn't error, it should return the original HTML unchanged
if (responseText === TEST_HTML) {
console.log('Server returned original HTML unchanged (acceptable fallback)');
return true;
} else {
console.warn('Server did not error but returned modified HTML');
console.log('Response:', responseText);
return false;
}
} else {
console.error('Unexpected response status:', response.status);
return false;
}
} catch (error) {
console.error('Test failed:', error);
return false;
}
}
// Run all tests
async function runAllTests() {
console.log('Starting API tests for AutoSite application...');
const results = {
askAiInitial: await testAskAiInitial(),
askAiFollowUp: await testAskAiFollowUp(),
applyDiffs: await testApplyDiffs(),
askAiErrorHandling: await testAskAiErrorHandling(),
applyDiffsErrorHandling: await testApplyDiffsErrorHandling()
};
console.log('\n--- Test Results Summary ---');
Object.entries(results).forEach(([test, passed]) => {
console.log(`${test}: ${passed ? '✅ PASSED' : '❌ FAILED'}`);
});
const passedCount = Object.values(results).filter(Boolean).length;
const totalCount = Object.values(results).length;
console.log(`\nTests passed: ${passedCount}/${totalCount} (${Math.round(passedCount/totalCount*100)}%)`);
return results;
}
// Execute tests when run in Node.js
if (typeof window === 'undefined') {
console.log('AutoSite API Test Script running in Node.js');
runAllTests().catch(console.error);
} else {
console.log('AutoSite API Test Script loaded in browser');
console.log('Run tests by calling: runAllTests()');
}