├── .circleci └── config.yml ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── cypress.json ├── cypress ├── integration │ └── spec.ts └── tsconfig.json ├── jest.config.js ├── package-lock.json ├── package.json ├── renovate.json ├── src ├── foo.test.ts └── foo.ts ├── tsconfig.json └── tsconfig.lint.json /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | orbs: 3 | cypress: cypress-io/cypress@1.27.0 4 | workflows: 5 | build: 6 | jobs: 7 | - cypress/run: 8 | # there are no jobs to follow this one 9 | # so no need to save the workspace files (saves time) 10 | no-workspace: true 11 | build: npm run lint && npm run lint:cypress 12 | # runs Cypress tests by default 13 | post-steps: 14 | - run: 15 | name: Jest tests 16 | command: npm test 17 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: [push] 3 | jobs: 4 | e2e: 5 | runs-on: ubuntu-20.04 6 | steps: 7 | - name: Checkout 🛎 8 | uses: actions/checkout@v2 9 | 10 | - name: Install and run Cypress tests 🌲 11 | uses: cypress-io/github-action@v2 12 | 13 | unit: 14 | runs-on: ubuntu-20.04 15 | steps: 16 | - name: Checkout 🛎 17 | uses: actions/checkout@v2 18 | 19 | # we are only interested in installing and caching dependencies, 20 | # without installing the Cypress binary 21 | - name: Install NPM dependencies 📦 22 | uses: bahmutov/npm-install@v1 23 | env: 24 | # we do not need to install Cypress itself 25 | # as we do not plan to run tests 26 | CYPRESS_INSTALL_BINARY: 0 27 | 28 | - name: Run Jest tests 🧪 29 | run: npm test 30 | 31 | unit-using-cypress-gh-action: 32 | runs-on: ubuntu-20.04 33 | steps: 34 | - name: Checkout 🛎 35 | uses: actions/checkout@v2 36 | 37 | # we are only interested in installing and caching dependencies, 38 | # without installing the Cypress binary 39 | - name: Install NPM dependencies 📦 40 | uses: cypress-io/github-action@v2 41 | # we do not want to accidentally overwrite 42 | # the full cache created in the e2e test job 43 | # because this job does not cache Cypress binary 44 | # thus we use custom cache key 45 | with: 46 | cache-key: unit-cache-v1-${{ runner.os }}-hash-${{ hashFiles('package-lock.json') }} 47 | env: 48 | # we do not need to install Cypress itself 49 | # as we do not plan to run tests 50 | CYPRESS_INSTALL_BINARY: 0 51 | 52 | - name: Run Jest tests 🧪 53 | run: npm test 54 | 55 | unit-without-any-helpers: 56 | runs-on: ubuntu-20.04 57 | steps: 58 | - name: Checkout 🛎 59 | uses: actions/checkout@v2 60 | 61 | # use actions/cache to restore / save cache 62 | - name: Cache dependencies 💎 63 | uses: actions/cache@v2 64 | with: 65 | path: ~/.npm 66 | # use key string with "v1" for simple cache invalidation 67 | key: dependencies-v1-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} 68 | 69 | - name: Install dependencies 📦 70 | run: npm ci 71 | env: 72 | # we do not need to install Cypress itself 73 | # as we do not plan to run tests 74 | CYPRESS_INSTALL_BINARY: 0 75 | 76 | - name: Run Jest tests 🧪 77 | run: npm test 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | src/*.js 3 | cypress/integration/*.js 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## MIT License 2 | 3 | Copyright (c) 2019 Cypress.io https://www.cypress.io 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cypress-and-jest-typescript-example [![renovate-app badge][renovate-badge]][renovate-app] [![CircleCI](https://circleci.com/gh/cypress-io/cypress-and-jest-typescript-example.svg?style=svg)](https://circleci.com/gh/cypress-io/cypress-and-jest-typescript-example) 2 | > Example using Jest and Cypress with TypeScript in a single repo 3 | 4 | If you are using Jest and Cypress types in the same project, they might conflict because both test runners use globals like `expect`. This project shows how to isolate Cypress TypeScript definitions from Jest TS definitions in the same project. 5 | 6 | See the root level [tsconfig.json](tsconfig.json) and [jest.config.js](jest.config.js). The Cypress types are isolated from the root in the file [cypress/tsconfig.json](cypress/tsconfig.json). The root tsconfig explicitly only includes `libs` with Jest globals (without Cypress) 7 | 8 | ## Linting 9 | 10 | While writing the production code, we want to limit ourselves to the `src` TS files without including the spec files. While linting, we want to lint all files. Thus we create a separate [tsconfig.lint.json](tsconfig.lint.json) file that includes all `src` files, but sets `noEmit: true` compiler option. The command `npm run lint` thus lints `src` folder, without Cypress files. 11 | 12 | To lint Cypress specs, we have a separate lint command that points at [cypress/tsconfig.json](cypress/tsconfig.json) file. 13 | 14 | ```json 15 | { 16 | "scripts": { 17 | "build": "tsc", 18 | "lint": "tsc --project tsconfig.lint.json", 19 | "lint:cypress": "tsc --project cypress/tsconfig.json" 20 | } 21 | } 22 | ``` 23 | 24 | ## Additional information 25 | 26 | See the excellent advice on setting TypeScript for Jest and Cypress in [TypeScript Deep Dive](https://basarat.gitbooks.io/typescript/content/) e-book by [Basarat Syed](https://twitter.com/basarat) 27 | 28 | - [Using Jest with TypeScript](https://basarat.gitbooks.io/typescript/docs/testing/jest.html) 29 | - [Cypress E2E with TypeScript](https://basarat.gitbooks.io/typescript/docs/testing/cypress.html) 30 | - Cypress TypeScript transpilation is using [built-in TS support](https://on.cypress.io/typescript) 31 | 32 | ## Questions or problems 33 | 34 | If you hit a problem using Jest and Cypress in the same project, please open an issue in this repository. Include a fork of this repository that shows the problem. 35 | 36 | ## CircleCI workflow 37 | 38 | The file [.circleci/config.yml](./.circleci/config.yml) shows how to run Cypress and Jest tests using [Cypress CircleCI Orb](https://github.com/cypress-io/circleci-orb) 39 | 40 | ## GitHub Actions workflow 41 | 42 | This repo shows how to install dependencies and how to run Jest test in separate jobs on GitHub Actions. See the workflow file [.github/workflows/ci.yml](./.github/workflows/ci.yml) for several different approaches 43 | 44 | - install and cache dependencies yourself using [actions/cache](http://github.com/actions/cache) 45 | - install and cache NPM dependencies using [bahmutov/npm-install](https://github.com/bahmutov/npm-install) helper 46 | - install and cache NPM dependencies using [cypress-io/github-action](https://github.com/cypress-io/github-action) 47 | 48 | **Tip:** you can learn more about running Cypress tests on continuous integration services from [Cypress CI guide](https://on.cypress.io/ci) and [Cypress on CI workshop](https://github.com/cypress-io/cypress-workshop-ci). 49 | 50 | ## License 51 | 52 | This project is licensed under the terms of the [MIT license](/LICENSE.md). 53 | 54 | [renovate-badge]: https://img.shields.io/badge/renovate-app-blue.svg 55 | [renovate-app]: https://renovateapp.com/ 56 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginsFile": false, 3 | "supportFile": false, 4 | "fixturesFolder": false 5 | } 6 | -------------------------------------------------------------------------------- /cypress/integration/spec.ts: -------------------------------------------------------------------------------- 1 | // import function from the application source 2 | import { sum } from '../../src/foo' 3 | 4 | describe('TypeScript spec', () => { 5 | it('works', () => { 6 | cy.wrap('foo').should('equal', 'foo') 7 | }) 8 | 9 | it('calls TS source file', () => { 10 | expect(sum(1, 2, 3, 4)).to.equal(10) 11 | }) 12 | }) 13 | 14 | // uncomment to get a lint error 15 | // const aCypressString: string = 42; 16 | -------------------------------------------------------------------------------- /cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | // be explicit about types included 6 | // to avoid clashing with Jest types 7 | "types": ["cypress"] 8 | }, 9 | "include": [ 10 | "../node_modules/cypress", 11 | "./**/*.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "roots": [ 3 | "/src" 4 | ], 5 | "transform": { 6 | "^.+\\.tsx?$": "ts-jest" 7 | }, 8 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cyts", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest", 8 | "cy:open": "cypress open", 9 | "build": "tsc", 10 | "lint": "tsc --project tsconfig.lint.json", 11 | "lint:cypress": "tsc --project cypress/tsconfig.json" 12 | }, 13 | "dependencies": { 14 | "@types/chai": "^4.1.7", 15 | "@types/mocha": "^8.0.0", 16 | "cypress": "6.8.0", 17 | "typescript": "^4.0.0" 18 | }, 19 | "devDependencies": { 20 | "@types/jest": "26.0.22", 21 | "jest": "26.6.3", 22 | "ts-jest": "26.5.4" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "automerge": true, 6 | "prHourlyLimit": 5, 7 | "updateNotScheduled": false, 8 | "timezone": "America/New_York", 9 | "schedule": [ 10 | "every weekend" 11 | ], 12 | "masterIssue": true 13 | } 14 | -------------------------------------------------------------------------------- /src/foo.test.ts: -------------------------------------------------------------------------------- 1 | import { sum } from './foo'; 2 | 3 | test('basic', () => { 4 | expect(sum()).toBe(0); 5 | }); 6 | 7 | test('basic again', () => { 8 | expect(sum(1, 2)).toBe(3); 9 | }); 10 | 11 | // uncomment to get a lint error 12 | // const aTestString: string = 42; 13 | -------------------------------------------------------------------------------- /src/foo.ts: -------------------------------------------------------------------------------- 1 | export const sum 2 | = (...a: number[]) => 3 | a.reduce((acc, val) => acc + val, 0); 4 | 5 | // uncomment to get a lint error 6 | // const aString: string = 42; 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "lib": ["ES2015", "DOM"], 6 | "strict": true, 7 | "types": ["jest"], 8 | "noEmit": true 9 | }, 10 | // only compile the production TS files 11 | "include": ["src/*.ts"], 12 | "exclude": ["src/*.test.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true 5 | }, 6 | "exclude": [] 7 | } 8 | --------------------------------------------------------------------------------