import { jest } from '@jest/globals' import { Knex } from 'knex' import { DbConfig } from '../../../../src/Database/index.js' import { KnexDatabase } from '../../../../src/Database/integrations/knex/KnexDatabase.js' import { KnexTransactionImpl } from '../../../../src/Database/integrations/knex/KnexTransaction.js' const testResources = async (config: Partial>) => { const database = { config: { autoCommit: true, ...config, } as DbConfig<'knex'>, } as any as KnexDatabase const txMock = jest.fn() as any txMock.commit = jest.fn() txMock.rollback = jest.fn() txMock.select = jest.fn() const wMock = jest.fn() as any wMock.transaction = jest.fn(() => txMock) const writer = wMock as Knex const transaction = txMock as Knex.Transaction return { transaction, writer, underTest: await KnexTransactionImpl.newTransaction(writer, database), } } describe('KnexTransaction', () => { test('Can only commit once', async () => { const { writer, transaction, underTest } = await testResources({}) await underTest.commit() expect(underTest.isOpen()).toBe(false) expect(writer.transaction).toBeCalled() expect(transaction.commit).toBeCalled() await expect(underTest.commit).rejects.toThrowError( 'Cannot commit, transaction is already closed!' ) }) test("Can't commit after rollback", async () => { const { writer, transaction, underTest } = await testResources({}) await underTest.rollback() expect(underTest.isOpen()).toBe(false) expect(writer.transaction).toBeCalled() expect(transaction.rollback).toBeCalled() await expect(underTest.commit).rejects.toThrowError( 'Cannot commit, transaction is already closed!' ) }) test('Forwards calls to transaction', async () => { const { transaction, underTest } = await testResources({}) await underTest.select('name') expect(transaction.select).toBeCalledWith('name') }) test('Blocks transaction calls after commit', async () => { const { transaction, underTest } = await testResources({}) expect(underTest.select).toBeDefined() await underTest.commit() expect(transaction.commit).toBeCalled() expect(underTest.isOpen()).toBe(false) expect(underTest.select).toBeUndefined() }) }) describe('KnexTransaction - closeSuccess', () => { test('Close success commits', async () => { const { transaction, underTest } = await testResources({}) await underTest.closeSuccess() expect(transaction.commit).toBeCalled() }) test("Close success, doesn't commit again if already committed", async () => { const { transaction, underTest } = await testResources({}) await underTest.commit() expect(transaction.commit).toBeCalledTimes(1) await underTest.closeSuccess() expect(transaction.commit).toBeCalledTimes(1) }) test('Close success, rolls back if not autocommit', async () => { const { transaction, underTest } = await testResources({ autoCommit: false }) await underTest.closeSuccess() expect(transaction.rollback).toBeCalled() }) test("Close success, doesn't rollback if already committed", async () => { const { transaction, underTest } = await testResources({ autoCommit: false }) await underTest.commit() expect(transaction.commit).toBeCalledTimes(1) await underTest.closeSuccess() expect(transaction.rollback).not.toBeCalled() expect(transaction.commit).toBeCalledTimes(1) }) test("Close success, doesn't rollback if already rolled back", async () => { const { transaction, underTest } = await testResources({ autoCommit: false }) await underTest.rollback() expect(transaction.rollback).toBeCalledTimes(1) await underTest.closeSuccess() expect(transaction.rollback).toBeCalledTimes(1) expect(transaction.commit).not.toBeCalled() }) }) describe('KnexTransaction - closeFailure', () => { test('Close failure rolls back', async () => { const { transaction, underTest } = await testResources({}) await underTest.closeFailure() expect(transaction.rollback).toBeCalled() }) test("Close failure, doesn't rollback again if already rolled back", async () => { const { transaction, underTest } = await testResources({}) await underTest.rollback() expect(transaction.rollback).toBeCalledTimes(1) await underTest.closeFailure() expect(transaction.rollback).toBeCalledTimes(1) }) test("Close failure, doesn't rollback if already committed", async () => { const { transaction, underTest } = await testResources({ autoCommit: false }) await underTest.commit() expect(transaction.commit).toBeCalledTimes(1) await underTest.closeFailure() expect(transaction.rollback).not.toBeCalled() expect(transaction.commit).toBeCalledTimes(1) }) }) describe('KnexTransaction - call direct', () => { test('Calls transaction', async () => { const { transaction, underTest } = await testResources({ autoCommit: false }) underTest('test') expect(transaction).toBeCalledWith('test') }) })