Initial commit - Church Music Database

This commit is contained in:
2026-01-27 18:04:50 -06:00
commit d367261867
336 changed files with 103545 additions and 0 deletions

234
new-site/test-system.js Normal file
View File

@@ -0,0 +1,234 @@
#!/usr/bin/env node
/**
* System Integration Test
* Tests frontend → backend → database connectivity
*/
const http = require("http");
const https = require("https");
const tests = [];
const results = {
passed: 0,
failed: 0,
errors: [],
};
// Test configuration
const BACKEND_URL = "http://localhost:8080";
const FRONTEND_URL = "http://localhost:5100";
const EXTERNAL_URL = "https://houseofprayer.ddns.net";
// Utility: Make HTTP request
function makeRequest(url, options = {}) {
return new Promise((resolve, reject) => {
const client = url.startsWith("https") ? https : http;
const req = client.request(url, options, (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => {
resolve({
statusCode: res.statusCode,
headers: res.headers,
body: data,
});
});
});
req.on("error", reject);
req.on("timeout", () => reject(new Error("Request timeout")));
req.setTimeout(5000);
if (options.body) {
req.write(options.body);
}
req.end();
});
}
// Test: Backend health endpoint
tests.push({
name: "Backend Health Check",
async run() {
const res = await makeRequest(`${BACKEND_URL}/health`);
if (res.statusCode !== 200) {
throw new Error(`Expected 200, got ${res.statusCode}`);
}
const data = JSON.parse(res.body);
if (data.status !== "ok") {
throw new Error(`Health check failed: ${data.status}`);
}
},
});
// Test: Backend songs API
tests.push({
name: "Backend Songs API",
async run() {
const res = await makeRequest(`${BACKEND_URL}/api/songs`);
if (res.statusCode !== 200) {
throw new Error(`Expected 200, got ${res.statusCode}`);
}
const data = JSON.parse(res.body);
if (!data.success) {
throw new Error("API returned success=false");
}
if (!Array.isArray(data.songs)) {
throw new Error("Expected songs array");
}
if (data.songs.length === 0) {
throw new Error("No songs found in database");
}
console.log(` ✓ Found ${data.songs.length} songs`);
},
});
// Test: Backend profiles API
tests.push({
name: "Backend Profiles API",
async run() {
const res = await makeRequest(`${BACKEND_URL}/api/profiles`);
if (res.statusCode !== 200) {
throw new Error(`Expected 200, got ${res.statusCode}`);
}
const data = JSON.parse(res.body);
if (!data.success) {
throw new Error("API returned success=false");
}
if (!Array.isArray(data.profiles)) {
throw new Error("Expected profiles array");
}
console.log(` ✓ Found ${data.profiles.length} profiles`);
},
});
// Test: Backend lists API
tests.push({
name: "Backend Lists API",
async run() {
const res = await makeRequest(`${BACKEND_URL}/api/lists`);
if (res.statusCode !== 200) {
throw new Error(`Expected 200, got ${res.statusCode}`);
}
const data = JSON.parse(res.body);
if (!data.success) {
throw new Error("API returned success=false");
}
if (!Array.isArray(data.lists)) {
throw new Error("Expected lists array");
}
console.log(` ✓ Found ${data.lists.length} worship lists`);
},
});
// Test: Backend stats API
tests.push({
name: "Backend Stats API",
async run() {
const res = await makeRequest(`${BACKEND_URL}/api/stats`);
if (res.statusCode !== 200) {
throw new Error(`Expected 200, got ${res.statusCode}`);
}
const data = JSON.parse(res.body);
if (!data.success) {
throw new Error("API returned success=false");
}
if (!data.stats || typeof data.stats.songs !== "number") {
throw new Error("Invalid stats format");
}
console.log(
` ✓ Stats: ${data.stats.songs} songs, ${data.stats.profiles} profiles, ${data.stats.lists} lists`,
);
},
});
// Test: Frontend serving
tests.push({
name: "Frontend Server",
async run() {
const res = await makeRequest(FRONTEND_URL);
if (res.statusCode !== 200) {
throw new Error(`Expected 200, got ${res.statusCode}`);
}
if (!res.body.includes("<!doctype html>")) {
throw new Error("Invalid HTML response");
}
if (!res.body.includes("Worship Platform")) {
throw new Error("Missing expected content");
}
},
});
// Test: External HTTPS access
tests.push({
name: "External HTTPS Access",
async run() {
const res = await makeRequest(EXTERNAL_URL);
if (res.statusCode !== 200) {
throw new Error(`Expected 200, got ${res.statusCode}`);
}
if (!res.body.includes("<!doctype html>")) {
throw new Error("Invalid HTML response");
}
},
});
// Test: CORS headers
tests.push({
name: "CORS Configuration",
async run() {
const res = await makeRequest(`${BACKEND_URL}/api/songs`, {
method: "OPTIONS",
headers: {
Origin: "https://houseofprayer.ddns.net",
"Access-Control-Request-Method": "GET",
},
});
if (!res.headers["access-control-allow-origin"]) {
throw new Error("Missing CORS headers");
}
},
});
// Run all tests
async function runTests() {
console.log("\n🔍 Running System Integration Tests...\n");
console.log("=".repeat(60));
for (const test of tests) {
try {
process.stdout.write(`\n${test.name}... `);
await test.run();
console.log("✅ PASSED");
results.passed++;
} catch (err) {
console.log("❌ FAILED");
console.log(` Error: ${err.message}`);
results.failed++;
results.errors.push({ test: test.name, error: err.message });
}
}
// Summary
console.log("\n" + "=".repeat(60));
console.log("\n📊 Test Summary:");
console.log(` ✅ Passed: ${results.passed}`);
console.log(` ❌ Failed: ${results.failed}`);
console.log(` 📈 Total: ${tests.length}`);
if (results.failed > 0) {
console.log("\n❌ FAILURES:");
results.errors.forEach(({ test, error }) => {
console.log(`${test}: ${error}`);
});
process.exit(1);
} else {
console.log("\n✅ All tests passed!");
console.log("\n🎉 System is fully operational!");
process.exit(0);
}
}
// Run
runTests().catch((err) => {
console.error("\n💥 Fatal error:", err);
process.exit(1);
});