Skip to content

Commit

Permalink
Fix for directUrl usage during testing (#7898)
Browse files Browse the repository at this point in the history
* When testing an application with directUrl functionality in Prisma populate DIRECT_URL env variable with TEST_DIRECT_URL or TEST_DATABASE_URL

* Add regex parsing for directUrl env variable in schema.prisma and set it to test database

* refactor to add a test

* change back to project config

* more fixes from local testing

* remove stray `afterAll`

* set same env var in execa

---------

Co-authored-by: Dominic Saadi <dominiceliassaadi@gmail.com>
  • Loading branch information
aslaker and jtoar committed Mar 25, 2023
1 parent cf6dd8f commit b98d221
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 4 deletions.
5 changes: 3 additions & 2 deletions __fixtures__/empty-project/api/db/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
provider = "sqlite"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}

generator client {
Expand Down
19 changes: 17 additions & 2 deletions packages/testing/config/jest/api/globalSetup.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
const fs = require('fs')
const path = require('path')

const { getPaths } = require('@redwoodjs/project-config')

const {
getDefaultDb,
checkAndReplaceDirectUrl,
} = require('../../../dist/api/directUrlHelpers')

const rwjsPaths = getPaths()

module.exports = async function () {
Expand All @@ -10,8 +16,16 @@ module.exports = async function () {
// Load dotenvs
require('dotenv-defaults/config')

const cacheDirDb = `file:${path.join(__dirname, '.redwood', 'test.db')}`
process.env.DATABASE_URL = process.env.TEST_DATABASE_URL || cacheDirDb
const defaultDb = getDefaultDb(rwjsPaths.base)

process.env.DATABASE_URL = process.env.TEST_DATABASE_URL || defaultDb

const prismaSchema = fs.readFileSync(
path.join(rwjsPaths.api.dbSchema),
'utf-8'
)

const directUrlEnvVar = checkAndReplaceDirectUrl(prismaSchema, defaultDb)

const command =
process.env.TEST_DATABASE_STRATEGY === 'reset'
Expand All @@ -25,6 +39,7 @@ module.exports = async function () {
shell: true,
env: {
DATABASE_URL: process.env.DATABASE_URL,
[directUrlEnvVar]: process.env[directUrlEnvVar],
},
})
}
Expand Down
43 changes: 43 additions & 0 deletions packages/testing/src/api/__tests__/directUrlHelpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import fs from 'fs'
import path from 'path'

import { checkAndReplaceDirectUrl, getDefaultDb } from '../directUrlHelpers'

const FIXTURE_DIR_PATH = path.resolve('..', '..', '__fixtures__')

const NO_DIRECT_URL_FIXTURE_PATH = path.join(FIXTURE_DIR_PATH, 'test-project')
const DIRECT_URL_FIXTURE_PATH = path.join(FIXTURE_DIR_PATH, 'empty-project')

it("does nothing if directUrl isn't set", () => {
process.env.RWJS_CWD = NO_DIRECT_URL_FIXTURE_PATH

checkAndReplaceDirectUrl(
fs.readFileSync(
path.join(NO_DIRECT_URL_FIXTURE_PATH, 'api', 'db', 'schema.prisma'),
'utf-8'
),
getDefaultDb(NO_DIRECT_URL_FIXTURE_PATH)
)

expect(process.env.DIRECT_URL).toBeUndefined()

delete process.env.RWJS_CWD
})

it("overwrites directUrl if it's set", () => {
process.env.RWJS_CWD = DIRECT_URL_FIXTURE_PATH

const defaultDb = getDefaultDb(DIRECT_URL_FIXTURE_PATH)

const directUrlEnvVar = checkAndReplaceDirectUrl(
fs.readFileSync(
path.join(DIRECT_URL_FIXTURE_PATH, 'api', 'db', 'schema.prisma'),
'utf-8'
),
defaultDb
)

expect(process.env[directUrlEnvVar as string]).toBe(defaultDb)

delete process.env.RWJS_CWD
})
39 changes: 39 additions & 0 deletions packages/testing/src/api/directUrlHelpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import path from 'path'

export function getDefaultDb(rwjsCwd: string) {
return `file:${path.join(rwjsCwd, '.redwood', 'test.db')}`
}

export function checkAndReplaceDirectUrl(
prismaSchema: string,
defaultDb: string
) {
// Check the schema.prisma for a directUrl.
const directUrl = prismaSchema.match(PRISMA_DIRECT_URL_REGEXP)

// If it's not there, make this a no-op.
if (!directUrl) {
return
}

// If it is, set its env var to the test equivalent.
const directUrlEnvMatch = directUrl[0].match(BETWEEN_PARENTHESES_REGEXP) //[2]

// This is mostly to please TS. But it's good to be safe because in this case we want to be 100% correct.
if (!directUrlEnvMatch) {
throw new Error(
'Error parsing `directUrl` from schema.prisma. Proceeding with this env var could be dangerous. Please check your schema.prisma file; if everything looks ok, file an issue.'
)
}

// `directUrlEnvMatch` look something like `["(DIRECT_URL)", "", "DIRECT_URL"]`. We want the third element.
const directUrlEnv = directUrlEnvMatch[2]

process.env[directUrlEnv] =
process.env.TEST_DIRECT_URL || process.env.TEST_DATABASE_URL || defaultDb

return directUrlEnv
}

const PRISMA_DIRECT_URL_REGEXP = /directUrl(\s?)=(\s?)env\(('|")(.*)('|")\)/g
const BETWEEN_PARENTHESES_REGEXP = /\(('|")([^)]+)('|")\)/

0 comments on commit b98d221

Please sign in to comment.