test migration script

This commit is contained in:
jackiettran
2025-11-25 21:35:09 -05:00
parent 9ec3e97d9e
commit f3a356d64b
2 changed files with 226 additions and 1 deletions

View File

@@ -21,7 +21,7 @@
"db:migrate:undo:all": "sequelize-cli db:migrate:undo:all", "db:migrate:undo:all": "sequelize-cli db:migrate:undo:all",
"db:migrate:status": "sequelize-cli db:migrate:status", "db:migrate:status": "sequelize-cli db:migrate:status",
"db:create": "sequelize-cli db:create", "db:create": "sequelize-cli db:create",
"test:migrations": "node scripts/test-migrations.js", "test:migrations": "NODE_ENV=test node scripts/test-migrations.js",
"alpha:add": "NODE_ENV=dev node scripts/manageAlphaInvitations.js add", "alpha:add": "NODE_ENV=dev node scripts/manageAlphaInvitations.js add",
"alpha:list": "NODE_ENV=dev node scripts/manageAlphaInvitations.js list", "alpha:list": "NODE_ENV=dev node scripts/manageAlphaInvitations.js list",
"alpha:revoke": "NODE_ENV=dev node scripts/manageAlphaInvitations.js revoke", "alpha:revoke": "NODE_ENV=dev node scripts/manageAlphaInvitations.js revoke",

View File

@@ -0,0 +1,225 @@
#!/usr/bin/env node
/**
* Migration Test Script
*
* Tests that all migrations can run successfully up and down.
* This script:
* 1. Connects to a test database
* 2. Runs all migrations down (clean slate)
* 3. Runs all migrations up
* 4. Verifies tables were created
* 5. Runs all migrations down (test rollback)
* 6. Runs all migrations up again (test idempotency)
* 7. Reports results
*
* Usage:
* NODE_ENV=test npm run test:migrations
*
* Requires:
* - Test database to exist (create with: npm run db:create)
* - Environment variables set for test database connection
*/
const { execSync } = require("child_process");
const path = require("path");
// Colors for console output
const colors = {
reset: "\x1b[0m",
green: "\x1b[32m",
red: "\x1b[31m",
yellow: "\x1b[33m",
blue: "\x1b[34m",
};
function log(message, color = colors.reset) {
console.log(`${color}${message}${colors.reset}`);
}
function logStep(step, message) {
log(`\n[${step}] ${message}`, colors.blue);
}
function logSuccess(message) {
log(`${message}`, colors.green);
}
function logError(message) {
log(`${message}`, colors.red);
}
function logWarning(message) {
log(`${message}`, colors.yellow);
}
function runCommand(command, description) {
try {
log(` Running: ${command}`, colors.yellow);
const output = execSync(command, {
cwd: path.resolve(__dirname, ".."),
encoding: "utf-8",
stdio: ["pipe", "pipe", "pipe"],
env: { ...process.env, NODE_ENV: process.env.NODE_ENV || "test" },
});
if (output.trim()) {
console.log(output);
}
logSuccess(description);
return { success: true, output };
} catch (error) {
logError(`${description} failed`);
console.error(error.stderr || error.message);
return { success: false, error };
}
}
async function main() {
log("\n========================================", colors.blue);
log(" Migration Test Suite", colors.blue);
log("========================================\n", colors.blue);
const env = process.env.NODE_ENV;
// Safety checks - only allow running against test database
if (!env) {
logError("NODE_ENV is not set!");
logError("This script will DELETE ALL DATA in the target database.");
logError("You must explicitly set NODE_ENV=test to run this script.");
log("\nUsage: NODE_ENV=test npm run test:migrations\n");
process.exit(1);
}
if (env.toLowerCase() !== "test") {
logWarning(`Unrecognized NODE_ENV: ${env}`);
logWarning("This script will DELETE ALL DATA in the target database.");
logWarning("Recommended: NODE_ENV=test npm run test:migrations");
log("");
}
log(`Environment: ${env}`);
const results = {
steps: [],
passed: 0,
failed: 0,
};
function recordResult(step, success) {
results.steps.push({ step, success });
if (success) {
results.passed++;
} else {
results.failed++;
}
}
// Step 1: Check migration status
logStep(1, "Checking current migration status");
const statusResult = runCommand(
"npx sequelize-cli db:migrate:status",
"Migration status check"
);
recordResult("Status check", statusResult.success);
// Step 2: Undo all migrations (clean slate)
logStep(2, "Undoing all migrations (clean slate)");
const undoAllResult = runCommand(
"npx sequelize-cli db:migrate:undo:all",
"Undo all migrations"
);
recordResult("Undo all migrations", undoAllResult.success);
if (!undoAllResult.success) {
logWarning("Undo failed - database may already be empty, continuing...");
}
// Step 3: Run all migrations up
logStep(3, "Running all migrations up");
const migrateUpResult = runCommand(
"npx sequelize-cli db:migrate",
"Run all migrations"
);
recordResult("Migrate up", migrateUpResult.success);
if (!migrateUpResult.success) {
logError("Migration up failed - cannot continue");
printSummary(results);
process.exit(1);
}
// Step 4: Verify migration status shows all executed
logStep(4, "Verifying all migrations executed");
const verifyResult = runCommand(
"npx sequelize-cli db:migrate:status",
"Verify migration status"
);
recordResult("Verify status", verifyResult.success);
// Step 5: Test rollback - undo all migrations
logStep(5, "Testing rollback - undoing all migrations");
const rollbackResult = runCommand(
"npx sequelize-cli db:migrate:undo:all",
"Rollback all migrations"
);
recordResult("Rollback", rollbackResult.success);
if (!rollbackResult.success) {
logError("Rollback failed - down migrations have issues");
printSummary(results);
process.exit(1);
}
// Step 6: Test idempotency - run migrations up again
logStep(6, "Testing idempotency - running migrations up again");
const idempotencyResult = runCommand(
"npx sequelize-cli db:migrate",
"Re-run all migrations"
);
recordResult("Idempotency test", idempotencyResult.success);
if (!idempotencyResult.success) {
logError("Idempotency test failed - migrations may not be repeatable");
printSummary(results);
process.exit(1);
}
// Step 7: Final status check
logStep(7, "Final migration status");
const finalStatusResult = runCommand(
"npx sequelize-cli db:migrate:status",
"Final status check"
);
recordResult("Final status", finalStatusResult.success);
printSummary(results);
if (results.failed > 0) {
process.exit(1);
}
log("\nMigration tests completed successfully!", colors.green);
process.exit(0);
}
function printSummary(results) {
log("\n========================================", colors.blue);
log(" Test Summary", colors.blue);
log("========================================\n", colors.blue);
results.steps.forEach(({ step, success }) => {
if (success) {
logSuccess(step);
} else {
logError(step);
}
});
log(`\nTotal: ${results.passed} passed, ${results.failed} failed`);
}
main().catch((error) => {
logError("Unexpected error:");
console.error(error);
process.exit(1);
});