Giter Site home page Giter Site logo

Comments (13)

redrockzee avatar redrockzee commented on May 12, 2024 5

Use this package:
https://github.com/jeeyah/jestscreenshot

from jest-puppeteer.

mejackreed avatar mejackreed commented on May 12, 2024 4

I like the idea of the automation behind this, and +1 to uploading to S3 for a CI debug. But as a user of jest-puppeteer, it would feel a bit of a reach to me to have this on by default and not configurable. I agree this would be a great feature to have but I could see an issue where for someone breaking a build, many unexpected images are now created which could slow down the testing process. I love the idea of this 👏 @melissachang !

So +1 to opt-in and the ability to have it configurable.

from jest-puppeteer.

callumlocke avatar callumlocke commented on May 12, 2024 4

Is anyone else working on this? If not I might try and get something working...

from jest-puppeteer.

amid2887 avatar amid2887 commented on May 12, 2024 3

This is a very desirable feature. As far as I understand, this should be done with the help of a jasmine reporter. But the version of jasmine that is used only works with synchronous calls. And this creates some problems.
At the moment, the best I've been able to do for myself is to redefine the "it" calls. This method has some disadvantages, but it may be useful to someone.

// package.json
{
  // jest section
  "preset": "jest-puppeteer",
  "setupTestFrameworkScriptFile": "./jest-setup.js"
}
// jest-setup.js
const fs = require('fs');
const jestPreset = require('jest-puppeteer/jest-preset');
const expectPuppeteer = require(jestPreset.setupTestFrameworkScriptFile);

const { browser } = global;

const env = jasmine.getEnv();
// create a reference to original "it" method
const { it: originalIt } = env;

// replace jasmine "it" method with the new one which returns original
env.it = (name, fn, ...args) => {
  const newFn = async (...fnArgs) => {
    try {
      return await fn(...fnArgs);
    } catch (e) {
      // get the filename where the error occurred
      // PS this is a weak place and it does not work for 100% - for some errors can be "null"
      let message = e.stack;
      message = message.match(new RegExp(`${__dirname}(.*)`));
      if (message && message[1]) {
        message = message[1]
          .replace(/^.*[\\/]/, '')
          .replace(/:.+$/, '');
      }

      // run through opened pages also take a screenshot and save source code of the page to the "./artifacts" folder
      const pages = await browser.pages();
      for (let page of pages) {
        const title = await page.title();
        // filter "about:blank" pages and pages without the title attribute
        if (title) {
          const fileName = `${message}__${name}__${title}`.replace(/\s+/g, '_');
          const path = `${__dirname}/artifacts/${fileName}.png`;
          await page.screenshot({ path });
          const content = await page.content();
          await fs.writeFile(`${__dirname}/artifacts/${fileName}.html`, content);
        }
      }
      throw e;
    }
  }
  return originalIt(name, newFn, ...args);
}

module.exports = expectPuppeteer;

from jest-puppeteer.

wangtao0101 avatar wangtao0101 commented on May 12, 2024 1

use this setupTestFrameworkScriptFile in jest config

setupTestFrameworkScriptFile: './hack-expect.js',
// hack-expect.js
const expectPuppeteer = require('expect-puppeteer');
const getPuppeteerType = require('expect-puppeteer/lib/utils').getPuppeteerType;

const puppeteerMatchers = {
  'toClick': 0,
  'toDisplayDialog': 0,
  'toFill': 0,
  'toFillForm': 0,
  'toMatch': 0,
  'toMatchElement': 0,
  'toSelect': 0,
  'toUploadFile': 0,
  'not': {
    'toMatch': 0,
    'toMatchElement': 0,
  },
}

function createMatcher(actual, matcher) {
  return async (...args) => {
    try {
      return await matcher(...args);
    } catch (error) {
      await actual.screenshot({ path: './screenshot.png' });
      throw error;
    }
  }
}

if (typeof global.expect !== 'undefined') {
  const originalExpect = global.expect
  global.expect = (actual, ...args) => {
    const matchers = originalExpect(actual, ...args);

    const type = getPuppeteerType(actual);
    if (type == null) {
      return matchers;
    }
    Object.keys(puppeteerMatchers).forEach(key => {
      if (key === 'not') return;
      if (matchers[key]) {
        matchers[key] = createMatcher(actual, matchers[key])
      }
    })

    Object.keys(puppeteerMatchers.not).forEach(key => {
      if (matchers.not[key]) {
        matchers.not[key] = createMatcher(actual, matchers.not[key])
      }
    })
    return matchers;
  }
  Object.keys(originalExpect).forEach(prop => {
    global.expect[prop] = originalExpect[prop];
  })
}

from jest-puppeteer.

gregberge avatar gregberge commented on May 12, 2024

Good idea!

from jest-puppeteer.

melissachang avatar melissachang commented on May 12, 2024

Thanks. My recommendations:

  • Take advantage of the fact that this repo is relatively new, and don't make an option for this. Just always do this by default.
  • When someone requests an option, you can add an option. But it should be on by default, because I think it would be useful most of the time.

from jest-puppeteer.

yanivefraim avatar yanivefraim commented on May 12, 2024

@neoziro @melissachang - I played with this on one of our projects (created a reporter which take screenshots for failing tests). It is not 100% ready but I would be happy to help here.

One nice feature: upload those screenshots (s3?) so we can see those on CI as well.

WDYT?

from jest-puppeteer.

melissachang avatar melissachang commented on May 12, 2024

Good point, default off is probably safest. CI integration would be awesome.

from jest-puppeteer.

gregberge avatar gregberge commented on May 12, 2024

@callumlocke you are welcome 😀

from jest-puppeteer.

wangtao0101 avatar wangtao0101 commented on May 12, 2024

@amid2887 if you want to getFilename and testName, the right way is:

const getState = require('expect/build/jest_matchers_object').getState;
console.log(getState());

And await browser.pages() may return unexpected page because of concurrency.

from jest-puppeteer.

amid2887 avatar amid2887 commented on May 12, 2024

@wangtao0101 thanks for the advice - it works more stable than previous one =)
I forgot to mention that I use jest --runInBand mode because I have to login in tests with different user types and tests can have a few opened window at the same time.
But yeah, this part should be done in another way...
Does anyone have any suggestions?

from jest-puppeteer.

gregberge avatar gregberge commented on May 12, 2024

Follow up in #131

from jest-puppeteer.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.