feat(test): add project seeding utilities for localhost testing
- Add seed-test-projects.js utility script - Generates test project data matching API schema - Creates projects with handleIds, jwtIds, planSummary, previousClaim - Supports export, seed, and generate commands - Can seed projects to localhost API server - Add test-api-server-with-seed.js - Standalone Express server for localhost testing - Auto-seeds test projects on startup - Implements /api/v2/report/plansLastUpdatedBetween endpoint - Includes debugging endpoints (/api/test/projects, /api/test/health) - Ready to use immediately without database setup - Update localhost testing guide - Add seeding instructions and examples - Document test API server usage - Explain how to integrate with existing API servers This enables testing prefetch functionality even when your localhost API has no project data. The test server can be started immediately and provides 5 seeded test projects ready for prefetch queries.
This commit is contained in:
249
scripts/seed-test-projects.js
Executable file
249
scripts/seed-test-projects.js
Executable file
@@ -0,0 +1,249 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Seed Test Projects for Localhost Testing
|
||||
*
|
||||
* Creates test project data for localhost API server testing.
|
||||
* Can be run standalone or integrated into your local dev server.
|
||||
*
|
||||
* @author Matthew Raymer
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
const http = require('http');
|
||||
|
||||
/**
|
||||
* Generate a test JWT ID with timestamp prefix for sorting
|
||||
*/
|
||||
function generateJwtId(timestamp = Date.now()) {
|
||||
const random = Math.random().toString(36).substring(2, 8);
|
||||
const hash = Math.random().toString(36).substring(2, 10);
|
||||
return `${Math.floor(timestamp / 1000)}_${random}_${hash}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate test project data
|
||||
*/
|
||||
function generateTestProject(handleId, index = 0) {
|
||||
const now = Date.now();
|
||||
const startTime = new Date(now + (index * 86400000)); // 1 day apart
|
||||
const endTime = new Date(startTime.getTime() + (30 * 86400000)); // 30 days later
|
||||
|
||||
return {
|
||||
jwtId: generateJwtId(now + (index * 1000)),
|
||||
handleId: handleId,
|
||||
name: `Test Project ${index + 1}`,
|
||||
description: `This is test project ${index + 1} for localhost prefetch testing. Created for User Zero starred plans querying.`,
|
||||
issuerDid: "did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F",
|
||||
agentDid: "did:test:agent_" + index,
|
||||
startTime: startTime.toISOString(),
|
||||
endTime: endTime.toISOString(),
|
||||
locLat: 40.7128 + (index * 0.1), // Vary location slightly
|
||||
locLon: -74.0060 + (index * 0.1),
|
||||
url: `https://test-project-${index + 1}.timesafari.test`,
|
||||
version: "1.0.0"
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate complete test project with previous claim
|
||||
*/
|
||||
function generateTestProjectWithClaim(handleId, index = 0) {
|
||||
const project = generateTestProject(handleId, index);
|
||||
const previousClaimJwtId = generateJwtId(Date.now() - (86400000 * 2)); // 2 days ago
|
||||
|
||||
return {
|
||||
planSummary: project,
|
||||
previousClaim: {
|
||||
jwtId: previousClaimJwtId,
|
||||
claimType: "project_update",
|
||||
claimData: {
|
||||
message: `Previous update for ${handleId}`,
|
||||
version: "0.9.0"
|
||||
},
|
||||
metadata: {
|
||||
createdAt: new Date(Date.now() - (86400000 * 2)).toISOString(),
|
||||
updatedAt: new Date(Date.now() - (86400000)).toISOString()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Default test project IDs from config
|
||||
*/
|
||||
const DEFAULT_TEST_PROJECT_IDS = [
|
||||
"test_project_1",
|
||||
"test_project_2",
|
||||
"test_project_3",
|
||||
"demo_project_alpha",
|
||||
"demo_project_beta"
|
||||
];
|
||||
|
||||
/**
|
||||
* Generate all test projects
|
||||
*/
|
||||
function generateAllTestProjects(projectIds = DEFAULT_TEST_PROJECT_IDS) {
|
||||
return projectIds.map((handleId, index) =>
|
||||
generateTestProjectWithClaim(handleId, index)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed projects to localhost API server
|
||||
*
|
||||
* Makes POST requests to create projects in your local API
|
||||
*/
|
||||
function seedToLocalhost(apiUrl, projectIds = DEFAULT_TEST_PROJECT_IDS) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const projects = generateAllTestProjects(projectIds);
|
||||
|
||||
console.log(`📦 Generating ${projects.length} test projects...`);
|
||||
projects.forEach((project, index) => {
|
||||
console.log(` ${index + 1}. ${project.planSummary.handleId} - ${project.planSummary.name}`);
|
||||
});
|
||||
|
||||
// If your API has a seed endpoint, use this:
|
||||
const seedUrl = `${apiUrl}/api/test/seed-projects`;
|
||||
const postData = JSON.stringify({ projects });
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(postData)
|
||||
}
|
||||
};
|
||||
|
||||
const req = http.request(seedUrl, options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
if (res.statusCode === 200 || res.statusCode === 201) {
|
||||
console.log('✅ Test projects seeded successfully');
|
||||
console.log(`📊 Response: ${data}`);
|
||||
resolve(JSON.parse(data));
|
||||
} else {
|
||||
console.error(`❌ Seed failed: ${res.statusCode} ${res.statusMessage}`);
|
||||
console.error(`Response: ${data}`);
|
||||
reject(new Error(`HTTP ${res.statusCode}: ${data}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
console.error(`❌ Request error: ${error.message}`);
|
||||
reject(error);
|
||||
});
|
||||
|
||||
req.write(postData);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate mock API server response data
|
||||
*
|
||||
* Returns the data structure that your localhost API should return
|
||||
*/
|
||||
function getMockApiResponse(projectIds = DEFAULT_TEST_PROJECT_IDS, afterId = null) {
|
||||
const allProjects = generateAllTestProjects(projectIds);
|
||||
|
||||
// Filter by afterId if provided (simple comparison by jwtId)
|
||||
let filteredProjects = allProjects;
|
||||
if (afterId) {
|
||||
const afterIndex = allProjects.findIndex(p => p.planSummary.jwtId === afterId);
|
||||
if (afterIndex >= 0) {
|
||||
filteredProjects = allProjects.slice(afterIndex + 1);
|
||||
} else {
|
||||
// If afterId not found, return all (for testing)
|
||||
filteredProjects = allProjects;
|
||||
}
|
||||
}
|
||||
|
||||
const nextAfterId = filteredProjects.length > 0
|
||||
? filteredProjects[filteredProjects.length - 1].planSummary.jwtId
|
||||
: null;
|
||||
|
||||
return {
|
||||
data: filteredProjects,
|
||||
hitLimit: false,
|
||||
pagination: {
|
||||
hasMore: false,
|
||||
nextAfterId: nextAfterId
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Export project data as JSON file
|
||||
*/
|
||||
function exportToJSON(filename = 'test-projects.json', projectIds = DEFAULT_TEST_PROJECT_IDS) {
|
||||
const fs = require('fs');
|
||||
const projects = generateAllTestProjects(projectIds);
|
||||
const data = {
|
||||
projects: projects,
|
||||
generatedAt: new Date().toISOString(),
|
||||
count: projects.length
|
||||
};
|
||||
|
||||
fs.writeFileSync(filename, JSON.stringify(data, null, 2));
|
||||
console.log(`💾 Exported ${projects.length} test projects to ${filename}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
// CLI usage
|
||||
if (require.main === module) {
|
||||
const args = process.argv.slice(2);
|
||||
const command = args[0];
|
||||
|
||||
switch (command) {
|
||||
case 'export':
|
||||
{
|
||||
const filename = args[1] || 'test-projects.json';
|
||||
const projectIds = args[2] ? args[2].split(',') : DEFAULT_TEST_PROJECT_IDS;
|
||||
exportToJSON(filename, projectIds);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'seed':
|
||||
{
|
||||
const apiUrl = args[1] || 'http://localhost:3000';
|
||||
const projectIds = args[2] ? args[2].split(',') : DEFAULT_TEST_PROJECT_IDS;
|
||||
seedToLocalhost(apiUrl, projectIds)
|
||||
.then(() => {
|
||||
console.log('✅ Seeding complete');
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('❌ Seeding failed:', error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'generate':
|
||||
default:
|
||||
{
|
||||
const projectIds = args[1] ? args[1].split(',') : DEFAULT_TEST_PROJECT_IDS;
|
||||
const projects = generateAllTestProjects(projectIds);
|
||||
console.log(JSON.stringify({ data: projects }, null, 2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateTestProject,
|
||||
generateTestProjectWithClaim,
|
||||
generateAllTestProjects,
|
||||
getMockApiResponse,
|
||||
seedToLocalhost,
|
||||
exportToJSON,
|
||||
DEFAULT_TEST_PROJECT_IDS,
|
||||
generateJwtId
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user