API.md

March 5, 2019 ยท View on GitHub

Differencify specific methods

MethodArgumentsdescription
launchBrowser/launchObject puppeteer.launch optionsLaunches a browser instance
connectBrowser/connectObject puppeteer.connect optionsAttaches to an existing browser instance
initTestOptionsConfigure and prepare differencify to operate based on TestOptions
cleanupno argumentCloses browser instance if it is not closed already

Additional methods on top of Puppeteer's Page class

MethodArgumentsdescription
toMatchSnapshotimage or
image, callback or
callback
Pass an image object to compare it to the snapshot. Optionally, pass a callback to receive details from the comparison. Alternatively, just pass a callback to receive details of the snapshot currently in the chain.
resultObjectA function that returns response object of previous step when on chained mode
launchObject puppeteer.launch optionslaunches new browser and returns browser object
connectObject puppeteer.connect optionsAttaches to an existing browser instance and returns browser object
freezeImagestringSelector name of a <img> tag containing animated image to be freezed before taking screenshot
mockRequestsObjectRuns chrome headless browser in isolation using Mockeer

Puppeteer methods

Differencify matches Puppeteer's API completely. Here are some examples of how to use it.

Simple

(async () => {
  await differencify.launchBrowser();
  await differencify
    .init()
    .newPage()
    .setViewport({ width: 1600, height: 1200 })
    .goto('https://github.com/NimaSoroush/differencify')
    .waitFor(1000)
    .screenshot()
    .toMatchSnapshot()
    .result((result) => {
      console.log(result) // True or False
    })
    .close()
    .end();
  await differencify.cleanup();
})();

In this example, differencify will launch a browser instance and continues on others steps

Simple unchained

(async () => {
  await differencify.launchBrowser();
  const target = differencify.init({ testName: 'Differencify simple unchained', chain: false });
  const page = await target.newPage();
  await page.goto('https://github.com/NimaSoroush/differencify');
  await page.setViewport({ width: 1600, height: 1200 });
  await page.waitFor(1000);
  const image = await page.screenshot();
  const result = await target.toMatchSnapshot(image);
  await page.close();
  console.log(result) // True or False
  await differencify.cleanup();
})();

In this example, differencify will launch a browser instance and unchain steps. differencify.init().newPage() will return a puppeteer page instance which with all supported methods on that page

Launch new browser per test

(async () => {
  await differencify
    .init()
    .launch()
    .newPage()
    .setViewport({ width: 1600, height: 1200 })
    .goto('https://github.com/NimaSoroush/differencify')
    .waitFor(1000)
    .screenshot()
    .toMatchSnapshot()
    .result((result) => {
      console.log(result) // True or False
    })
    .close()
    .end();
})();

In this example, differencify will launch a browser instance and continues on others steps and on close() it will close both page and browser

Launch new browser per test when unchained

(async () => {
  const target = differencify.init({ testName: 'Differencify simple unchained', chain: false });
  await target.launch();
  const page = await target.newPage();
  await page.goto('https://github.com/NimaSoroush/differencify');
  await page.setViewport({ width: 1600, height: 1200 });
  await page.waitFor(1000);
  const image = await page.screenshot();
  const result = await target.toMatchSnapshot(image);
  await page.close();
  await target.close();
  console.log(result) // True or False
})();

In this example, differencify will launch a browser instance and unchain steps. differencify.init().newPage() will return a puppeteer page instance which with all supported methods on that page

Share browser

(async () => {
  await differencify.launchBrowser();
  await differencify
    .init({ testName: 'test1' })
    .newPage()
    .setViewport({ width: 1600, height: 1200 })
    .goto('https://github.com/NimaSoroush/differencify')
    .wait(3000)
    .screenshot()
    .toMatchSnapshot()
    .result((result) => {
      console.log(result) // True or False
    })
    .close()
    .end();

  await differencify
    .init({ testName: 'test2' })
    .newPage()
    .setViewport({ width: 1600, height: 1200 })
    .goto('https://github.com/NimaSoroush/differencify')
    .wait(3000)
    .screenshot()
    .toMatchSnapshot()
    .result((result) => {
      console.log(result) // True or False
    })
    .close()
    .end();

  await differencify.cleanup();
})();

