Skip to content

Commit

Permalink
Merge pull request #521 from RobertBroersma/rb-testing
Browse files Browse the repository at this point in the history
[Testing] Improve testing capabilities for Web
  • Loading branch information
peterp authored May 28, 2020
2 parents f890802 + 55b6ca4 commit 40277e3
Show file tree
Hide file tree
Showing 27 changed files with 973 additions and 647 deletions.
2 changes: 1 addition & 1 deletion packages/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"license": "MIT",
"devDependencies": {
"@auth0/auth0-spa-js": "^1.7.0",
"@types/react": "^16.9.34",
"@types/react": "16.9.35",
"gotrue-js": "^0.9.25",
"netlify-identity-widget": "1.6.0",
"react": "^16.13.1"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup, screen } from '@testing-library/react'
import { render, cleanup, screen } from '@redwoodjs/testing'

import { Loading, Empty, Failure, Success } from './UserProfileCell'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup, screen } from '@testing-library/react'
import { render, cleanup, screen } from '@redwoodjs/testing'

import { Loading, Empty, Failure, Success } from './UserCell'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup, screen } from '@testing-library/react'
import { render, cleanup, screen } from '@redwoodjs/testing'

import { Loading, Empty, Failure, Success } from './${pascalName}Cell'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup } from '@testing-library/react'
import { render, cleanup } from '@redwoodjs/testing'

import UserProfile from './UserProfile'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup } from '@testing-library/react'
import { render, cleanup } from '@redwoodjs/testing'

import User from './User'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup } from '@testing-library/react'
import { render, cleanup } from '@redwoodjs/testing'

import ${pascalName} from './${pascalName}'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup } from '@testing-library/react'
import { render, cleanup } from '@redwoodjs/testing'

import SinglePageLayout from './SinglePageLayout'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup } from '@testing-library/react'
import { render, cleanup } from '@redwoodjs/testing'

import AppLayout from './AppLayout'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup } from '@testing-library/react'
import { render, cleanup } from '@redwoodjs/testing'

import ${pascalName}Layout from './${pascalName}Layout'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup } from '@testing-library/react'
import { render, cleanup } from '@redwoodjs/testing'

import ContactUsPage from './ContactUsPage'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup } from '@testing-library/react'
import { render, cleanup } from '@redwoodjs/testing'

import HomePage from './HomePage'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, cleanup } from '@testing-library/react'
import { render, cleanup } from '@redwoodjs/testing'

import ${pascalName}Page from './${pascalName}Page'

Expand Down
60 changes: 60 additions & 0 deletions packages/core/config/babel-plugin-routes-auto-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const path = require('path')

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

const redwoodPaths = getPaths()

module.exports = function ({ types: t }) {
// Process the dir to find all Page dependencies.
let deps = processPagesDir()

return {
visitor: {
// Remove any deps that have been explicitly declared in the Routes file. When one
// is present, the user is requesting that the module be included in the main
// bundle.
ImportDeclaration(path) {
const declaredImports = path.node.specifiers.map(
(specifier) => specifier.local.name
)

deps = deps.filter((dep) => !declaredImports.includes(dep.const))
},
Program: {
exit(nodePath) {
// Prepend all imports to the top of the file
deps.forEach((dep) => {
const basename = path.posix.basename(dep.const)
const importFile = [redwoodPaths.web.src, 'pages', basename].join(
'/'
)

nodePath.node.body.unshift(
t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier(dep.const),
t.objectExpression([
t.objectProperty(
t.identifier('name'),
t.stringLiteral(dep.const)
),
t.objectProperty(
t.identifier('loader'),
t.arrowFunctionExpression(
[],
t.callExpression(t.identifier('import'), [
t.stringLiteral(importFile),
])
)
),
])
),
])
)
})
},
},
},
}
}
9 changes: 9 additions & 0 deletions packages/core/config/babel-preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
* This is the babel preset used `create-redwood-app`
*/

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

// TODO: Determine what to do different during development, test, and production
// TODO: Take a look at create-react-app. They've dropped a ton of knowledge.

Expand Down Expand Up @@ -132,5 +135,11 @@ module.exports = () => ({
test: /.+Cell.(js|tsx)$/,
plugins: [require('./babel-plugin-redwood-cell')],
},
// Automatically import files in `src/pages/*` in to
// the `src/Routes.[ts|jsx]` file.
{
test: redwoodPaths.web.routes,
plugins: [require('./babel-plugin-routes-auto-loader')],
},
],
})
29 changes: 29 additions & 0 deletions packages/core/config/jest.config.web.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,40 @@

const path = require('path')

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

const redwoodPaths = getPaths()

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

