Skip to content

Commit

Permalink
test: Allow to conditionally skip type tests in new setup (#13712)
Browse files Browse the repository at this point in the history
Syntax: `@ts-error-if: condition` where condition can be any JS boolean
expression. It may also use any properties from suite config. During the
tests it will then turn into `// @ts-expect-error` commend if condition
evaluates to truthy value and stay the as is otherwise.

Fix prisma/client-planning#65
  • Loading branch information
SevInf committed Jun 13, 2022
1 parent 662cf8c commit e3d4631
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 7 deletions.
5 changes: 5 additions & 0 deletions packages/client/tests/functional/_example/tests.ts
Expand Up @@ -50,6 +50,11 @@ testMatrix.setupTestSuite(
expect(schemaString).toContain('datasource')
expect(schemaString).toContain('model')
})

testIf(suiteConfig.provider !== 'mongodb')('conditional @ts-test-if', async () => {
// @ts-test-if: provider !== 'mongodb'
await prisma.$queryRaw`SELECT 1;`
})
},
// Use `optOut` to opt out from testing the default selected providers
// otherwise the suite will require all providers to be specified.
Expand Down
3 changes: 3 additions & 0 deletions packages/client/tests/functional/_utils/setupFilesAfterEnv.ts
Expand Up @@ -5,4 +5,7 @@ process.env.DATABASE_URI_postgresql = process.env.TEST_POSTGRES_URI
process.env.DATABASE_URI_mysql = process.env.TEST_MYSQL_URI
process.env.DATABASE_URI_cockroachdb = process.env.TEST_COCKROACH_URI

globalThis.testIf = (condition: boolean) => (condition ? test : test.skip)
globalThis.describeIf = (condition: boolean) => (condition ? describe : describe.skip)

export {}
35 changes: 31 additions & 4 deletions packages/client/tests/functional/_utils/setupTestSuiteEnv.ts
@@ -1,6 +1,7 @@
import crypto from 'crypto'
import fs from 'fs-extra'
import path from 'path'
import { Script } from 'vm'

import { DbDrop } from '../../../../migrate/src/commands/DbDrop'
import { DbPush } from '../../../../migrate/src/commands/DbPush'
Expand All @@ -18,21 +19,47 @@ export async function setupTestSuiteFiles(suiteMeta: TestSuiteMeta, suiteConfig:

// we copy the minimum amount of files needed for the test suite
await fs.copy(path.join(suiteMeta.testDir, 'prisma'), path.join(suiteFolder, 'prisma'))
await copyWithImportsAdjust(
await copyPreprocessed(
path.join(suiteMeta.testDir, suiteMeta.testFileName),
path.join(suiteFolder, suiteMeta.testFileName),
suiteConfig,
)
await copyWithImportsAdjust(path.join(suiteMeta.testDir, '_matrix.ts'), path.join(suiteFolder, '_matrix.ts'))
await copyPreprocessed(path.join(suiteMeta.testDir, '_matrix.ts'), path.join(suiteFolder, '_matrix.ts'), suiteConfig)
await fs.copy(path.join(suiteMeta.testDir, 'package.json'), path.join(suiteFolder, 'package.json')).catch(() => {})
}

async function copyWithImportsAdjust(from: string, to: string): Promise<void> {
async function copyPreprocessed(from: string, to: string, suiteConfig: TestSuiteConfig): Promise<void> {
// we adjust the relative paths to work from the generated folder
const contents = await fs.readFile(from, 'utf8')
const newContents = contents.replace(/'..\//g, "'../../../")
const newContents = contents
.replace(/'..\//g, "'../../../")
.replace(/\/\/\s*@ts-test-if:(.+)/g, (match, condition) => {
if (!evaluateMagicComment(condition, suiteConfig)) {
return '// @ts-expect-error'
}
return match
})
await fs.writeFile(to, newContents, 'utf8')
}

/**
* Evaluates the condition from @ts-test-if magic comment as
* a JS expression.
* All properties from suite config are available as variables
* within the expression.
*
* @param conditionFromComment
* @param suiteConfig
* @returns
*/
function evaluateMagicComment(conditionFromComment: string, suiteConfig: TestSuiteConfig): boolean {
const script = new Script(conditionFromComment)
const value = script.runInNewContext({
...suiteConfig,
})
return Boolean(value)
}

/**
* Write the generated test suite schema to the test suite folder.
* @param suiteMeta
Expand Down
2 changes: 2 additions & 0 deletions packages/client/tests/functional/globals.d.ts
@@ -0,0 +1,2 @@
declare function testIf(condition: boolean): jest.It
declare function describeIf(condition: boolean): jest.Describe
13 changes: 10 additions & 3 deletions packages/client/tests/functional/typescript/tests.ts
Expand Up @@ -35,9 +35,16 @@ function getAllTestSuiteTypeChecks(fileNames: string[]) {
}

describe('typescript', () => {
const suitePaths = glob.sync('./**/.generated/**/*.ts', {
ignore: ['./**/.generated/**/*.d.ts', './**/.generated/**/_schema.ts'],
})
const suitePaths = glob
.sync('./**/.generated/**/*.ts', {
ignore: ['./**/.generated/**/*.d.ts', './**/.generated/**/_schema.ts'],
})
// global.d.ts does not really needs typechecking, but
// since no sources import it directly, it has to be included
// in the source set in order for global `describeIf` and `testIf` to
// be discovered
.concat([path.resolve(__dirname, '..', 'globals.d.ts')])

const suiteChecks = getAllTestSuiteTypeChecks(suitePaths)
const suiteTable = map(suitePaths, (path) => [getTestSuiteDisplayName(path), path])

Expand Down

0 comments on commit e3d4631

Please sign in to comment.