Skip to content

Commit

Permalink
feat: add first test case
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike Loydd committed Jun 29, 2023
1 parent c40c079 commit 3e824b5
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ node_modules/
.idea
pixelpact/coverage
.direnv/

example/playwright-report
example/test-results
example/pixelpact/*_diff.png
example/pixelpact/*_actual.png
91 changes: 91 additions & 0 deletions example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
"format": "npx prettier --write ."
},
"devDependencies": {
"@playwright/test": "^1.35.1",
"pino-pretty": "^10.0.0",
"prettier": "2.8.8"
},
"dependencies": {
"@pixelpact-hook/playwright-js": "file:../pixelpact-hooks/playwright-js",
"tar": "^6.1.14"
}
}
5 changes: 5 additions & 0 deletions example/pixelpact.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"serverUrl": "http://0.0.0.0:8888",
"folderPath": "./pixelpact/",
"mode": "verify"
}
Binary file added example/pixelpact/ErgonWebsite_expected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 64 additions & 0 deletions example/playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { devices } from "@playwright/test";

/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// require('dotenv').config();

/**
* See https://playwright.dev/docs/test-configuration.
*/
const config = {
testDir: "./tests",
/* Maximum time one test can run for. */
timeout: 30 * 1000,
expect: {
/**
* Maximum time expect() should wait for the condition to be met.
* For example in `await expect(locator).toHaveText();`
*/
timeout: 5000,
},
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
actionTimeout: 0,
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://localhost:3000',

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},

/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: {
...devices["Desktop Chrome"],
},
},
],

/* Folder for test artifacts such as screenshots, videos, traces, etc. */
// outputDir: 'test-results/',

/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// port: 3000,
// },
};

export default config;
20 changes: 20 additions & 0 deletions example/tests/example.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { test } from "@playwright/test";
import { toMatchVisually } from "@pixelpact-hook/playwright-js";

test.use({
viewport: { width: 1920, height: 1024 },
locale: "de-CH",
video: "on",
trace: "on",
reporter: "html",
});

import fs from "fs/promises";

test("test login page", async ({ page, browser }, testInfo) => {
await page.goto("https://www.ergon.ch/de/themen", {
waitUntil: "networkidle",
});

await toMatchVisually(page, testInfo, "ErgonWebsite");
});
67 changes: 56 additions & 11 deletions pixelpact-hooks/playwright-js/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { readFileSync, existsSync } from "fs";
import { readFileSync, existsSync, mkdirSync } from "fs";
import fs from "fs/promises";
import { dirname, resolve } from "path";

const appDir = process.env.PWD;
const data = readFileSync(`${appDir}/pixelpact.config.json`, {
encoding: "utf8",
flag: "r",
});
const data = JSON.parse(
readFileSync(`${appDir}/pixelpact.config.json`, {
encoding: "utf8",
flag: "r",
})
);

const mimeType = "image/png";
const fallbackFolderPath = `${appDir}/pixelpact/`;
Expand All @@ -19,29 +22,67 @@ export async function toMatchVisually(page, testInfo, fileNamePrefix) {
}

const session = await page.context().newCDPSession(page);
const mhtml = await session.send("Page.captureSnapshot", { format: "mhtml" });
const mhtml = (
await session.send("Page.captureSnapshot", { format: "mhtml" })
).data;

if (data.mode === "record") {
const referenceFileName = composeFileName(fileNamePrefix, "expected");
const referenceFilePath = folderPath + referenceFileName;
const referenceImage = await render(mhtml, page);
await fs.writeFile(referenceFilePath, referenceImage);
} else if (data.mode === "verify") {
await toExpect(page, testInfo, fileNamePrefix, mhtml);
} else {
throw Error("Unknown Mode!");
}
}

async function render(actualHtml, page) {
const serverUrl = data.serverUrl;

const body = {
actualHtml,
viewport: page.viewportSize(),
};

const response = await fetch(`${serverUrl}/render`, {
method: "post",
body: JSON.stringify(body),
headers: { "Content-Type": "application/json" },
});

const result = await response.json();
return Buffer.from(result.actual, "base64");
}

async function toExpect(page, testInfo, fileNamePrefix, mhtml) {
const serverUrl = data.serverUrl;
const folderPath = getFolderPath();

const referenceFileName = composeFileName(fileNamePrefix, "expected");
const referenceFilePath = folderPath + referenceFileName;
const referenceImage = await fs.readFile(referenceFilePath);
const body = {
actualHtml: mhtml,
expected: referenceImage.toString("base64"),
viewport: { width: 1920, height: 1024 },
context: context.toString("base64"),
viewport: page.viewportSize(),
};

const response = await fetch(serverUrl, {
const response = await fetch(serverUrl + "/check", {
method: "post",
body: JSON.stringify(body),
headers: { "Content-Type": "application/json" },
});
const result = await response.json();

const expectedFileName = composeFileName(fileNamePrefix, "expected");
const expectedFilePath = folderPath + actualFileName;
const expectedFilePath = folderPath + expectedFileName;
await fs.writeFile(expectedFilePath, Buffer.from(result.expected, "base64"));
testInfo.attachments.push({
name: expectedFileName,
contentType: mimeType,
path: expectedFileName,
path: expectedFilePath,
});

const actualFileName = composeFileName(fileNamePrefix, "actual");
Expand All @@ -61,6 +102,10 @@ export async function toMatchVisually(page, testInfo, fileNamePrefix) {
contentType: mimeType,
path: diffFilePath,
});

if (result.numDiffPixels !== 0) {
throw Error("Missmatch!");
}
}

function getFolderPath() {
Expand Down

0 comments on commit 3e824b5

Please sign in to comment.