-
Notifications
You must be signed in to change notification settings - Fork 78
chore: Babel + Typescript example #408
Changes from all commits
7b85dda
0452686
9e331a3
a1d7a1d
90f0b0e
3d5c595
d49c96e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| package-lock=false |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| # example: using-babel | ||
|
|
||
| > Component testing for typescript projects using Babel config with `@babel/preset-typescript` | ||
|
|
||
|  | ||
|
|
||
| ## Usage | ||
|
|
||
| 1. Make sure the root project has been built . | ||
|
|
||
| ```bash | ||
| # in the root of the project | ||
| npm install | ||
| npm run build | ||
| ``` | ||
|
|
||
| 2. Run `npm install` in this folder to symlink the `cypress-react-unit-test` dependency. | ||
|
|
||
| ```bash | ||
| # in this folder | ||
| npm install | ||
| ``` | ||
|
|
||
| 3. Start Cypress | ||
|
|
||
| ```bash | ||
| npm run cy:open | ||
| # or just run headless tests | ||
| npm test | ||
| ``` | ||
|
|
||
| ## Specs | ||
|
|
||
| See spec files [src/\*.spec.js](src). The specs are bundled using [babel.config.js](babel.config.js) settings via [cypress/plugins/index.js](cypress/plugins/index.js) file that includes file preprocessor. | ||
|
|
||
| ```js | ||
| // let's bundle spec files and the components they include using | ||
| // the same bundling settings as the project by loading .babelrc | ||
| const preprocessor = require('cypress-react-unit-test/plugins/babelrc') | ||
| module.exports = (on, config) => { | ||
| preprocessor(on, config) | ||
| // IMPORTANT to return the config object | ||
| // with the any changed environment variables | ||
| return config | ||
| } | ||
| ``` | ||
|
|
||
| ## Mocking | ||
|
|
||
| During test runs, there is a Babel plugin that transforms ES6 imports into plain objects that can be stubbed using [cy.stub](https://on.cypress.io/stub). In essence | ||
|
|
||
| ```ts | ||
| // component imports named ES6 import from "calc.js | ||
| import { getRandomNumber } from './calc' | ||
| const Component = () => { | ||
| // then calls it | ||
| const n = getRandomNumber() | ||
| return <div className="random">{n}</div> | ||
| } | ||
| ``` | ||
|
|
||
| The test can mock that import before mounting the component | ||
|
|
||
| ```js | ||
| import Component from './Component' | ||
| import * as calc from './calc' | ||
| describe('Component', () => { | ||
| it('mocks call from the component', () => { | ||
| cy.stub(calc, 'getRandomNumber') | ||
| .returns(777) | ||
| mount(<Component />) | ||
| }) | ||
| }) | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| module.exports = { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Verified that it works also with
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sure, rename it
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I've been not clear. I mean the name of plugin itself. It will require breaking change, right? Or just make a new alias name?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. right - ok, in that case we probably better with an alias, like react-scripts is an alias to car. |
||
| presets: [ | ||
| '@babel/preset-env', | ||
| '@babel/preset-typescript', | ||
| '@babel/preset-react', | ||
| ], | ||
| plugins: ['@babel/plugin-proposal-class-properties'], | ||
| env: { | ||
| // place plugins for Cypress tests into "test" environment | ||
| // so that production bundle is not instrumented | ||
| test: { | ||
| plugins: [ | ||
| // during Cypress tests we want to instrument source code | ||
| // to get code coverage from tests | ||
| 'babel-plugin-istanbul', | ||
| // we also want to export ES6 modules as objects | ||
| // to allow mocking named imports | ||
| [ | ||
| '@babel/plugin-transform-modules-commonjs', | ||
| { | ||
| loose: true, | ||
| }, | ||
| ], | ||
| ], | ||
| }, | ||
| }, | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| { | ||
| "fixturesFolder": false, | ||
| "testFiles": "**/*spec.tsx", | ||
| "viewportWidth": 500, | ||
| "viewportHeight": 500, | ||
| "experimentalComponentTesting": true, | ||
| "componentFolder": "src" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| /// <reference types="cypress" /> | ||
| describe('integration spec', () => { | ||
| it('works', () => { | ||
| expect(1).to.equal(1) | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // let's bundle spec files and the components they include using | ||
| // the same bundling settings as the project by loading .babelrc | ||
| // https://github.com/bahmutov/cypress-react-unit-test#install | ||
| const preprocessor = require('cypress-react-unit-test/plugins/babelrc') | ||
| module.exports = (on, config) => { | ||
| preprocessor(on, config) | ||
| // IMPORTANT to return the config object | ||
| // with the any changed environment variables | ||
| return config | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| require('cypress-react-unit-test/dist/hooks') |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "name": "example-using-babel", | ||
| "description": "Component testing for projects using Babel config", | ||
| "private": true, | ||
| "scripts": { | ||
| "test": "node ../../scripts/cypress-expect run --passing 17", | ||
| "cy:open": "../../node_modules/.bin/cypress open" | ||
| }, | ||
| "devDependencies": { | ||
| "cypress-react-unit-test": "file:../.." | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import * as React from 'react' | ||
| import { Component } from './Component' | ||
| import * as calc from './calc' | ||
| import { mount } from 'cypress-react-unit-test' | ||
|
|
||
| // import the component and the file it imports | ||
| // stub the method on the imported "calc" and | ||
| // confirm the component renders the mock value | ||
| describe('Component', () => { | ||
| it('mocks call from the component', () => { | ||
| cy.stub(calc, 'getRandomNumber').returns(777) | ||
|
|
||
| mount(<Component />) | ||
|
|
||
| cy.get('.random').contains('777') | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import * as React from 'react' | ||
| import { getRandomNumber } from './calc' | ||
|
|
||
| /** | ||
| * Example React component that imports `getRandomNumber` | ||
| * function from another file and uses it to show a random | ||
| * number in the UI. | ||
| */ | ||
| export const Component = () => { | ||
| const n = getRandomNumber() | ||
| return <div className="random">{n}</div> | ||
| } | ||
|
|
||
| export default Component |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export const getRandomNumber = () => Math.round(Math.random() * 1000) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "compilerOptions": { | ||
| "jsx": "react", | ||
| "baseUrl": ".", | ||
| "noEmit": true, | ||
| "target": "esnext", | ||
| "types": ["cypress"], | ||
| // ⚠️ required only for demo purposes, remove from code | ||
| "paths": { | ||
| "cypress-react-unit-test": ["../../lib/index.ts"] | ||
| } | ||
| }, | ||
| "exclude": ["node_modules"], | ||
| "include": ["./src/**.ts*"] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,16 @@ const debug = require('debug')('cypress-react-unit-test') | |
| const webpackPreprocessor = require('@cypress/webpack-preprocessor') | ||
| const { addImageRedirect } = require('../utils/add-image-redirect') | ||
|
|
||
| const wpPreprocessorOptions = { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another question – do we need to keep using
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would not change unless necessary |
||
| ...webpackPreprocessor.defaultOptions, | ||
| } | ||
|
|
||
| wpPreprocessorOptions.webpackOptions.resolve = { | ||
| extensions: ['.js', '.ts', '.jsx', '.tsx', '.json'], | ||
| } | ||
|
|
||
| wpPreprocessorOptions.webpackOptions.module.rules[0].test = /\.(jsx|tsx|js|ts)?$/ | ||
|
|
||
| // note: modifies the input object | ||
| function enableBabelrc(webpackOptions) { | ||
| if (!Array.isArray(webpackOptions.module.rules)) { | ||
|
|
@@ -66,7 +76,6 @@ module.exports = config => { | |
| config && config.env && config.env.coverage === false | ||
| debug('coverage is disabled? %o', { coverageIsDisabled }) | ||
|
|
||
| const wpPreprocessorOptions = webpackPreprocessor.defaultOptions | ||
| enableBabelrc(wpPreprocessorOptions.webpackOptions) | ||
| debug('webpack options %o', wpPreprocessorOptions.webpackOptions) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What the motivation for using cypress/run instead of normal docker container with node?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
caching, all OSS dependencies are present, restores the CircleCI workspace correctly. If you want to recreate this, see the expanded config at circle, it is giant https://app.circleci.com/pipelines/github/bahmutov/cypress-react-unit-test/635/config
this config is 330 lines, expanded 1000
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally the above command would have "parallel" flag, in that case it skips the install. Since we are just reusing workspace from the previous install job, I have to hack skipping the install. I should probably just add a flag to our orb
install: falseto do this better