@geekmidas/testkit 0.3.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Factory-BFVnMMCC.mjs.map +1 -1
- package/dist/Factory-BhjUOBWN.cjs.map +1 -1
- package/dist/{Factory-BK06XuDA.d.cts → Factory-Bx0AJXZB.d.cts} +3 -2
- package/dist/Factory-Bx0AJXZB.d.cts.map +1 -0
- package/dist/{Factory-BcGJjLc8.d.mts → Factory-SFupxRC2.d.mts} +2 -1
- package/dist/Factory-SFupxRC2.d.mts.map +1 -0
- package/dist/Factory.d.cts +2 -2
- package/dist/Factory.d.mts +1 -1
- package/dist/KyselyFactory-BFqVIn_0.cjs.map +1 -1
- package/dist/KyselyFactory-DMswpwji.mjs.map +1 -1
- package/dist/{KyselyFactory-Bu9ssWZP.d.cts → KyselyFactory-KLeKH43i.d.cts} +4 -3
- package/dist/KyselyFactory-KLeKH43i.d.cts.map +1 -0
- package/dist/{KyselyFactory-Cj-EultY.d.mts → KyselyFactory-vAxYodck.d.mts} +3 -2
- package/dist/KyselyFactory-vAxYodck.d.mts.map +1 -0
- package/dist/KyselyFactory.d.cts +3 -3
- package/dist/KyselyFactory.d.mts +2 -2
- package/dist/{ObjectionFactory-DL4qkuF1.d.mts → ObjectionFactory-BWjB49-i.d.mts} +3 -2
- package/dist/ObjectionFactory-BWjB49-i.d.mts.map +1 -0
- package/dist/ObjectionFactory-BeFBYcan.cjs.map +1 -1
- package/dist/ObjectionFactory-QCJ7u0Ql.mjs.map +1 -1
- package/dist/{ObjectionFactory-tKWZOiYO.d.cts → ObjectionFactory-aMGvAKt9.d.cts} +4 -3
- package/dist/ObjectionFactory-aMGvAKt9.d.cts.map +1 -0
- package/dist/ObjectionFactory.d.cts +3 -3
- package/dist/ObjectionFactory.d.mts +2 -2
- package/dist/{PostgresKyselyMigrator-upT-hmrz.mjs → PostgresKyselyMigrator-6sE1KOni.mjs} +2 -2
- package/dist/PostgresKyselyMigrator-6sE1KOni.mjs.map +1 -0
- package/dist/{PostgresKyselyMigrator-CIx3AFSR.d.mts → PostgresKyselyMigrator-CBltSOq5.d.cts} +3 -2
- package/dist/PostgresKyselyMigrator-CBltSOq5.d.cts.map +1 -0
- package/dist/{PostgresKyselyMigrator-CfytARcA.cjs → PostgresKyselyMigrator-D6IbPq8t.cjs} +2 -2
- package/dist/PostgresKyselyMigrator-D6IbPq8t.cjs.map +1 -0
- package/dist/{PostgresKyselyMigrator-CQ3aUoy_.d.cts → PostgresKyselyMigrator-DrVWncqd.d.mts} +3 -2
- package/dist/PostgresKyselyMigrator-DrVWncqd.d.mts.map +1 -0
- package/dist/PostgresKyselyMigrator.cjs +2 -2
- package/dist/PostgresKyselyMigrator.d.cts +2 -2
- package/dist/PostgresKyselyMigrator.d.mts +2 -2
- package/dist/PostgresKyselyMigrator.mjs +2 -2
- package/dist/{PostgresMigrator-DbuJGAVy.mjs → PostgresMigrator-BjjenqSd.mjs} +2 -2
- package/dist/PostgresMigrator-BjjenqSd.mjs.map +1 -0
- package/dist/{PostgresMigrator-D5UkK1_K.d.cts → PostgresMigrator-Bres0U6E.d.cts} +2 -1
- package/dist/PostgresMigrator-Bres0U6E.d.cts.map +1 -0
- package/dist/{PostgresMigrator-DFcNdCvD.cjs → PostgresMigrator-D6dQn0x2.cjs} +2 -2
- package/dist/PostgresMigrator-D6dQn0x2.cjs.map +1 -0
- package/dist/{PostgresMigrator-DQaRxoaY.d.mts → PostgresMigrator-S-YYosAC.d.mts} +2 -1
- package/dist/PostgresMigrator-S-YYosAC.d.mts.map +1 -0
- package/dist/PostgresMigrator.cjs +1 -1
- package/dist/PostgresMigrator.d.cts +1 -1
- package/dist/PostgresMigrator.d.mts +1 -1
- package/dist/PostgresMigrator.mjs +1 -1
- package/dist/{PostgresObjectionMigrator-CZHHcCOv.d.cts → PostgresObjectionMigrator-CPfBAP7r.d.cts} +3 -2
- package/dist/PostgresObjectionMigrator-CPfBAP7r.d.cts.map +1 -0
- package/dist/{PostgresObjectionMigrator-BG6ymgnt.cjs → PostgresObjectionMigrator-DK8ODIHQ.cjs} +2 -2
- package/dist/PostgresObjectionMigrator-DK8ODIHQ.cjs.map +1 -0
- package/dist/{PostgresObjectionMigrator-D_hCcrQu.d.mts → PostgresObjectionMigrator-DVEqB5tp.d.mts} +3 -2
- package/dist/PostgresObjectionMigrator-DVEqB5tp.d.mts.map +1 -0
- package/dist/{PostgresObjectionMigrator-DPj2pOpX.mjs → PostgresObjectionMigrator-D_QxXbIN.mjs} +2 -2
- package/dist/PostgresObjectionMigrator-D_QxXbIN.mjs.map +1 -0
- package/dist/PostgresObjectionMigrator.cjs +2 -2
- package/dist/PostgresObjectionMigrator.d.cts +2 -2
- package/dist/PostgresObjectionMigrator.d.mts +2 -2
- package/dist/PostgresObjectionMigrator.mjs +2 -2
- package/dist/{VitestKyselyTransactionIsolator-D3EZZhjZ.d.cts → VitestKyselyTransactionIsolator-CduJlHoT.d.cts} +4 -3
- package/dist/VitestKyselyTransactionIsolator-CduJlHoT.d.cts.map +1 -0
- package/dist/{VitestKyselyTransactionIsolator-Dxlp1u0f.d.mts → VitestKyselyTransactionIsolator-Cswnnj0k.d.mts} +4 -3
- package/dist/VitestKyselyTransactionIsolator-Cswnnj0k.d.mts.map +1 -0
- package/dist/{VitestKyselyTransactionIsolator-EvDLk5zg.cjs → VitestKyselyTransactionIsolator-D7RRXOBa.cjs} +2 -2
- package/dist/VitestKyselyTransactionIsolator-D7RRXOBa.cjs.map +1 -0
- package/dist/{VitestKyselyTransactionIsolator-CNURW8y6.mjs → VitestKyselyTransactionIsolator-DceyIqr4.mjs} +2 -2
- package/dist/VitestKyselyTransactionIsolator-DceyIqr4.mjs.map +1 -0
- package/dist/VitestKyselyTransactionIsolator.cjs +1 -1
- package/dist/VitestKyselyTransactionIsolator.d.cts +2 -2
- package/dist/VitestKyselyTransactionIsolator.d.mts +2 -2
- package/dist/VitestKyselyTransactionIsolator.mjs +1 -1
- package/dist/{VitestObjectionTransactionIsolator-1TpsPqfG.d.cts → VitestObjectionTransactionIsolator-BXoR6xdG.d.cts} +4 -3
- package/dist/VitestObjectionTransactionIsolator-BXoR6xdG.d.cts.map +1 -0
- package/dist/{VitestObjectionTransactionIsolator-CM5KTAFA.cjs → VitestObjectionTransactionIsolator-CdLRrzNf.cjs} +2 -2
- package/dist/VitestObjectionTransactionIsolator-CdLRrzNf.cjs.map +1 -0
- package/dist/{VitestObjectionTransactionIsolator-jQFaCz0u.mjs → VitestObjectionTransactionIsolator-OF2osYY5.mjs} +2 -2
- package/dist/VitestObjectionTransactionIsolator-OF2osYY5.mjs.map +1 -0
- package/dist/{VitestObjectionTransactionIsolator-i9jIgU8Q.d.mts → VitestObjectionTransactionIsolator-x6hY5j4u.d.mts} +4 -3
- package/dist/VitestObjectionTransactionIsolator-x6hY5j4u.d.mts.map +1 -0
- package/dist/VitestObjectionTransactionIsolator.cjs +1 -1
- package/dist/VitestObjectionTransactionIsolator.d.cts +2 -2
- package/dist/VitestObjectionTransactionIsolator.d.mts +2 -2
- package/dist/VitestObjectionTransactionIsolator.mjs +1 -1
- package/dist/{VitestTransactionIsolator-BvR19bYn.d.mts → VitestTransactionIsolator-BNWJqh9f.d.mts} +3 -2
- package/dist/VitestTransactionIsolator-BNWJqh9f.d.mts.map +1 -0
- package/dist/VitestTransactionIsolator-CMfJXZP8.cjs.map +1 -1
- package/dist/{VitestTransactionIsolator-CwQaxZLP.d.cts → VitestTransactionIsolator-CSroc7Df.d.cts} +3 -2
- package/dist/VitestTransactionIsolator-CSroc7Df.d.cts.map +1 -0
- package/dist/VitestTransactionIsolator-DQ7tLqgV.mjs.map +1 -1
- package/dist/VitestTransactionIsolator.d.cts +1 -1
- package/dist/VitestTransactionIsolator.d.mts +1 -1
- package/dist/aws.cjs.map +1 -1
- package/dist/aws.d.cts +2 -0
- package/dist/aws.d.cts.map +1 -0
- package/dist/aws.d.mts +2 -0
- package/dist/aws.d.mts.map +1 -0
- package/dist/aws.mjs.map +1 -1
- package/dist/benchmark.cjs.map +1 -1
- package/dist/benchmark.d.cts +1 -0
- package/dist/benchmark.d.cts.map +1 -0
- package/dist/benchmark.d.mts +1 -0
- package/dist/benchmark.d.mts.map +1 -0
- package/dist/benchmark.mjs.map +1 -1
- package/dist/better-auth.cjs +29 -30
- package/dist/better-auth.cjs.map +1 -1
- package/dist/better-auth.d.cts +2 -2
- package/dist/better-auth.d.cts.map +1 -0
- package/dist/better-auth.d.mts.map +1 -0
- package/dist/better-auth.mjs +29 -30
- package/dist/better-auth.mjs.map +1 -1
- package/dist/directory-B-Ozljzk.mjs.map +1 -1
- package/dist/directory-BVC8g7cX.cjs.map +1 -1
- package/dist/{directory-DlkPEzL4.d.cts → directory-CVrfTq1I.d.mts} +2 -1
- package/dist/directory-CVrfTq1I.d.mts.map +1 -0
- package/dist/directory-Cys9g76X.d.cts +13 -0
- package/dist/directory-Cys9g76X.d.cts.map +1 -0
- package/dist/faker-B14IEMIN.cjs.map +1 -1
- package/dist/faker-BGKYFoCT.mjs.map +1 -1
- package/dist/{faker-Cg76aFNO.d.cts → faker-BSH1EMtg.d.cts} +3 -3
- package/dist/faker-BSH1EMtg.d.cts.map +1 -0
- package/dist/faker-DHh7xs4u.d.mts.map +1 -0
- package/dist/faker.d.cts +1 -1
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +1 -0
- package/dist/helpers.d.cts.map +1 -0
- package/dist/helpers.d.mts +1 -0
- package/dist/helpers.d.mts.map +1 -0
- package/dist/helpers.mjs.map +1 -1
- package/dist/kysely.cjs +3 -3
- package/dist/kysely.cjs.map +1 -1
- package/dist/kysely.d.cts +8 -7
- package/dist/kysely.d.cts.map +1 -0
- package/dist/kysely.d.mts +7 -6
- package/dist/kysely.d.mts.map +1 -0
- package/dist/kysely.mjs +3 -3
- package/dist/kysely.mjs.map +1 -1
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.d.cts +1 -0
- package/dist/logger.d.cts.map +1 -0
- package/dist/logger.d.mts +1 -0
- package/dist/logger.d.mts.map +1 -0
- package/dist/logger.mjs.map +1 -1
- package/dist/objection.cjs +3 -3
- package/dist/objection.cjs.map +1 -1
- package/dist/objection.d.cts +8 -7
- package/dist/objection.d.cts.map +1 -0
- package/dist/objection.d.mts +7 -6
- package/dist/objection.d.mts.map +1 -0
- package/dist/objection.mjs +3 -3
- package/dist/objection.mjs.map +1 -1
- package/dist/os/directory.d.cts +1 -1
- package/dist/os/directory.d.mts +1 -1
- package/dist/os/index.d.cts +1 -1
- package/dist/os/index.d.mts +1 -1
- package/dist/timer.cjs.map +1 -1
- package/dist/timer.d.cts +2 -0
- package/dist/timer.d.cts.map +1 -0
- package/dist/timer.d.mts +2 -0
- package/dist/timer.d.mts.map +1 -0
- package/dist/timer.mjs.map +1 -1
- package/package.json +39 -5
- package/src/Factory.ts +72 -72
- package/src/KyselyFactory.ts +330 -330
- package/src/ObjectionFactory.ts +354 -355
- package/src/PostgresKyselyMigrator.ts +37 -37
- package/src/PostgresMigrator.ts +107 -107
- package/src/PostgresObjectionMigrator.ts +91 -91
- package/src/VitestKyselyTransactionIsolator.ts +27 -27
- package/src/VitestObjectionTransactionIsolator.ts +39 -39
- package/src/VitestTransactionIsolator.ts +196 -195
- package/src/__tests__/Factory.spec.ts +163 -155
- package/src/__tests__/KyselyFactory.spec.ts +443 -439
- package/src/__tests__/ObjectionFactory.spec.ts +563 -557
- package/src/__tests__/PostgresKyselyMigrator.spec.ts +641 -641
- package/src/__tests__/PostgresMigrator.spec.ts +341 -341
- package/src/__tests__/PostgresObjectionMigrator.spec.ts +578 -578
- package/src/__tests__/VitestObjectionTransactionIsolator.spec.ts +114 -114
- package/src/__tests__/benchmark.spec.ts +140 -0
- package/src/__tests__/better-auth.spec.ts +15 -15
- package/src/__tests__/faker.spec.ts +226 -137
- package/src/__tests__/integration.spec.ts +597 -597
- package/src/__tests__/utilities.spec.ts +211 -0
- package/src/aws.ts +104 -104
- package/src/benchmark.ts +12 -12
- package/src/better-auth.ts +286 -301
- package/src/faker.ts +153 -153
- package/src/helpers.ts +6 -6
- package/src/kysely.ts +33 -33
- package/src/logger.ts +10 -10
- package/src/objection.ts +31 -31
- package/src/os/directory.ts +11 -10
- package/src/timer.ts +1 -1
- package/test/globalSetup.ts +45 -45
- package/test/helpers.ts +189 -189
- package/test/migrations/1749664623372_user.ts +13 -13
- package/tsconfig.json +9 -0
- package/vitest.config.ts +4 -4
- package/dist/PostgresKyselyMigrator-CfytARcA.cjs.map +0 -1
- package/dist/PostgresKyselyMigrator-upT-hmrz.mjs.map +0 -1
- package/dist/PostgresMigrator-DFcNdCvD.cjs.map +0 -1
- package/dist/PostgresMigrator-DbuJGAVy.mjs.map +0 -1
- package/dist/PostgresObjectionMigrator-BG6ymgnt.cjs.map +0 -1
- package/dist/PostgresObjectionMigrator-DPj2pOpX.mjs.map +0 -1
- package/dist/VitestKyselyTransactionIsolator-CNURW8y6.mjs.map +0 -1
- package/dist/VitestKyselyTransactionIsolator-EvDLk5zg.cjs.map +0 -1
- package/dist/VitestObjectionTransactionIsolator-CM5KTAFA.cjs.map +0 -1
- package/dist/VitestObjectionTransactionIsolator-jQFaCz0u.mjs.map +0 -1
- package/dist/directory-BPf1LgNX.d.mts +0 -12
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Knex } from 'knex';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
type IsolationLevel,
|
|
4
|
+
VitestPostgresTransactionIsolator,
|
|
5
5
|
} from './VitestTransactionIsolator';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -33,43 +33,43 @@ import {
|
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
35
|
export class VitestObjectionTransactionIsolator extends VitestPostgresTransactionIsolator<
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
Knex,
|
|
37
|
+
Knex.Transaction
|
|
38
38
|
> {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
39
|
+
async destroy(_conn: Knex<any, any[]>): Promise<void> {}
|
|
40
|
+
/**
|
|
41
|
+
* Creates a Knex transaction with the specified isolation level.
|
|
42
|
+
* Implements the abstract transact method from VitestPostgresTransactionIsolator.
|
|
43
|
+
* This transaction can be used with Objection.js models via Model.query(trx).
|
|
44
|
+
*
|
|
45
|
+
* @param conn - The Knex database connection
|
|
46
|
+
* @param level - The transaction isolation level
|
|
47
|
+
* @param fn - The function to execute within the transaction
|
|
48
|
+
* @returns Promise that resolves when the transaction completes
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* await isolator.transact(knex, IsolationLevel.REPEATABLE_READ, async (trx) => {
|
|
53
|
+
* // Use transaction with Objection models
|
|
54
|
+
* await User.query(trx).insert({ name: 'Test' });
|
|
55
|
+
* await Post.query(trx).where('userId', user.id).delete();
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
async transact(
|
|
60
|
+
connection: Knex,
|
|
61
|
+
level: IsolationLevel,
|
|
62
|
+
fn: (trx: Knex.Transaction) => Promise<void>,
|
|
63
|
+
): Promise<void> {
|
|
64
|
+
const isolationLevel = level.toLowerCase() as Lowercase<IsolationLevel>;
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
66
|
+
await connection.transaction(
|
|
67
|
+
async (trx) => {
|
|
68
|
+
await fn(trx);
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
isolationLevel,
|
|
72
|
+
},
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
75
|
}
|
|
@@ -7,20 +7,20 @@ import type { TestAPI } from 'vitest';
|
|
|
7
7
|
* @template Transaction - The transaction type specific to the database driver
|
|
8
8
|
* @template Extended - Additional context properties provided by the extend function
|
|
9
9
|
*/
|
|
10
|
-
export interface DatabaseFixtures<Transaction,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
export interface DatabaseFixtures<Transaction, _Extended = object> {
|
|
11
|
+
/**
|
|
12
|
+
* The database transaction available to the test.
|
|
13
|
+
* All database operations should use this transaction to ensure proper rollback.
|
|
14
|
+
*/
|
|
15
|
+
trx: Transaction;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Combined fixtures type that merges the base transaction fixture with extended context.
|
|
20
20
|
*/
|
|
21
21
|
export type ExtendedDatabaseFixtures<
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
Transaction,
|
|
23
|
+
Extended = object,
|
|
24
24
|
> = DatabaseFixtures<Transaction> & Extended;
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -37,7 +37,7 @@ export type ExtendedDatabaseFixtures<
|
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
39
|
export type ExtendContextFn<Transaction, Extended> = (
|
|
40
|
-
|
|
40
|
+
trx: Transaction,
|
|
41
41
|
) => Extended | Promise<Extended>;
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -47,26 +47,26 @@ export type ExtendContextFn<Transaction, Extended> = (
|
|
|
47
47
|
* @see https://www.postgresql.org/docs/current/transaction-iso.html
|
|
48
48
|
*/
|
|
49
49
|
export enum IsolationLevel {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Lowest isolation level. Allows dirty reads.
|
|
52
|
+
* Not recommended for testing.
|
|
53
|
+
*/
|
|
54
|
+
READ_UNCOMMITTED = 'READ UNCOMMITTED',
|
|
55
|
+
/**
|
|
56
|
+
* Default PostgreSQL isolation level.
|
|
57
|
+
* Prevents dirty reads but allows non-repeatable reads.
|
|
58
|
+
*/
|
|
59
|
+
READ_COMMITTED = 'READ COMMITTED',
|
|
60
|
+
/**
|
|
61
|
+
* Prevents dirty reads and non-repeatable reads.
|
|
62
|
+
* Recommended for most test scenarios.
|
|
63
|
+
*/
|
|
64
|
+
REPEATABLE_READ = 'REPEATABLE READ',
|
|
65
|
+
/**
|
|
66
|
+
* Highest isolation level. Prevents all phenomena.
|
|
67
|
+
* May cause performance overhead in tests.
|
|
68
|
+
*/
|
|
69
|
+
SERIALIZABLE = 'SERIALIZABLE',
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
@@ -97,129 +97,130 @@ export enum IsolationLevel {
|
|
|
97
97
|
* ```
|
|
98
98
|
*/
|
|
99
99
|
export abstract class VitestPostgresTransactionIsolator<TConn, Transaction> {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Abstract method to create a transaction with the specified isolation level.
|
|
102
|
+
* Must be implemented by subclasses for specific database drivers.
|
|
103
|
+
*
|
|
104
|
+
* @param conn - The database connection
|
|
105
|
+
* @param isolationLevel - The transaction isolation level
|
|
106
|
+
* @param fn - The function to execute within the transaction
|
|
107
|
+
* @returns Promise that resolves when the transaction completes
|
|
108
|
+
*/
|
|
109
|
+
abstract transact(
|
|
110
|
+
conn: TConn,
|
|
111
|
+
isolationLevel: IsolationLevel,
|
|
112
|
+
fn: (trx: Transaction) => Promise<void>,
|
|
113
|
+
): Promise<void>;
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
115
|
+
abstract destroy(conn: TConn): Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* Creates a new VitestPostgresTransactionIsolator instance.
|
|
118
|
+
*
|
|
119
|
+
* @param api - The Vitest test API (usually the `test` export from vitest)
|
|
120
|
+
*/
|
|
121
|
+
constructor(private readonly api: TestAPI) {}
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Creates a wrapped version of Vitest's test API that provides transaction isolation.
|
|
125
|
+
* Each test will run within a database transaction that is automatically rolled back.
|
|
126
|
+
*
|
|
127
|
+
* @param options - Configuration options for transaction wrapping
|
|
128
|
+
* @returns A wrapped test API with transaction support
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const isolatedTest = isolator.wrapVitestWithTransaction({
|
|
133
|
+
* connection: db,
|
|
134
|
+
* setup: async (trx) => {
|
|
135
|
+
* await trx.insert('settings', { key: 'test', value: 'true' });
|
|
136
|
+
* },
|
|
137
|
+
* fixtures: {
|
|
138
|
+
* factory: (trx) => new Factory(trx),
|
|
139
|
+
* },
|
|
140
|
+
* });
|
|
141
|
+
*
|
|
142
|
+
* isolatedTest('test with transaction', async ({ trx, factory }) => {
|
|
143
|
+
* const user = await factory.insert('user', { name: 'Test' });
|
|
144
|
+
* expect(user).toBeDefined();
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
wrapVitestWithTransaction<Extended extends Record<string, unknown> = {}>(
|
|
149
|
+
options: TransactionWrapperOptions<TConn, Transaction, Extended>,
|
|
150
|
+
) {
|
|
151
|
+
const {
|
|
152
|
+
connection,
|
|
153
|
+
setup,
|
|
154
|
+
isolationLevel = IsolationLevel.REPEATABLE_READ,
|
|
155
|
+
fixtures,
|
|
156
|
+
} = options;
|
|
157
157
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
158
|
+
// Build fixture definitions for additional fixtures that depend on trx
|
|
159
|
+
const additionalFixtures: Record<string, unknown> = {};
|
|
160
|
+
if (fixtures) {
|
|
161
|
+
for (const [key, creator] of Object.entries(fixtures)) {
|
|
162
|
+
additionalFixtures[key] = async (
|
|
163
|
+
{ trx }: { trx: Transaction },
|
|
164
|
+
use: (value: unknown) => Promise<void>,
|
|
165
|
+
) => {
|
|
166
|
+
const value = await (creator as (trx: Transaction) => unknown)(trx);
|
|
167
|
+
await use(value);
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
type CombinedFixtures = DatabaseFixtures<Transaction> & Extended;
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
// Cast to bypass Vitest's strict fixture typing which can't infer
|
|
175
|
+
// dynamically built fixture objects
|
|
176
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
177
|
+
const extendFn = this.api.extend as <T>(fixtures: any) => TestAPI<T>;
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
179
|
+
return extendFn<CombinedFixtures>({
|
|
180
|
+
// This fixture automatically provides a transaction to each test
|
|
181
|
+
// biome-ignore lint/correctness/noEmptyPattern: this has to be like this to satisfy Biome
|
|
182
|
+
trx: async ({}: {}, use: (value: Transaction) => Promise<void>) => {
|
|
183
|
+
// Create a custom error class for rollback
|
|
184
|
+
class TestRollback extends Error {
|
|
185
|
+
constructor() {
|
|
186
|
+
super('Test rollback');
|
|
187
|
+
this.name = 'TestRollback';
|
|
188
|
+
}
|
|
189
|
+
}
|
|
189
190
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
191
|
+
let testError: Error | undefined;
|
|
192
|
+
const conn = await connection();
|
|
193
|
+
try {
|
|
194
|
+
await this.transact(conn, isolationLevel, async (transaction) => {
|
|
195
|
+
try {
|
|
196
|
+
// Provide the transaction to the test
|
|
197
|
+
await setup?.(transaction);
|
|
198
|
+
await use(transaction);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
// Capture any test errors
|
|
201
|
+
testError = error as Error;
|
|
202
|
+
}
|
|
202
203
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
204
|
+
// Always throw to trigger rollback
|
|
205
|
+
throw new TestRollback();
|
|
206
|
+
});
|
|
207
|
+
} catch (error) {
|
|
208
|
+
// Only rethrow if it's not our rollback error
|
|
209
|
+
if (!(error instanceof TestRollback)) {
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
211
212
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
213
|
+
// If the test had an error, throw it now
|
|
214
|
+
if (testError) {
|
|
215
|
+
throw testError;
|
|
216
|
+
}
|
|
217
|
+
} finally {
|
|
218
|
+
await this.destroy(conn);
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
...additionalFixtures,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
export type DatabaseConnectionFn<Conn> = () => Conn | Promise<Conn>;
|
|
@@ -229,18 +230,18 @@ export type DatabaseConnection<Conn> = DatabaseConnectionFn<Conn>;
|
|
|
229
230
|
* Options for wrapping Vitest tests with database transaction isolation.
|
|
230
231
|
*/
|
|
231
232
|
export interface TransactionWrapperOptions<
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
233
|
+
TConn,
|
|
234
|
+
Transaction,
|
|
235
|
+
Extended extends Record<string, unknown> = {},
|
|
235
236
|
> {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
237
|
+
/** Function that creates or returns a database connection */
|
|
238
|
+
connection: DatabaseConnection<TConn>;
|
|
239
|
+
/** Optional setup function to run within the transaction before each test */
|
|
240
|
+
setup?: (trx: Transaction) => Promise<void>;
|
|
241
|
+
/** Transaction isolation level (defaults to REPEATABLE_READ) */
|
|
242
|
+
isolationLevel?: IsolationLevel;
|
|
243
|
+
/** Additional fixtures that depend on the transaction */
|
|
244
|
+
fixtures?: FixtureCreators<Transaction, Extended>;
|
|
244
245
|
}
|
|
245
246
|
|
|
246
247
|
/**
|
|
@@ -248,12 +249,12 @@ export interface TransactionWrapperOptions<
|
|
|
248
249
|
* Each function receives the transaction and returns the fixture value.
|
|
249
250
|
*/
|
|
250
251
|
export type FixtureCreators<
|
|
251
|
-
|
|
252
|
-
|
|
252
|
+
Transaction,
|
|
253
|
+
Extended extends Record<string, unknown>,
|
|
253
254
|
> = {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
255
|
+
[K in keyof Extended]: (
|
|
256
|
+
trx: Transaction,
|
|
257
|
+
) => Extended[K] | Promise<Extended[K]>;
|
|
257
258
|
};
|
|
258
259
|
|
|
259
260
|
/**
|
|
@@ -265,25 +266,25 @@ export type FixtureCreators<
|
|
|
265
266
|
* @template BaseTest - The base wrapped test type
|
|
266
267
|
*/
|
|
267
268
|
export type TestWithExtendedFixtures<
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
269
|
+
Transaction,
|
|
270
|
+
Extended extends Record<string, unknown>,
|
|
271
|
+
BaseTest extends ReturnType<TestAPI['extend']> = ReturnType<
|
|
272
|
+
TestAPI['extend']
|
|
273
|
+
>,
|
|
273
274
|
> = BaseTest & {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
275
|
+
<C extends object>(
|
|
276
|
+
name: string,
|
|
277
|
+
fn: (
|
|
278
|
+
context: DatabaseFixtures<Transaction> & Extended & C,
|
|
279
|
+
) => Promise<void>,
|
|
280
|
+
): void;
|
|
281
|
+
<C extends object>(
|
|
282
|
+
name: string,
|
|
283
|
+
options: object,
|
|
284
|
+
fn: (
|
|
285
|
+
context: DatabaseFixtures<Transaction> & Extended & C,
|
|
286
|
+
) => Promise<void>,
|
|
287
|
+
): void;
|
|
287
288
|
};
|
|
288
289
|
|
|
289
290
|
/**
|
|
@@ -320,26 +321,26 @@ export type TestWithExtendedFixtures<
|
|
|
320
321
|
* ```
|
|
321
322
|
*/
|
|
322
323
|
export function extendWithFixtures<
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
324
|
+
Transaction,
|
|
325
|
+
Extended extends Record<string, unknown>,
|
|
326
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
327
|
+
T extends ReturnType<TestAPI['extend']> = any,
|
|
327
328
|
>(
|
|
328
|
-
|
|
329
|
-
|
|
329
|
+
wrappedTest: T,
|
|
330
|
+
fixtures: FixtureCreators<Transaction, Extended>,
|
|
330
331
|
): TestWithExtendedFixtures<Transaction, Extended, T> {
|
|
331
|
-
|
|
332
|
-
|
|
332
|
+
// Build fixture definitions for Vitest's extend API
|
|
333
|
+
const fixtureDefinitions: Record<string, any> = {};
|
|
333
334
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
335
|
+
for (const [key, creator] of Object.entries(fixtures)) {
|
|
336
|
+
fixtureDefinitions[key] = async (
|
|
337
|
+
{ trx }: { trx: Transaction },
|
|
338
|
+
use: (value: unknown) => Promise<void>,
|
|
339
|
+
) => {
|
|
340
|
+
const value = await (creator as (trx: Transaction) => unknown)(trx);
|
|
341
|
+
await use(value);
|
|
342
|
+
};
|
|
343
|
+
}
|
|
343
344
|
|
|
344
|
-
|
|
345
|
+
return (wrappedTest as any).extend(fixtureDefinitions);
|
|
345
346
|
}
|