tests.ts•4.38 kB
import { Providers } from '../_utils/providers'
import { waitFor } from '../_utils/tests/waitFor'
import { NewPrismaClient } from '../_utils/types'
import testMatrix from './_matrix'
// @ts-ignore
import type { Prisma as PrismaNamespace, PrismaClient } from './generated/prisma/client'
declare const newPrismaClient: NewPrismaClient<PrismaClient, typeof PrismaClient>
declare let Prisma: typeof PrismaNamespace
testMatrix.setupTestSuite(
({ provider, driverAdapter, clientEngineExecutor }, _suiteMeta, _clientMeta) => {
const isSqlServer = provider === Providers.SQLSERVER
const isCockroachDb = provider === Providers.COCKROACHDB
const usesJsDrivers = driverAdapter !== undefined || clientEngineExecutor === 'remote'
const queries: string[] = []
let prisma: PrismaClient
beforeAll(() => {
prisma = newPrismaClient({
log: [
{
emit: 'event',
level: 'query',
},
],
})
// @ts-expect-error - client not typed for log opts for cross generator compatibility - can be improved once we drop the prisma-client-js generator
prisma.$on('query', (event: Prisma.QueryEvent) => {
queries.push(event.query)
})
})
afterEach(() => {
queries.length = 0
})
const testIsolationLevel = (
name: string,
{
level,
onlyIf,
expectSql,
}: { level: () => PrismaNamespace.TransactionIsolationLevel; onlyIf?: () => boolean; expectSql: string },
) => {
// Driver adapters do not issue SET TRANSACTION ISOLATION LEVEL through the query engine.
testIf(!usesJsDrivers && (onlyIf ? onlyIf() : true))(name, async () => {
await prisma.$transaction([prisma.user.findFirst({}), prisma.user.findFirst({})], {
isolationLevel: level(),
})
await waitFor(() => {
expect(queries).toContain(expectSql)
})
})
}
testIsolationLevel('ReadUncommitted', {
// @ts-test-if: !['cockroachdb'].includes(provider)
level: () => Prisma.TransactionIsolationLevel.ReadUncommitted,
onlyIf: () => !isCockroachDb,
expectSql: 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED',
})
testIsolationLevel('ReadCommitted', {
level: () => Prisma.TransactionIsolationLevel.ReadCommitted,
expectSql: 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED',
})
testIsolationLevel('RepeatableRead', {
// @ts-test-if: !['cockroachdb'].includes(provider)
level: () => Prisma.TransactionIsolationLevel.RepeatableRead,
onlyIf: () => !isCockroachDb,
expectSql: 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ',
})
testIsolationLevel('Serializable', {
level: () => Prisma.TransactionIsolationLevel.Serializable,
expectSql: 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE',
})
test('default value generates no SET TRANSACTION ISOLATION LEVEL statements (unless running MSSQL)', async () => {
await prisma.$transaction([prisma.user.findFirst({}), prisma.user.findFirst({})])
const match = queries.find((q) => q.includes('SET TRANSACTION ISOLATION LEVEL'))
if (isSqlServer && !usesJsDrivers) {
expect(match).toBeDefined()
} else {
expect(match).toBeUndefined()
}
})
test('invalid level generates run- and compile- time error', async () => {
// @ts-expect-error
const result = prisma.$transaction([prisma.user.findFirst({}), prisma.user.findFirst({})], {
isolationLevel: 'yes',
})
await expect(result).rejects.toMatchPrismaErrorInlineSnapshot(`
"
Invalid \`prisma.$transaction([prisma.user.findFirst()\` invocation in
/client/tests/functional/batch-transaction-isolation-level/tests.ts:0:0
XX
XX test('invalid level generates run- and compile- time error', async () => {
XX // @ts-expect-error
→ XX const result = prisma.$transaction([prisma.user.findFirst(
Inconsistent column data: Conversion failed: Invalid isolation level \`yes\`"
`)
})
},
{
optOut: {
from: ['mongodb', 'sqlite'],
reason: `
mongo - Not supported
sqlite, cockroach - Support only serializable level, never generate sql for setting isolation level
`,
},
skipDefaultClientInstance: true,
},
)