garris / BackstopJS

Catch CSS curve balls.
http://backstopjs.org
MIT License
6.74k stars 602 forks source link

Will backstop JS work with Cypress tests? #1134

Open mudra-octopus opened 4 years ago

mudra-octopus commented 4 years ago

Hi Following up on https://github.com/garris/BackstopJS/issues/622#issuecomment-353752942 Is there any change to this situation? I would like to know if I can use Backstop JS with cypress tests.

garris commented 4 years ago

I don't know of any integrations with cypress -- I would ask on their issues page to see if someone has done it.

FWIW: Backstop was recently integrated into Ember -- there is a plugin for that here... https://github.com/garris/ember-backstop. It would be fairly straight-forward to implement a similar plugin for Cypress. I think cypress is cool and would happily provide some support for anyone who wanted to take this on.

jscontreras commented 4 years ago

Here is how I solved it BackstopJS can be executed as a function so you can create a task.

Testing Patternlab using BackstopJS and Cypress

In plugins/index.js

const backstop = require('backstopjs');
// Place your initial backstop js config as a fixture
const config = require('../fixtures/backstop-base.json')

/**
 * Run BackstopJS as code 
 * Scenarios and Report folder name can be set via params
*/
function backstopExec(payload = {scenarios: [], folder:'default'}, refreshReferences = true) {
  return new Promise((resolve) => {
    const configuration = config
    config.scenarios = payload.scenarios
    config.paths.html_report = `cypress/reports/backstop/${payload.folder}/html_report`
    config.paths.ci_report = `cypress/reports/backstop/${payload.folder}/ci_report`

    if (refreshReferences) {
      backstop('reference', { config: configuration }).then(() => {
        resolve(null)
      }).catch(() => {
        resolve(null)
      })
    } else {
      backstop('test', { config: configuration }).then(() => {
        resolve(null)
      }).catch(() => {
        resolve(null)
      })
    }

  })
}

/**
 * @type {Cypress.PluginConfig}
 */
module.exports = (on, config) => {
  backstop('init')
   on('task', {
    log(message) {
      console.log(message)
      return null
    },
    backstopRefreshReferences(customConfig) {
      return backstopExec(customConfig)
    },
    backstopTest(customConfig) {
      return backstopExec(customConfig, false)
    }
  })
};

The configuration file that I'm importing, looks like this. cypress/fixtures/backstop-base.json

{
  "id": "schroff_homepage",
  "viewports": [
    {
      "label": "phone",
      "width": 375,
      "height": 812
    },
    {
      "label": "desktop",
      "width": 1200,
      "height": 800
    }
  ],
  "onBeforeScript": "puppet/onBefore.js",
  "onReadyScript": "puppet/onReady.js",
  "scenarios": [],
  "paths": {
    "bitmaps_reference": "cypress/reports/backstop_data/bitmaps_reference",
    "bitmaps_test": "cypress/reports/backstop_data/bitmaps_test",
    "engine_scripts": "cypress/reports/backstop_data/engine_scripts",
    "html_report": "cypress/reports/backstop/html_report",
    "ci_report": "cypress/reports/backstop/ci_report"
  },
  "report": ["browser"],
  "engine": "puppeteer",
  "engineOptions": {
    "args": ["--no-sandbox"]
  },
  "asyncCaptureLimit": 5,
  "asyncCompareLimit": 50,
  "debug": false,
  "debugWindow": false
}

Once you register the task you can use them within your tests. ( I use mochawesome to add links to the generated reports) if you run the task using cypress open then the reports are open automatically.

// Im getting my url from env
const baseUrl = Cypress.env('baseUrl')
// reset baseUrl by combining the two
Cypress.config("baseUrl", baseUrl)

// Reference URL for doing the compare
const refUrl = Cypress.env('refUrl') || false

let pages = [
  { label: 'base', url: `${baseUrl}/patterns/00-base/index.html`, hideSelectors },
  { label: 'atoms', url: `${baseUrl}/patterns/01-atoms/index.html`, hideSelectors },
  { label: 'patterns', url: `${baseUrl}/patterns/02-molecules/index.html`, hideSelectors },
  { label: 'organisms', url: `${baseUrl}/patterns/03-organisms/index.html`, hideSelectors },
  { label: 'templates', url: `${baseUrl}/patterns/04-templates/index.html`, hideSelectors },
  { label: 'pages', url: `${baseUrl}/patterns/05-pages/index.html`, hideSelectors },
]

describe('Using backstopjs', () => {
if (refUrl) {
    it('Generate report using Backstop JS', function () {
      // If ref URl is set, then it means we are in the right env for doing both refresh and test calls
      let refScenarios = []
      let testScenarios = []
      pages.forEach((scenario) => {
        const refScenarioUrl = scenario.url.replace(baseUrl, refUrl)
        const refScenario = { ...scenario }
        const testScenario = { ...scenario }
        refScenario.url = refScenarioUrl
        refScenarios.push(refScenario)
        testScenarios.push(testScenario)
      })
      cy.task('backstopRefreshReferences', { scenarios: refScenarios, folder: 'paternlab' }, { timeout: 820000 })
      cy.task('backstopTest', { scenarios: testScenarios, folder: 'patternlab' }, { timeout: 820000 })
      })
    })
  }
})
cgpro commented 1 year ago

@jscontreras how can I "tell" cypress to display a failed test, if the backstop test fails? (aka have differences)

In my case it works, but cypress is showing me "passed", instead of failed if differences in the screenshots are present.