Skip to content

Commit

Permalink
add Happo visual tests for a component test (#205)
Browse files Browse the repository at this point in the history
  • Loading branch information
bahmutov authored May 13, 2020
1 parent fe6f6ac commit c068ae6
Show file tree
Hide file tree
Showing 27 changed files with 1,201 additions and 89 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ Folder Name | Description
--- | ---
[react-scripts](examples/react-scripts) | A project using `react-scripts` with component tests in `src` folder
[react-scripts-folder](examples/react-scripts-folder) | A project using `react-scripts` with component tests in `cypress/component`
[visual-testing](examples/visual-testing) | [Visual testing](https://on.cypress.io/visual-testing) for components using 3rd party service Percy
[visual-testing-with-percy](examples/visual-testing-with-percy) | [Visual testing](https://on.cypress.io/visual-testing) for components using 3rd party service [Percy.io](https://percy.io/)
[visual-testing-with-happo](examples/visual-testing-with-happo) | [Visual testing](https://on.cypress.io/visual-testing) for components using 3rd party service [Happo](https://happo.io/)
[webpack-options](examples/webpack-options) | Using the default Webpack options from `@cypress/webpack-preprocessor` to transpile JSX specs
<!-- prettier-ignore-end -->

Expand Down Expand Up @@ -237,7 +238,7 @@ If you are using [plugins/cra-v3](plugins/cra-v3) it instruments the code on the

## Visual testing

You can use any Cypress [Visual Testing plugin](https://on.cypress.io/plugins#visual-testing) to perform [visual testing](https://on.cypress.io/visual-testing) from the component tests. This repo uses [Percy.io](https://percy.io) visual diffing service as a GitHub pull request check, see [visual-testing](examples/visual-testing) example.
You can use any Cypress [Visual Testing plugin](https://on.cypress.io/plugins#visual-testing) to perform [visual testing](https://on.cypress.io/visual-testing) from the component tests. This repo has several example projects, see [visual-testing-with-percy](examples/visual-testing-with-percy) and [visual-testing-with-happo](examples/visual-testing-with-happo)

## Common problems

Expand Down
25 changes: 22 additions & 3 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,33 @@ workflows:
store_artifacts: true

- cypress/run:
name: Example Visual Testing
name: Visual with Percy
executor: cypress/base-12
requires:
- Install
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
install-command: npm install
verify-command: echo 'Already verified'
no-workspace: true
working_directory: examples/visual-testing
working_directory: examples/visual-testing-with-percy
# run Percy agent and then run Cypress component tests
# https://docs.percy.io/docs/cypress
command: npx percy exec -- npm test
store_artifacts: true

- cypress/run:
name: Visual with Happo
executor: cypress/base-12
requires:
- Install
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
install-command: npm install
verify-command: echo 'Already verified'
no-workspace: true
working_directory: examples/visual-testing-with-happo
command: npm test
store_artifacts: true

- cypress/run:
name: Test
executor: cypress/base-12
Expand All @@ -102,6 +115,11 @@ workflows:
# only we will run semantic release script instead
- cypress/run:
name: NPM release
# only run NPM release from specific branch(es)
filters:
branches:
only:
- master
# we need newer Node for semantic release
executor: cypress/base-12
requires:
Expand All @@ -110,7 +128,8 @@ workflows:
- Example React Scripts
- Example Component Folder
- Example Webpack options
- Example Visual Testing
- Visual with Percy
- Visual with Happo
install-command: echo 'Already installed'
verify-command: echo 'Already verified'
no-workspace: true
Expand Down
18 changes: 18 additions & 0 deletions examples/visual-testing-with-happo/.happo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// https://docs.happo.io/docs/cypress
const { RemoteBrowserTarget } = require('happo.io')

// use the same resolution as cypress.json
const cypressConfig = require('./cypress.json')
const width = cypressConfig.viewportWidth || 1000
const height = cypressConfig.viewportHeight || 660
const viewport = `${width}x${height}`

module.exports = {
apiKey: process.env.HAPPO_API_KEY,
apiSecret: process.env.HAPPO_API_SECRET,
targets: {
chrome: new RemoteBrowserTarget('chrome', {
viewport,
}),
},
}
File renamed without changes.
3 changes: 3 additions & 0 deletions examples/visual-testing-with-happo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# example: visual-testing-with-happo

> Visual component testing using [Happo.io](https://docs.happo.io/docs/cypress)
8 changes: 8 additions & 0 deletions examples/visual-testing-with-happo/cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"fixturesFolder": false,
"testFiles": "**/*cy-spec.js",
"viewportWidth": 400,
"viewportHeight": 700,
"experimentalComponentTesting": true,
"componentFolder": "src"
}
10 changes: 10 additions & 0 deletions examples/visual-testing-with-happo/cypress/plugins/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const preprocessor = require('../../../../plugins/react-scripts')
const happoTask = require('happo-cypress/task')

module.exports = (on, config) => {
on('task', happoTask)
preprocessor(on, config)
// IMPORTANT to return the config object
// with the any changed environment variables
return config
}
3 changes: 3 additions & 0 deletions examples/visual-testing-with-happo/cypress/support/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require('cypress-react-unit-test/support')
require('@cypress/code-coverage/support')
require('happo-cypress')
12 changes: 12 additions & 0 deletions examples/visual-testing-with-happo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "example-happo",
"description": "Visual component testing using Happo.io",
"private": true,
"scripts": {
"test": "../../node_modules/.bin/cypress run",
"cy:open": "../../node_modules/.bin/cypress open"
},
"devDependencies": {
"cypress-react-unit-test": "file:../.."
}
}
78 changes: 78 additions & 0 deletions examples/visual-testing-with-happo/src/Calendar.cy-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/// <reference types="cypress" />
import React from 'react'
import { mount } from 'cypress-react-unit-test'
import Calendar from './Calendar'
import CalendarHeatmap from 'react-calendar-heatmap'
import 'react-calendar-heatmap/dist/styles.css'

describe('Calendar heatmap', () => {
// Skipping the test because the tooltip does not get cleaned correctly
// when the next test starts, see issue
// https://github.com/bahmutov/cypress-react-unit-test/issues/206
it.skip('random data', () => {
// we cannot really screenshot random data for visual testing
mount(<Calendar />)
cy.get('.react-calendar-heatmap')

cy.log('Check tooltip')
// first there should be not toolip
cy.get('[data-id=tooltip]').should('not.be.visible')

// select a day using part of the attribute "data-tip"
// full attribute: data-tip="2019-12-29 has count: 4"
cy.get('[data-tip^="2019-12-29"]').click()
cy.get('[data-id=tooltip]')
})

// stable but random sequence from
// http://indiegamr.com/generate-repeatable-random-numbers-in-js/
let seed = 6
function seededRandom(max, min) {
max = max || 1
min = min || 0

seed = (seed * 9301 + 49297) % 233280
const rnd = seed / 233280

return min + rnd * (max - min)
}

it('deterministic data', () => {
// let's use heatmap with the data we control
const startDate = new Date(2019, 10, 1) // year, month, day
const endDate = new Date(2020, 3, 1)

const values = Cypress._.range(1, 30).map(days => {
return {
date: new Date(2020, 0, days),
count: Math.floor(seededRandom() * 4),
}
})

const classForValue = value => {
if (!value || !value.count) {
return 'color-empty'
}

return `color-github-${value.count}`
}

mount(
<>
<h1>Stable random sequence</h1>
<CalendarHeatmap
startDate={startDate}
endDate={endDate}
values={values}
showWeekdayLabels={true}
classForValue={classForValue}
/>
</>,
)

// now we can do visual diffing
cy.get('.react-calendar-heatmap').happoScreenshot({
component: 'CalendarHeatmap',
})
})
})
59 changes: 59 additions & 0 deletions examples/visual-testing-with-happo/src/Calendar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// This example follows https://codesandbox.io/s/73mk9wlyx
import React from 'react'
import CalendarHeatmap from 'react-calendar-heatmap'
import ReactTooltip from 'react-tooltip'

import 'react-calendar-heatmap/dist/styles.css'
import './styles.css'

const today = new Date()

export default function Calendar() {
const randomValues = getRange(200).map(index => {
return {
date: shiftDate(today, -index),
count: getRandomInt(1, 4),
}
})
return (
<div>
<h1>react-calendar-heatmap demos</h1>
<p>Random values with onClick and react-tooltip</p>
<CalendarHeatmap
startDate={shiftDate(today, -150)}
endDate={today}
values={randomValues}
classForValue={value => {
if (!value) {
return 'color-empty'
}
return `color-github-${value.count}`
}}
tooltipDataAttrs={value => {
return {
'data-tip': `${value.date.toISOString().slice(0, 10)} has count: ${
value.count
}`,
}
}}
showWeekdayLabels={true}
onClick={value => alert(`Clicked on value with count: ${value.count}`)}
/>
<ReactTooltip />
</div>
)
}

function shiftDate(date, numDays) {
const newDate = new Date(date)
newDate.setDate(newDate.getDate() + numDays)
return newDate
}

function getRange(count) {
return Array.from({ length: count }, (_, i) => i)
}

function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
3 changes: 3 additions & 0 deletions examples/visual-testing-with-happo/src/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* {
font-family: sans-serif;
}
1 change: 1 addition & 0 deletions examples/visual-testing-with-percy/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package-lock=false
File renamed without changes.
File renamed without changes.
File renamed without changes.
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)
})
})
File renamed without changes
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit c068ae6

Please sign in to comment.