import { jest } from '@jest/globals' import * as pg from 'pg' import type { DbConfig } from '../../../../src/Database/index.js' import { PostgresDatabase } from '../../../../src/Database/integrations/pgsql/PostgresDatabase.js' import { PostgresTransactionImpl } from '../../../../src/Database/integrations/pgsql/PostgresTransaction.js' const testResources = async (config: Partial>) => { const database = { config: { autoCommit: true, ...config, } as DbConfig<'pg'>, } as any as PostgresDatabase const transaction = jest.fn().mockImplementation(() => { return { commit: jest.fn(), rollback: jest.fn(), query: jest.fn(), } })() as any as pg.PoolClient const writer = jest.fn().mockImplementation(() => { return { connect: jest.fn(() => transaction), } })() as any as pg.Pool return { transaction, writer, underTest: await PostgresTransactionImpl.newTransaction(writer, database), } } describe('PostgresTransaction', () => { test('Transaction starts opened', async () => { const { transaction, underTest } = await testResources({}) expect(underTest.isOpen()).toBe(true) expect(transaction.query).toHaveBeenNthCalledWith(1, 'BEGIN') await expect(underTest.begin).rejects.toThrowError( 'Cannot begin, transaction is already opened!' ) }) test('Can only commit once', async () => { const { transaction, underTest } = await testResources({}) await underTest.commit() expect(underTest.isOpen()).toBe(false) expect(transaction.query).toBeCalledWith('COMMIT') await expect(underTest.commit).rejects.toThrowError( 'Cannot commit, transaction is already closed!' ) }) test('Can only rollback once', async () => { const { transaction, underTest } = await testResources({}) await underTest.rollback() expect(underTest.isOpen()).toBe(false) expect(transaction.query).toBeCalledWith('ROLLBACK') await expect(underTest.rollback).rejects.toThrowError( 'Cannot rollback, transaction is already closed!' ) }) test("Can't open transaction twice", async () => { const { transaction, underTest } = await testResources({}) expect(underTest.isOpen()).toBe(true) expect(transaction.query).toHaveBeenNthCalledWith(1, 'BEGIN') await expect(underTest.begin).rejects.toThrowError( 'Cannot begin, transaction is already opened!' ) }) test('Can commit, begin and commit again ', async () => { const { transaction, underTest } = await testResources({}) await underTest.commit() expect(underTest.isOpen()).toBe(false) expect(transaction.query).toBeCalledWith('COMMIT') await underTest.begin() expect(underTest.isOpen()).toBe(true) expect(transaction.query).toHaveBeenNthCalledWith(3, 'BEGIN') await underTest.commit() expect(underTest.isOpen()).toBe(false) expect(transaction.query).toHaveBeenNthCalledWith(4, 'COMMIT') }) test('Can commit, begin and rollback ', async () => { const { transaction, underTest } = await testResources({}) await underTest.commit() expect(underTest.isOpen()).toBe(false) expect(transaction.query).toBeCalledWith('COMMIT') await underTest.begin() expect(underTest.isOpen()).toBe(true) expect(transaction.query).toHaveBeenNthCalledWith(3, 'BEGIN') await underTest.rollback() expect(underTest.isOpen()).toBe(false) expect(transaction.query).toHaveBeenNthCalledWith(4, 'ROLLBACK') }) test('Can rollback, begin and commit ', async () => { const { transaction, underTest } = await testResources({}) await underTest.rollback() expect(underTest.isOpen()).toBe(false) expect(transaction.query).toBeCalledWith('ROLLBACK') await underTest.begin() expect(underTest.isOpen()).toBe(true) expect(transaction.query).toHaveBeenNthCalledWith(3, 'BEGIN') await underTest.commit() expect(underTest.isOpen()).toBe(false) expect(transaction.query).toHaveBeenNthCalledWith(4, 'COMMIT') }) })