In this example, differencify will launch a browser instance and share same browser instance with all following tests and on cleanup() it will close the browser

Using result function

(async () => {
  await differencify
    .init()
    .newPage()
    .setViewport({ width: 1600, height: 1200 })
    .goto('https://github.com/NimaSoroush/differencify')
    .title()
    .result((title) => {
      console.log(title)
    })
    .screenshot()
    .toMatchSnapshot()
    .result((result) => {
      console.log(result) // True or False
    })
    .close()
    .end();
})();

In this example, after calling result function it will return the previous step result as an object.

Detailed Result Information

For programmatic use cases where more information is required than simply whether or not a test passed, a callback function may be passed to toMatchSnapshot which will be invoked after the test and passed additional details.

(async () => {
  await differencify
    .init()
    .newPage()
    .setViewport({ width: 1600, height: 1200 })
    .goto('https://github.com/NimaSoroush/differencify')
    .screenshot()
    .toMatchSnapshot((resultDetail) => {
     console.log(resultDetail);
     /*
     Example output:
      {
        testConfig: {
          chain: false,
          testNameProvided: true,
          testName: 'TestName',
          'testId': 2,
          'isUpdate': false,
          'isJest': false,
          'newWindow': true
        },
        testResult: {
          diffPath: '/parent/__image_snapshots__/__differencified_output__/test.differencified.png',
          matched: false,
          diffPercent: 0.02,
          distance: 0,
          snapshotPath: '/parent/__image_snapshots__/test.snap.png',
        }
      }
    */
    })
    .close()
    .end();
})();

Similarly, the callback may be passed as a second argument when unchained:

(async () => {
  const target = differencify.init({ chain: false });
  await target.launch();
  const page = await target.newPage();
  await page.goto('https://github.com/NimaSoroush/differencify');
  await page.setViewport({ width: 1600, height: 1200 });
  await page.waitFor(1000);
  const image = await page.screenshot();
  await target.toMatchSnapshot(image, (resultDetail) => {
   console.log(resultDetail);
   /*
   Example output:
    {
      testConfig: {
        chain: false,
        testNameProvided: true,
        testName: 'TestName',
        'testId': 2,
        'isUpdate': false,
        'isJest': false,
        'newWindow': true
      },
      testResult: {
        diffPath: '/parent/__image_snapshots__/__differencified_output__/test.differencified.png',
        matched: false,
        diffPercent: 0.02,
        distance: 0,
        snapshotPath: '/parent/__image_snapshots__/test.snap.png',
      }
    }
  */
  });
  await page.close();
  await target.close();
})();

Context switching when chained

(async () => {
  await differencify
    .init()
    .newPage()
    .tracing
      .start({ path: 'trace.json' })
    .page
      .setViewport({ width: 1600, height: 1200 })
      .goto('https://nimasoroush.github.io/differencify/')
      .waitFor(1000)
    .keyboard
      .press('Space')
    .tracing
      .stop()
    .page
      .screenshot()
      .toMatchSnapshot()
      .result((result) => {
        console.log(result) // True or False
      })
      .close()
      .end();
})();

In this example, differencify will launch a browser instance and opens a new tab and starts tracing, goto url, mouse click, stop tracing and finally closes the tab. All steps are running on page context unless you switch to one of the following context:

  'page',
  'keyboard',
  'mouse',
  'touchscreen',
  'tracing',

If you do so, you need to come back to page context by calling it.

Calling Puppeteer's specific functions when chained

(async () => {
  await differencify
    .init()
    .newPage()
    .setViewport({ width: 1600, height: 1200 })
    .goto('https://nimasoroush.github.io/differencify/')
    .on('console', msg => {
      for (let i = 0; i < msg.args.length; ++i) {
        console.log(`${i}: ${msg.args[i]}`); // JSHandle:hello
      }
    });
    .evaluate(() => console.log('hello', 5, { foo: 'bar' }))
    .screenshot()
    .toMatchSnapshot()
    .result((result) => {
      console.log(result) // True or False
    })
    .close()
    .end();
})();

In this example, differencify will call on() method of Puppeteer asynchronously. same logic should apply for other specific methods of Puppeteer like:

