test(up): structure the up tests in a better way

This commit is contained in:
Joakim Carlstein 2024-01-19 11:05:23 +01:00 committed by Joakim Carlstein
parent 9ef0fa2776
commit e71c318ea5

View file

@ -23,6 +23,15 @@ type Mocked<T> = {
};
describe('up', () => {
it("returns 1 and finishes with an error when the storage couldn't be initialized", async () => {
const { reporter, run } = getUpCommand(['some_migration.js']);
const exitCode = await run();
assert.strictEqual(exitCode, 1);
assertPreconditionsFailed({ dry: false }, reporter, StorageInitError.fromError(new Error('No storage configured')));
});
it('returns 0 and finishes without an error when there are no migrations to run', async () => {
const { reporter, run } = getUpCommand([], getStorage([]));
@ -50,6 +59,67 @@ describe('up', () => {
assertPreconditionsFulfilled({ dry: false }, reporter, []);
});
it('returns 0 and finishes without an error when all pending migrations are run successfully', async () => {
const migration = mock.fn(async () => {
// Success
});
const { reporter, run } = getUpCommand(
['some_already_run_migration.js', 'some_migration.js', 'some_other_migration.js'],
getStorage(['some_already_run_migration.js']),
[
{
loadableExtensions: ['.js'],
async loadMigration() {
return migration;
},
},
],
);
const exitCode = await run();
assert.strictEqual(exitCode, 0);
assertPreconditionsFulfilled({ dry: false }, reporter, [
{ name: 'some_migration.js', status: 'done', started: true },
{ name: 'some_other_migration.js', status: 'done', started: true },
]);
assert.strictEqual(migration.mock.calls.length, 2);
});
it('returns 1 and finishes with an error when a pending migration throw when run', async () => {
const { reporter, run } = getUpCommand(
['some_already_run_migration.js', 'some_migration.js', 'fail.js', 'some_other_migration.js'],
getStorage(['some_already_run_migration.js']),
[
{
loadableExtensions: ['.js'],
async loadMigration(migration) {
return async () => {
if (migration.name === 'fail.js') {
throw new Error('Oh noes!');
}
};
},
},
],
);
const exitCode = await run();
assert.strictEqual(exitCode, 1);
assertPreconditionsFulfilled(
{ dry: false },
reporter,
[
{ name: 'some_migration.js', status: 'done', started: true },
{ name: 'fail.js', status: 'failed', started: true, error: new Error('Oh noes!') },
{ name: 'some_other_migration.js', status: 'skipped' },
],
new MigrationRunError('Failed to run migration: migrations/fail.js', { cause: new Error('Oh noes!') }),
);
});
describe('each migration file extension needs a corresponding loader plugin', () => {
it('returns 1 and finishes with an error when there are migration file extensions without a corresponding loader plugin', async () => {
const { reporter, run } = getUpCommand(['some_other.js', 'some_file.sql'], getStorage([]));
@ -91,7 +161,9 @@ describe('up', () => {
BadOptionError.fromOption('plugin', 'No loader plugin found for file extension: .sql'),
);
});
});
describe('failed migrations in the history are blocking', () => {
it('returns 1 and finishes with an error when there are failed migrations in the history', async () => {
const failedEntry = toEntry('some_failed_migration.js', 'failed');
const { reporter, run } = getUpCommand([failedEntry.name, 'some_file.js'], getStorage([failedEntry]));
@ -157,42 +229,12 @@ describe('up', () => {
assert.strictEqual(exitCode, 0);
assertPreconditionsFulfilled({ dry: false }, reporter, []);
});
it("returns 1 and finishes with an error when the storage couldn't be initialized", async () => {
const { reporter, run } = getUpCommand(['some_migration.js']);
const exitCode = await run();
assert.strictEqual(exitCode, 1);
assertPreconditionsFailed({ dry: false }, reporter, StorageInitError.fromError(new Error('No storage configured')));
});
it('returns 0 and finishes without an error when all pending migrations are run successfully', async () => {
const { reporter, run } = getUpCommand(
['some_already_run_migration.js', 'some_migration.js', 'some_other_migration.js'],
getStorage(['some_already_run_migration.js']),
[
{
loadableExtensions: ['.js'],
async loadMigration() {
return async () => {
// Success
};
},
},
],
);
const exitCode = await run();
assert.strictEqual(exitCode, 0);
assertPreconditionsFulfilled({ dry: false }, reporter, [
{ name: 'some_migration.js', status: 'done', started: true },
{ name: 'some_other_migration.js', status: 'done', started: true },
]);
});
it('returns 0 and finishes without an error when the given number of pending migrations are run successfully', async () => {
const migration = mock.fn(async () => {
// Success
});
const { reporter, run } = getUpCommand(
['some_already_run_migration.js', 'some_migration.js', 'some_other_migration.js'],
getStorage(['some_already_run_migration.js']),
@ -200,9 +242,7 @@ describe('up', () => {
{
loadableExtensions: ['.js'],
async loadMigration() {
return async () => {
// Success
};
return migration;
},
},
],
@ -215,8 +255,10 @@ describe('up', () => {
{ name: 'some_migration.js', status: 'done', started: true },
{ name: 'some_other_migration.js', status: 'skipped' },
]);
assert.strictEqual(migration.mock.calls.length, 1);
});
describe('limiting which pending migrations to run', () => {
it('returns 0 and finishes without an error with the given number of pending migrations are validated and listed successfully in dry-mode', async () => {
const { reporter, run } = getUpCommand(
['some_already_run_migration.js', 'some_migration.js', 'some_other_migration.js'],
@ -233,6 +275,9 @@ describe('up', () => {
});
it('returns 0 and finishes without an error when pending migrations after given "from" parameter are run successfully, even when the "from" is not an existing migration', async () => {
const migration = mock.fn(async () => {
// Success
});
const { reporter, run } = getUpCommand(
['1_some_already_run_migration.js', '2_some_migration.js', '4_some_other_migration.js'],
getStorage(['1_some_already_run_migration.js']),
@ -240,9 +285,7 @@ describe('up', () => {
{
loadableExtensions: ['.js'],
async loadMigration() {
return async () => {
// Success
};
return migration;
},
},
],
@ -255,6 +298,7 @@ describe('up', () => {
{ name: '2_some_migration.js', status: 'skipped' },
{ name: '4_some_other_migration.js', status: 'done', started: true },
]);
assert.strictEqual(migration.mock.calls.length, 1);
});
it('returns 0 and finishes without an error when pending migrations after given "from" parameter are validated and listed successfully in dry-mode, even when the "from" is not an existing migration', async () => {
@ -273,6 +317,9 @@ describe('up', () => {
});
it('returns 0 and finishes without an error when pending migrations before given "to" parameter are run successfully, even when the "to" is not an existing migration', async () => {
const migration = mock.fn(async () => {
// Success
});
const { reporter, run } = getUpCommand(
['1_some_already_run_migration.js', '2_some_migration.js', '4_some_other_migration.js'],
getStorage(['1_some_already_run_migration.js']),
@ -280,9 +327,7 @@ describe('up', () => {
{
loadableExtensions: ['.js'],
async loadMigration() {
return async () => {
// Success
};
return migration;
},
},
],
@ -295,6 +340,7 @@ describe('up', () => {
{ name: '2_some_migration.js', status: 'done', started: true },
{ name: '4_some_other_migration.js', status: 'skipped' },
]);
assert.strictEqual(migration.mock.calls.length, 1);
});
it('returns 0 and finishes without an error when pending migrations after given "to" parameter are validated and listed successfully in dry-mode, even when the "to" is not an existing migration', async () => {
@ -313,6 +359,9 @@ describe('up', () => {
});
it('returns 0 and finishes without an error when the pending migrations fulfilling "from", "to" and "limit" are run successfully', async () => {
const migration = mock.fn(async () => {
// Success
});
const { reporter, run } = getUpCommand(
[
'1_some_already_run_migration.js',
@ -327,9 +376,7 @@ describe('up', () => {
{
loadableExtensions: ['.js'],
async loadMigration() {
return async () => {
// Success
};
return migration;
},
},
],
@ -345,39 +392,8 @@ describe('up', () => {
{ name: '5_yet_another_migration.js', status: 'skipped' },
{ name: '6_some_more_migration.js', status: 'skipped' },
]);
assert.strictEqual(migration.mock.calls.length, 2);
});
it('returns 1 and finishes with an error when a pending migration throw when run', async () => {
const { reporter, run } = getUpCommand(
['some_already_run_migration.js', 'some_migration.js', 'fail.js', 'some_other_migration.js'],
getStorage(['some_already_run_migration.js']),
[
{
loadableExtensions: ['.js'],
async loadMigration(migration) {
return async () => {
if (migration.name === 'fail.js') {
throw new Error('Oh noes!');
}
};
},
},
],
);
const exitCode = await run();
assert.strictEqual(exitCode, 1);
assertPreconditionsFulfilled(
{ dry: false },
reporter,
[
{ name: 'some_migration.js', status: 'done', started: true },
{ name: 'fail.js', status: 'failed', started: true, error: new Error('Oh noes!') },
{ name: 'some_other_migration.js', status: 'skipped' },
],
new MigrationRunError('Failed to run migration: migrations/fail.js', { cause: new Error('Oh noes!') }),
);
});
});