├── .circleci └── config.yml ├── .gitignore ├── .npmrc ├── .vscode └── settings.json ├── README.md ├── cypress.json ├── cypress ├── fixtures │ └── example.json ├── integration │ ├── spec-a.js │ ├── spec-b.js │ └── spec-c.js ├── plugins │ └── index.js └── support │ ├── commands.js │ └── index.js ├── package-lock.json ├── package.json ├── renovate.json ├── reporter-config.json ├── server.js └── test └── simple.test.ts /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | orbs: 3 | # use latest 1.x.y version of the orb 4 | # best practice is to use an exact version 5 | cypress: cypress-io/cypress@1.16.1 6 | node: circleci/node@1.1 7 | 8 | executors: 9 | chrome80-ff72: 10 | docker: 11 | - image: 'cypress/browsers:node13.6.0-chrome80-ff72' 12 | 13 | # simplest use case - do everything in a single job 14 | # workflows: 15 | # build: 16 | # jobs: 17 | # - cypress/run 18 | 19 | # run tests using Chrome browser 20 | # (requires custom executor with Cypress docker image that has Chrome installed) 21 | # workflows: 22 | # build: 23 | # jobs: 24 | # - cypress/run: 25 | # executor: cypress/browsers-chrome69 26 | # browser: chrome 27 | 28 | # single job, but build the app and start server 29 | # workflows: 30 | # build: 31 | # jobs: 32 | # - cypress/run: 33 | # build: "npm run build" 34 | # start: "npm run server" 35 | 36 | # run only specific spec file 37 | # workflows: 38 | # build: 39 | # jobs: 40 | # - cypress/run: 41 | # record: false 42 | # spec: "cypress/integration/*-b.js" 43 | jobs: 44 | unit: 45 | executor: 46 | name: node/default 47 | tag: '12' 48 | steps: 49 | - checkout 50 | - node/with-cache: 51 | steps: 52 | - run: npm ci 53 | - run: npm test 54 | 55 | # custom cypress run command 56 | workflows: 57 | # a workflow to run on dependency updates with Renovate 58 | dependencies: 59 | jobs: 60 | - cypress/run: 61 | name: test dependencies 62 | filters: 63 | branches: 64 | only: /renovate.*/ 65 | no-workspace: true 66 | record: true 67 | tags: dependencies,renovate 68 | 69 | build: 70 | jobs: 71 | # could not run unit tests on Circle, validating config files 72 | # always caused an error: 73 | # Error: Configuration version 2.1 requires the "Enable Pipelines" project setting. 74 | # Enable pipelines under Project Settings -> Advanced Settings. 75 | # In order to retrigger pipelines, you must push a new commit. 76 | # 77 | # - unit 78 | 79 | # checks out code and installs dependencies once 80 | - cypress/run: 81 | filters: 82 | branches: 83 | ignore: /^renovate/ 84 | name: Mochawesome report 85 | # it is a single job, so no need to 86 | # cache workspace (faster!) 87 | no-workspace: true 88 | command: 'npm run report' 89 | post-steps: 90 | - store_test_results: 91 | path: cypress/results 92 | 93 | # run tests inside Docker image with Chrome pre-installed 94 | - cypress/run: 95 | filters: 96 | branches: 97 | ignore: /^renovate/ 98 | name: Chrome 80 99 | executor: chrome80-ff72 100 | no-workspace: true 101 | record: true 102 | browser: chrome 103 | # before running tests, show if any environment variables 104 | # starting with CYPRESS are set 105 | # using https://github.com/bahmutov/print-env 106 | build: npx has-env CYPRESS 107 | 108 | # realistic case: install in 1 job, 109 | # run tests in parallel on several machines after that 110 | # workflows: 111 | # build: 112 | # jobs: 113 | # # checks out code and installs dependencies once 114 | # - cypress/install: 115 | # build: 'npm run build' 116 | # # runs on 3 machines, load balances tests 117 | # # and records on Cypress Dashboard 118 | # - cypress/run: 119 | # requires: 120 | # - cypress/install 121 | # record: true 122 | # parallel: true 123 | # parallelism: 3 124 | # group: '3x' 125 | # start: 'npm run server' 126 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | cypress/videos 3 | cypress/results 4 | cypress/screenshots 5 | mochawesome.json 6 | mochawesome-report 7 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=http://registry.npmjs.org/ 2 | save-exact=true 3 | progress=false 4 | package-lock=true 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cypress CircleCI Orb Example 2 | 3 | [![CircleCI](https://circleci.com/gh/cypress-io/cypress-example-circleci-orb.svg?style=svg&circle-token=35ff1103f3c44a79246edd491b0d92169e84976a)](https://circleci.com/gh/cypress-io/cypress-example-circleci-orb) [![Cypress Dashboard](https://img.shields.io/badge/cypress-dashboard-brightgreen.svg)](https://dashboard.cypress.io/#/projects/j35334/runs) [![renovate-app badge][renovate-badge]][renovate-app] 4 | 5 | [Cypress CircleCI Orb](https://github.com/cypress-io/circleci-orb) 6 | 7 | [renovate-badge]: https://img.shields.io/badge/renovate-app-blue.svg 8 | [renovate-app]: https://renovateapp.com/ 9 | 10 | ## Introduction 11 | 12 | This project installs npm dependencies, runs Cypress tests and records the output to the Cypress Dashboard on CircleCI. See [.circleci/config.yml](.circleci/config.yml): 13 | 14 | ```yaml 15 | version: 2.1 16 | orbs: 17 | cypress: cypress/cypress@dev:0.0.1 18 | workflows: 19 | build: 20 | jobs: 21 | # record Cypress tests on the Dashboard 22 | - cypress/run: 23 | group: "all tests" 24 | record: true 25 | ``` 26 | 27 | Or you can run without recording on the dashboard: 28 | 29 | ```yaml 30 | version: 2.1 31 | orbs: 32 | cypress: cypress/cypress@dev:0.0.1 33 | workflows: 34 | build: 35 | jobs: 36 | - cypress/run 37 | ``` 38 | 39 | The hierarchy: 40 | 41 | ``` 42 | Workflow -> Jobs --> Commands -> define steps 43 | -> run on Executors 44 | ``` 45 | 46 | ## Development 47 | 48 | - Check if you are correctly using the Cypress CircleCI Orb in the [.circleci/config.yml](.circleci/config.yml) file by running `npm run validate`. 49 | - You can expand all commands from the orb and see how the "processed" [.circleci/config.yml](.circleci/config.yml) looks during the run on CircleCI. Execute `npm run process` to print the processed YAML in the terminal. 50 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectId": "j35334" 3 | } 4 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/integration/spec-a.js: -------------------------------------------------------------------------------- 1 | describe('spec a', () => { 2 | it('works', () => { 3 | cy.wrap('foo').should('be.equal', 'foo') 4 | }) 5 | it('waits a little', () => { 6 | cy.wait(10000) 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /cypress/integration/spec-b.js: -------------------------------------------------------------------------------- 1 | describe('spec b', () => { 2 | it('works', () => { 3 | cy.wrap('foo').should('be.equal', 'foo') 4 | }) 5 | it('waits a little', () => { 6 | cy.wait(10000) 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /cypress/integration/spec-c.js: -------------------------------------------------------------------------------- 1 | describe('spec c', () => { 2 | it('works', () => { 3 | cy.wrap('foo').should('be.equal', 'foo') 4 | }) 5 | it('waits a little', () => { 6 | cy.wait(10000) 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | module.exports = (on, config) => { 15 | // `on` is used to hook into various events Cypress emits 16 | // `config` is the resolved Cypress config 17 | } 18 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cypress-example-circleci-orb", 3 | "version": "1.0.0", 4 | "description": "Example project that shows Cypress CircleCI Orb in action", 5 | "main": "index.js", 6 | "private": true, 7 | "scripts": { 8 | "test": "npm run unit", 9 | "validate": "circleci config validate .circleci/config.yml", 10 | "process": "circleci config process .circleci/config.yml", 11 | "build": "echo building app 😃", 12 | "server": "node ./server", 13 | "unit": "ava-ts --verbose 'test/*.test.ts'", 14 | "cy:run": "cypress run", 15 | "delete:reports": "rm cypress/results/* || true", 16 | "prereport": "npm run delete:reports", 17 | "report": "cypress run --record false --reporter mocha-multi-reporters --reporter-options configFile=reporter-config.json" 18 | }, 19 | "engines": { 20 | "node": ">=10", 21 | "npm": ">=6" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/cypress-io/cypress-example-circleci-orb.git" 26 | }, 27 | "keywords": [], 28 | "author": "Gleb Bahmutov (https://glebbahmutov.com/)", 29 | "license": "ISC", 30 | "bugs": { 31 | "url": "https://github.com/cypress-io/cypress-example-circleci-orb/issues" 32 | }, 33 | "homepage": "https://github.com/cypress-io/cypress-example-circleci-orb#readme", 34 | "devDependencies": { 35 | "@bahmutov/print-env": "1.2.0", 36 | "@types/common-tags": "1.8.0", 37 | "@types/execa": "0.9.0", 38 | "@types/node": "10.17.16", 39 | "@types/temp-write": "3.3.0", 40 | "ava": "3.3.0", 41 | "ava-ts": "0.25.2", 42 | "cypress": "4.0.2", 43 | "execa": "2.1.0", 44 | "husky": "4.3.7", 45 | "js-yaml": "3.13.1", 46 | "mocha": "5.2.0", 47 | "mocha-junit-reporter": "1.23.3", 48 | "mocha-multi-reporters": "1.1.7", 49 | "temp-write": "4.0.0", 50 | "ts-node": "7.0.1", 51 | "typescript": "3.7.5" 52 | }, 53 | "husky": { 54 | "hooks": { 55 | "pre-commit": "npm run validate && npm run unit" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "automerge": true, 6 | "commitMessage": "{{semanticPrefix}}Update {{depName}} to {{newVersion}} 🌟", 7 | "prTitle": "{{semanticPrefix}}{{#if isPin}}Pin{{else}}Update{{/if}} dependency {{depName}} to version {{newVersion}} 🌟", 8 | "major": { 9 | "automerge": false 10 | }, 11 | "minor": { 12 | "automerge": false 13 | }, 14 | "prConcurrentLimit": 3, 15 | "prHourlyLimit": 2, 16 | "schedule": [ 17 | "after 10pm and before 5am on every weekday", 18 | "every weekend" 19 | ], 20 | "updateNotScheduled": false, 21 | "timezone": "America/New_York", 22 | "lockFileMaintenance": { 23 | "enabled": true 24 | }, 25 | "separatePatchReleases": true, 26 | "separateMultipleMajor": true, 27 | "masterIssue": true, 28 | "labels": [ 29 | "type: dependencies", 30 | "renovate" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /reporter-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "reporterEnabled": "spec, mocha-junit-reporter", 3 | "reporterOptions": { 4 | "mochaFile": "cypress/results/results-[hash].xml" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const message = () => { 2 | console.log('server is running') 3 | } 4 | setInterval(message, 5000) 5 | console.log('server has started ...') 6 | console.log('will print message every 5 seconds') 7 | -------------------------------------------------------------------------------- /test/simple.test.ts: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import { stripIndent } from 'common-tags' 3 | import * as execa from 'execa' 4 | import * as tempWrite from 'temp-write' 5 | 6 | const validate = (filename: string): Promise => { 7 | const cmd = `circleci config validate ${filename}` 8 | return execa(cmd, { stdio: 'inherit', shell: true }) 9 | } 10 | 11 | const validateConfig = (config: string): Promise => { 12 | const filename = tempWrite.sync(config + '\n\n', 'config.yml') 13 | return validate(filename) 14 | } 15 | 16 | const orb = 'cypress-io/cypress@1.14.0' 17 | 18 | test('simple', t => { 19 | t.plan(0) 20 | const config = stripIndent` 21 | # simple example workflow 22 | version: 2.1 23 | orbs: 24 | cypress: ${orb} 25 | workflows: 26 | build: 27 | jobs: 28 | - cypress/run 29 | ` 30 | return validateConfig(config) 31 | }) 32 | 33 | test('chrome browser', t => { 34 | t.plan(0) 35 | const config = stripIndent` 36 | # simple example workflow 37 | version: 2.1 38 | orbs: 39 | cypress: ${orb} 40 | workflows: 41 | build: 42 | jobs: 43 | - cypress/run: 44 | executor: cypress/browsers-chrome69 45 | browser: chrome 46 | ` 47 | return validateConfig(config) 48 | }) 49 | 50 | test('build and start commands', t => { 51 | t.plan(0) 52 | const config = stripIndent` 53 | # simple example workflow 54 | version: 2.1 55 | orbs: 56 | cypress: ${orb} 57 | workflows: 58 | build: 59 | jobs: 60 | - cypress/run: 61 | build: "npm run build" 62 | start: "npm run server" 63 | ` 64 | return validateConfig(config) 65 | }) 66 | 67 | test('custom cypress run command', t => { 68 | t.plan(0) 69 | const config = stripIndent` 70 | # simple example workflow 71 | version: 2.1 72 | orbs: 73 | cypress: ${orb} 74 | workflows: 75 | build: 76 | jobs: 77 | # checks out code and installs dependencies once 78 | - cypress/run: 79 | command: 'npm run cy:run -- --record false' 80 | ` 81 | return validateConfig(config) 82 | }) 83 | 84 | test('two jobs with parallel tests', t => { 85 | t.plan(0) 86 | const config = stripIndent` 87 | # simple example workflow 88 | version: 2.1 89 | orbs: 90 | cypress: ${orb} 91 | workflows: 92 | build: 93 | jobs: 94 | - cypress/install: 95 | build: 'npm run build' 96 | - cypress/run: 97 | requires: 98 | - cypress/install 99 | record: true 100 | parallel: true 101 | parallelism: 3 102 | group: '3x' 103 | start: 'npm run server' 104 | ` 105 | return validateConfig(config) 106 | }) 107 | --------------------------------------------------------------------------------