Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configure Jest dynamically per side #805

Merged
merged 8 commits into from
Jul 15, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 66 additions & 46 deletions packages/cli/src/commands/test.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,46 @@
import execa from 'execa'
import Listr from 'listr'
import VerboseRenderer from 'listr-verbose-renderer'
import terminalLink from 'terminal-link'

import { getPaths } from 'src/lib'
import c from 'src/lib/colors'

const jest = require('jest')

// TODO: Get from redwood.toml
const sides = ['web', 'api']
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved

// https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/scripts/test.js#L39
function isInGitRepository() {
try {
execa.commandSync('git rev-parse --is-inside-work-tree')
return true
} catch (e) {
return false
}
}

function isInMercurialRepository() {
try {
execa.commandSync('hg --cwd . root')
return true
} catch (e) {
return false
}
}
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved

export const command = 'test [side..]'
export const description = 'Run Jest tests for api and web'
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved
export const builder = (yargs) => {
yargs
.positional('side', {
choices: ['api', 'web'],
default: ['api', 'web'],
description: 'Which side(s) to test',
type: 'array',
.choices('side', sides)
.option('watch', {
type: 'boolean',
})
.option('watchAll', {
type: 'boolean',
})
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved
.option('collectCoverage', {
type: 'boolean',
})
.epilogue(
`Also see the ${terminalLink(
Expand All @@ -24,51 +50,45 @@ export const builder = (yargs) => {
)
}

export const handler = async ({ side }) => {
const { base: BASE_DIR, cache: CACHE_DIR } = getPaths()
export const handler = async ({ side, watch, watchAll, collectCoverage }) => {
const { cache: CACHE_DIR } = getPaths()
const sides = [].concat(side).filter(Boolean)

const DB_URL = process.env.TEST_DATABASE_URL || `file:${CACHE_DIR}/test.db`
const args = [
'--passWithNoTests',
watch && '--watch',
collectCoverage && '--collectCoverage',
watchAll && '--watchAll',
].filter(Boolean)

const execCommands = {
api: {
cwd: `${BASE_DIR}/api`,
cmd: `DATABASE_URL=${DB_URL} yarn rw db up && yarn jest`,
args: [
'--passWithNoTests',
'--config ../node_modules/@redwoodjs/core/config/jest.config.api.js',
],
},
web: {
cwd: `${BASE_DIR}/web`,
cmd: 'yarn jest',
args: [
'--passWithNoTests',
'--config ../node_modules/@redwoodjs/core/config/jest.config.web.js',
],
},
// Watch unless on CI or explicitly running all tests
if (!process.env.CI && !watchAll && !collectCoverage) {
// https://github.com/facebook/create-react-app/issues/5210
const hasSourceControl = isInGitRepository() || isInMercurialRepository()
args.push(hasSourceControl ? '--watch' : '--watchAll')
}

const tasks = new Listr(
side.map((sideName) => {
const { cmd, args, cwd } = execCommands[sideName]
return {
title: `Running '${sideName}' jest tests`,
task: () => {
return execa(cmd, args, {
stdio: 'inherit',
shell: true,
cwd,
})
},
}
}),
{
renderer: VerboseRenderer,
}
)
args.push('--config', './node_modules/@redwoodjs/core/config/jest.config.js')
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved

if (sides.length > 0) {
args.push('--projects', ...sides)
}

try {
await tasks.run()
/**
* Migrate test database. This should be moved to somehow be done on a
* per-side basis if possible.
*/
const DATABASE_URL =
process.env.TEST_DATABASE_URL || `file:${CACHE_DIR}/test.db`

await execa.command(`yarn rw db up`, {
stdio: 'inherit',
shell: true,
env: { DATABASE_URL },
})

jest.run(args)
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved
} catch (e) {
console.log(c.error(e.message))
}
Expand Down
10 changes: 8 additions & 2 deletions packages/core/config/babel-preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ const TARGETS_NODE = '12.16.1'
// were added in minor core-js releases.
const CORE_JS_VERSION = '3.6'

const path = require('path')

const { getPaths } = require('@redwoodjs/internal')

const redwoodPaths = getPaths()

module.exports = () => ({
presets: ['@babel/preset-react', '@babel/preset-typescript'],
plugins: [
Expand Down Expand Up @@ -57,7 +63,7 @@ module.exports = () => ({
'babel-plugin-module-resolver',
{
alias: {
src: './src',
src: path.join(redwoodPaths.api.base, 'src'),
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved
},
},
],
Expand Down Expand Up @@ -101,7 +107,7 @@ module.exports = () => ({
'babel-plugin-module-resolver',
{
alias: {
src: './src',
src: path.join(redwoodPaths.web.base, 'src'),
},
},
],
Expand Down
10 changes: 0 additions & 10 deletions packages/core/config/jest.config.api.js

This file was deleted.

18 changes: 18 additions & 0 deletions packages/core/config/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// used by cli `rw test` command

const path = require('path')

const { getPaths } = require('@redwoodjs/internal')

const redwoodPaths = getPaths()

module.exports = {
collectCoverageFrom: [
'**/*.{js,jsx,ts,tsx}',
'!**/node_modules/**',
'!**/dist/**',
],
coverageDirectory: path.join(redwoodPaths.base, 'coverage'),
rootDir: redwoodPaths.base,
projects: ['<rootDir>/{,!(node_modules)/**/}jest.config.js'],
peterp marked this conversation as resolved.
Show resolved Hide resolved
}
43 changes: 0 additions & 43 deletions packages/core/config/jest.config.web.js

This file was deleted.

8 changes: 6 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"config",
"dist"
],
"main": "dist/index.js",
"types": "dist/index.d.ts",
"dependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.0",
Expand Down Expand Up @@ -44,7 +46,7 @@
"graphql": "^14.6.0",
"graphql-tag": "^2.10.3",
"html-webpack-plugin": "^4.0.2",
"jest": "^25.2.3",
"jest": "^26.1.0",
"jest-directory-named-resolver": "^0.3.0",
"lodash.escaperegexp": "^4.1.2",
"mini-css-extract-plugin": "^0.9.0",
Expand All @@ -60,7 +62,9 @@
},
"gitHead": "1cb7c8d1085147787209af423c33a9c91c3e6517",
"scripts": {
"build": "yarn cross-env NODE_ENV=production babel src --out-dir dist --extensions \".js,.ts,.tsx\" --delete-dir-on-start",
"build": "yarn build:js && yarn build:types",
"build:js": "yarn cross-env NODE_ENV=production babel src --out-dir dist --extensions \".js,.ts,.tsx\" --delete-dir-on-start",
"build:types": "tsc --build --clean && tsc --build",
"prepublishOnly": "yarn build",
"build:watch": "nodemon --watch src --ext \"js,ts,tsx\" --ignore dist --exec \"yarn build\"",
"test": "jest",
Expand Down
56 changes: 56 additions & 0 deletions packages/core/src/browser/config/getBrowserJestConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// used by cli `rw test` command

const path = require('path')

const { getPaths } = require('@redwoodjs/internal')

const redwoodPaths = getPaths()

const NODE_MODULES_PATH = path.join(redwoodPaths.base, 'node_modules')

export function getBrowserJestConfig() {
return {
displayName: {
color: 'blueBright',
name: 'browser',
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved
},

resolver: 'jest-directory-named-resolver',
// NOTE: We run the tests with a `cwd` argument that's `getPaths().web.base`
// testMatch,
globals: {
__REDWOOD__: true,
__REDWOOD__API_PROXY_PATH: '/',
},
// transform: { '\\.js$': ['babel-jest', { rootMode: 'upward' }] },
setupFilesAfterEnv: [path.resolve(__dirname, './jest.setup.browser.js')],
moduleNameMapper: {
/**
* Make sure modules that require different versions of these
* dependencies end up using the same one.
*/
'^react$': path.join(NODE_MODULES_PATH, 'react'),
'^react-dom$': path.join(NODE_MODULES_PATH, 'react-dom'),
'^@apollo/react-common$': path.join(
NODE_MODULES_PATH,
'@apollo/react-common'
),
// We replace imports to "@redwoodjs/router" with our own implementation.
'^@redwoodjs/router$': path.join(
NODE_MODULES_PATH,
'@redwoodjs/testing/dist/MockRouter.js'
),
'^@redwoodjs/web$': path.join(NODE_MODULES_PATH, '@redwoodjs/web'),
'^@redwoodjs/testing$': path.join(
NODE_MODULES_PATH,
'@redwoodjs/testing'
),
'~__REDWOOD__USER_ROUTES_FOR_MOCK': getPaths().web.routes,
/**
* Mock out files that aren't particularly useful in tests. See fileMock.js for more info.
*/
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|css)$':
'@redwoodjs/testing/dist/fileMock.js',
},
}
}
39 changes: 39 additions & 0 deletions packages/core/src/getConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { getBrowserJestConfig } from './browser/config/getBrowserJestConfig'
import { getNodeJestConfig } from './node/config/getNodeJestConfig'

// TODO: Add more types like eslint, babel, etc?
// TODO: Move somewhere else
enum ConfigType {
Jest = 'jest',
}

// TODO: Add more build targets
// TODO: Move somewhere else
enum BuildTarget {
Browser = 'browser',
Node = 'node',
}
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved

interface GetJestConfigParams {
type: ConfigType.Jest
target: BuildTarget
}

const jestConfigMap = {
[BuildTarget.Browser]: getBrowserJestConfig,
[BuildTarget.Node]: getNodeJestConfig,
}

function getJestConfig({ target }: GetJestConfigParams) {
return jestConfigMap[target]()
}

const configMap = {
jest: getJestConfig,
}

type GetConfigParams = GetJestConfigParams

export function getConfig(opts: GetConfigParams) {
return configMap[opts.type](opts)
}
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { getConfig } from './getConfig'
13 changes: 13 additions & 0 deletions packages/core/src/node/config/getNodeJestConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const path = require('path')

export function getNodeJestConfig() {
return {
displayName: {
color: 'redBright',
name: 'node',
},

resolver: 'jest-directory-named-resolver',
setupFilesAfterEnv: [path.resolve(__dirname, './jest.setup.node.js')],
RobertBroersma marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading