From 242a6a6e7331ee68736c428e2b2a7460e89141bb Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Fri, 16 Jun 2017 14:33:34 -0700 Subject: [PATCH] Introduce screenshot tests This patch introduces a goldentest.js. The tests inside the file should rely on "golden" results rather then asserts. For now, goldentest.js allows only image expectations. If the actual result doesn't match the expected result, the two files are created under `test/output` folder: - The '-actual.png' contains the actual test result - The '-diff.png' contains the diff between images --- .gitignore | 1 + package.json | 10 +- test/assets/grid.html | 44 +++++++++ test/golden/screenshot-clip-rect.png | Bin 0 -> 2861 bytes test/golden/screenshot-sanity.png | Bin 0 -> 48624 bytes test/goldentest.js | 136 +++++++++++++++++++++++++++ 6 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 test/assets/grid.html create mode 100644 test/golden/screenshot-clip-rect.png create mode 100644 test/golden/screenshot-sanity.png create mode 100644 test/goldentest.js diff --git a/.gitignore b/.gitignore index 8b2754cd9d4..2c7c3259832 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /node_modules/ +/test/output /.local-chromium/ /.dev_profile* .DS_Store diff --git a/package.json b/package.json index d2416bdad87..a61af08bf07 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,9 @@ "main": "index.js", "scripts": { "test-puppeteer": "jasmine test/test.js", + "test-golden": "jasmine test/goldentest.js", "test-phantom": "python third_party/phantomjs/test/run-tests.py", - "test": "npm run test-puppeteer && npm run test-phantom", + "test": "npm run test-puppeteer && npm run test-golden && npm run test-phantom", "install": "node install.js" }, "author": "The Chromium Authors", @@ -22,9 +23,10 @@ "chromium_revision": "478524" }, "devDependencies": { - "ncp": "^2.0.0", - "minimist": "^1.2.0", "deasync": "^0.1.9", - "jasmine": "^2.6.0" + "jasmine": "^2.6.0", + "minimist": "^1.2.0", + "ncp": "^2.0.0", + "pixelmatch": "^4.0.2" } } diff --git a/test/assets/grid.html b/test/assets/grid.html new file mode 100644 index 00000000000..e35d349b562 --- /dev/null +++ b/test/assets/grid.html @@ -0,0 +1,44 @@ + + + diff --git a/test/golden/screenshot-clip-rect.png b/test/golden/screenshot-clip-rect.png new file mode 100644 index 0000000000000000000000000000000000000000..f541bce8e00581215d8a6b0c6dc6e0e7751f1531 GIT binary patch literal 2861 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 Hh9CYP&3}^{ literal 0 HcmV?d00001 diff --git a/test/goldentest.js b/test/goldentest.js new file mode 100644 index 00000000000..34f65c760b5 --- /dev/null +++ b/test/goldentest.js @@ -0,0 +1,136 @@ +/** + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var fs = require('fs'); +var path = require('path'); +var rm = require('rimraf').sync; +var Browser = require('../lib/Browser'); +var StaticServer = require('./StaticServer'); +var PNG = require('pngjs').PNG; +var pixelmatch = require('pixelmatch'); + +var PORT = 8907; +var STATIC_PREFIX = 'http://localhost:' + PORT; +var GOLDEN_DIR = path.join(__dirname, 'golden'); +var OUTPUT_DIR = path.join(__dirname, 'output'); + +describe('GoldenTests', function() { + var browser; + var staticServer; + var page; + + beforeAll(function() { + browser = new Browser(); + staticServer = new StaticServer(path.join(__dirname, 'assets'), PORT); + if (fs.existsSync(OUTPUT_DIR)) + rm(OUTPUT_DIR); + }); + + afterAll(function() { + browser.close(); + staticServer.stop(); + }); + + beforeEach(SX(async function() { + page = await browser.newPage(); + })); + + afterEach(function() { + page.close(); + }); + + imageTest('screenshot-sanity.png', async function() { + await page.setViewportSize({width: 500, height: 500}); + await page.navigate(STATIC_PREFIX + '/grid.html'); + return page.screenshot('png'); + }); + + imageTest('screenshot-clip-rect.png', async function() { + await page.setViewportSize({width: 500, height: 500}); + await page.navigate(STATIC_PREFIX + '/grid.html'); + return page.screenshot('png', { + x: 50, + y: 100, + width: 150, + height: 100 + }); + }); +}); + +/** + * @param {string} fileName + * @param {function():!Promise} runner + */ +function imageTest(fileName, runner) { + var expectedPath = path.join(GOLDEN_DIR, fileName); + var actualPath = path.join(OUTPUT_DIR, fileName); + var expected = null; + if (fs.existsSync(expectedPath)) { + var buffer = fs.readFileSync(expectedPath); + expected = PNG.sync.read(buffer); + } + it(fileName, SX(async function() { + var imageBuffer = await runner(); + if (!imageBuffer || !(imageBuffer instanceof Buffer)) { + fail(fileName + ' test did not return Buffer with image.'); + return; + } + var actual = PNG.sync.read(imageBuffer); + if (!expected) { + ensureOutputDir(); + fs.writeFileSync(addSuffix(actualPath, '-actual'), imageBuffer); + fail(fileName + ' is missing in golden results.'); + return; + } + if (expected.width !== actual.width || expected.height !== actual.height) { + ensureOutputDir(); + fs.writeFileSync(addSuffix(actualPath, '-actual'), imageBuffer); + fail(`Sizes differ: expected image ${expected.width}px X ${expected.height}px, but got ${actual.width}px X ${actual.height}px`); + return; + } + var diff = new PNG({width: expected.width, height: expected.height}); + var count = pixelmatch(expected.data, actual.data, diff.data, expected.width, expected.height, {threshold: 0.1}); + if (count > 0) { + ensureOutputDir(); + fs.writeFileSync(addSuffix(actualPath, '-actual'), imageBuffer); + fs.writeFileSync(addSuffix(actualPath, '-diff'), PNG.sync.write(diff)); + fail(fileName + ' mismatch!'); + } + })); +} + +function ensureOutputDir() { + if (!fs.existsSync(OUTPUT_DIR)) + fs.mkdirSync(OUTPUT_DIR); +} + +/** + * @param {string} filePath + * @param {string} suffix + * @return {string} + */ +function addSuffix(filePath, suffix) { + var dirname = path.dirname(filePath); + var ext = path.extname(filePath); + var name = path.basename(filePath, ext); + return path.join(dirname, name + suffix + ext); +} + +// Since Jasmine doesn't like async functions, they should be wrapped +// in a SX function. +function SX(fun) { + return done => Promise.resolve(fun()).then(done).catch(done.fail); +}