on('dialog', async dialog => { console.log(dialog.message()) };
evaluate(() => console.log('hello', 5, {foo: 'bar'}));
$$eval('div', divs => divs.length);
evaluateHandle(() => document.body);
...

Another example


(async () => {
  await differencify
    .init()
    .newPage()
    .setViewport({ width: 1600, height: 1200 })
    .goto('https://nimasoroush.github.io/differencify/')
    .on('dialog', async (dialog) => {
      console.log(dialog.message()); // 1
      await dialog.dismiss();
    })
    .evaluate(() => alert('1'))
    .screenshot()
    .toMatchSnapshot()
    .result((result) => {
      console.log(result) // True or False
    })
    .close()
    .end();
})();

Continue on chained object

(async () => {
  await differencify
    .init()
    .newPage()
    .goto('https://github.com/NimaSoroush/differencify')
    .mainFrame()
      .then
      .url()
      .result((url) => {
        console.log(url); // https://github.com/NimaSoroush/differencify
      })
    .screenshot()
    .toMatchSnapshot()
    .result((result) => {
      console.log(result); // True or False
    })
    .close()
    .end();
})();

In this example, differencify will get the mainFrame of page and continues by then to get childFrame of that frame and finally prints the url of the childFrame.

Multiple toMatchSnapshot on chained object

(async () => {
  await differencify
    .init()
    .newPage()
    .goto('https://nimasoroush.github.io/differencify/')
    .screenshot()
    .toMatchSnapshot()
    .result((result) => {
      console.log(result); // True or False
    })
    .goto('https://nimasoroush.github.io/differencify/')
    .screenshot()
    .toMatchSnapshot()
    .result((result) => {
      console.log(result); // True or False
    })
    .close()
    .end();
})();

In this example, differencify will got to different pages and compare screenshots with reference screenshots.

Multiple toMatchSnapshot when unchained

(async () => {
  const target = differencify.init({ chain: false });
  const page = await target.newPage();
  await page.goto('https://nimasoroush.github.io/differencify/');
  await page.setViewport({ width: 1600, height: 1200 });
  await page.waitFor(1000);
  const image = await page.screenshot();
  const result = await target.toMatchSnapshot(image);
  await page.goto('https://github.com/NimaSoroush/differencify#about');
  await page.setViewport({ width: 1600, height: 1200 });
  await page.waitFor(1000);
  const image2 = await page.screenshot();
  const result2 = await target.toMatchSnapshot(image2);
  await page.close();
  console.log(result); // True or False
  console.log(result2); // True or False
})();

In this example, differencify will got to different pages and compare screenshots with reference screenshots.

Custom test path

(async () => {
  const differencify = new Differencify({ imageSnapshotPath: './custom_test_path' });
  const target = differencify.init({ chain: false });
  await target.launch();
  const page = await target.newPage();
  await page.setViewport({ width: 1600, height: 1200 });
  await page.goto('http://example.com/');
  await page.waitFor(1000);
  const image = await page.screenshot();
  const result = await target.toMatchSnapshot(image);
  await page.close();
  console.log(result); // True or False
  console.log(result2); // True or False
})();

In this example, you can specify the custom path for storing images.

Freezing an image

(async () => {
  await differencify
    .init()
    .newPage()
    .setViewport({ width: 1600, height: 1200 })
    .goto('https://i.giphy.com/media/xTiTnoUnHxVaaVNWhO/giphy.webp')
    .waitFor('body > img')
    .freezeImage('body > img')
    .screenshot()
    .toMatchSnapshot()
    .close()
    .end();
})();

In this example, you can freeze an image by specifying the selector path.

Page interactions

(async () => {
  await differencify
    .init()
    .newPage()
    .goto('https://nimasoroush.github.io/differencify/')
    .waitFor(2000)
    .click('[id=js-repo-pjax-container] div nav a')
    .waitFor(2000)
    .url()
    .result((url) => {
      expect(url).toContain('pulls');
    })
    .screenshot()
    .toMatchSnapshot()
    .close()
    .end();
})();

In this example an element is clicked on that performs navigation, and the url checked to see it has been successful.