module.exports = {
resolver: 'jest-directory-named-resolver',
// NOTE: We run the tests with a `cwd` argument that's `getPaths().web.base`
rootDir: process.cwd(),
globals: {
__REDWOOD__API_PROXY_PATH: '/',
},
setupFilesAfterEnv: [path.resolve(__dirname, './jest.setup.web.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'
),
/**
* 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',
},
}
11 changes: 0 additions & 11 deletions packages/core/config/webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,6 @@ module.exports = (webpackEnv) => {
},
],
},
{
// Automatically import files in `src/pages/*` in to
// the `src/Routes.[ts|jsx]` file.
test: redwoodPaths.web.routes,
use: {
loader: path.resolve(
__dirname,
'../dist/loaders/routes-auto-loader.js'
),
},
},
],
},
optimization: {
Expand Down
11 changes: 7 additions & 4 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
"@babel/preset-typescript": "^7.9.0",
"@babel/runtime-corejs3": "^7.9.2",
"@prisma/cli": "2.0.0-beta.5",
"@redwoodjs/testing": "0.7.0",
"@redwoodjs/cli": "^0.7.1-canary.8",
"@redwoodjs/dev-server": "^0.7.1-canary.8",
"@redwoodjs/eslint-config": "^0.7.1-canary.8",
"@redwoodjs/internal": "^0.7.1-canary.8",
"@testing-library/jest-dom": "^5.3.0",
"@testing-library/react": "^10.0.1",
"@testing-library/jest-dom": "^5.8.0",
"@types/jest": "^25.1.4",
"@types/node": "^13.9.5",
"@types/react": "16.9.34",
"@types/react-dom": "16.9.7",
"@types/react": "16.9.35",
"@types/react-dom": "16.9.8",
"@types/webpack": "^4.41.11",
"babel-jest": "^25.2.3",
"babel-loader": "^8.1.0",
Expand Down Expand Up @@ -68,5 +68,8 @@
},
"devDependencies": {
"babel-plugin-tester": "^9.0.1"
},
"resolutions": {
"@types/react": "16.9.35"
}
}
1 change: 1 addition & 0 deletions packages/testing/.babelrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { extends: '../../babel.config.js' }
35 changes: 35 additions & 0 deletions packages/testing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# @RedwoodJS/Testing

<!-- toc -->
- [Purpose and Vision](#Purpose-and-Vision)
- [Package Lead](#Package-Lead)
- [Roadmap](#Roadmap)
- [Contributing](#Contributing)

## Purpose and Vision

This package provides helpful defaults when testing a Redwood project's web side. The core of the project is an re-export of `@testing-library/react` with a custom `render` method.

## Usage

In a jest test:
```js
import { render, screen } from '@redwoodjs/testing
it('works as expected', () => {
render(<MyComponent />)
expect(screen.queryByText('Text in my component')).toBeInTheDocument()
}
```
## Package Lead
- [@RobertBroersma](https://github.com/RobertBroersma)
- [@peterp](https://github.com/peterp)
## Roadmap
See [[Testing] Support Jest --config extensibility](https://github.com/redwoodjs/redwood/issues/564)
## Contributing
Core technologies
- [Jest](https://jestjs.io/docs/en/getting-started)
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)
23 changes: 23 additions & 0 deletions packages/testing/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@redwoodjs/testing",
"description": "Tools, wrappers and defaults for testing a Redwood project.",
"version": "0.7.0",
"files": [
"dist"
],
"main": "dist/index.js",
"license": "MIT",
"peerDependencies": {
"@redwoodjs/router": "*",
"react": "*"
},
"dependencies": {
"@redwoodjs/internal": "^0.7.0",
"@redwoodjs/web": "^0.7.0",
"@testing-library/react": "^10.0.4"
},
"scripts": {
"build": "yarn cross-env NODE_ENV=production babel src -d dist --delete-dir-on-start --extensions \".js,.ts\" --source-maps inline",
"build:watch": "nodemon --watch src --ext 'js,ts,tsx' --ignore dist --exec 'yarn build'"
}
}
20 changes: 20 additions & 0 deletions packages/testing/src/MockRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react'
// We're bypassing the `main` field in `package.json` because we're
// replacing imports of `@redwoodjs/router` with this file, and not doing so
// would cause an infinite loop.
// See: ./packages/core/config/jest.config.web.js
export * from '@redwoodjs/router/dist/index'

export const routes = {}

/**
* This is used in place of the real router during tests.
* It populates the `routes.<pagename>()` utility object.
*/
export const Router = ({ children }) => {
for (let route of React.Children.toArray(children)) {
const { name } = route.props
routes[name] = jest.fn(() => name)
}
return <></>
}
6 changes: 6 additions & 0 deletions packages/testing/src/fileMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* configure Jest to gracefully handle asset files such as stylesheets and images.
* Usually, these files aren't particularly useful in tests so we can safely mock them out.
* https://jestjs.io/docs/en/webpack#handling-static-assets
*/
module.exports = 'fileMock'
5 changes: 5 additions & 0 deletions packages/testing/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { MockRouter } from './MockRouter'

// https://testing-library.com/docs/react-testing-library/setup#custom-render
export * from '@testing-library/react'
export { customRender as render } from './render'
23 changes: 23 additions & 0 deletions packages/testing/src/render.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react'
import { getPaths } from '@redwoodjs/internal'
import { render } from '@testing-library/react'

// Import the user's Router from `./web/src/Router.js`.
// We use the `children` from this Router that are rendered via
// `./MockRouter.Router` so that we can populate the `routes object`.
const { default: UserRouterWithRoutes } = require(getPaths().web.routes)

const AllTheProviders = ({ children }) => {
return (
<>
<UserRouterWithRoutes />
{children}
</>
)
}

export const customRender = (ui, options = {}) =>
render(ui, {
wrapper: (props) => <AllTheProviders {...props} />,
...options,
})
2 changes: 1 addition & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"dependencies": {
"@apollo/react-components": "^3.1.3",
"@apollo/react-hooks": "^3.1.3",
"@types/react": "16.9.34",
"@types/react": "16.9.35",
"apollo-boost": "0.4.7",
"apollo-cache": "^1.3.4",
"apollo-client": "^2.6.8",
Expand Down
Loading

0 comments on commit 40277e3

Please sign in to comment.