Skip to content

Commit

Permalink
add screenshot for UAR stable and beta (#216)
Browse files Browse the repository at this point in the history
* add test for quiz and result pages

* add test for quiz and result pages

* add test for quiz and result pages

* add POC for analytics test

* update analytics tests and envs

* result envs

* update analytics only on firefox

* add dynamic tests

* add dynamic test for quiz page

* update quiz test

* update test structure

* add test for quiz and result pages

* add POC for analytics test

* update analytics tests and envs

* result envs

* update analytics only on firefox

* add dynamic tests

* add dynamic test for quiz page

* update quiz test

* update test structure

* update uar tests to new format

* update uar tests

* move everything to uar folder

* add dependency for js-yaml

* update test according to latest comments

* update test according to latest comments

* update tests according to the latest comments

* add uar config

* add analytics for uar

* update according to feedbacks

* update tags

* add @cc tag

* update according to feedbacks

* add dynamic tests for uar

* update according to review comments

* fix some typos

* update according to review comments

* merge console log info

* add UI screenshots for UAR

* move view point to test

* update according to feedback

* add analytics test for UAR

* update validation and uar libs

* update libs

* update by feedback

* update some config and tests

* update some config and tests

* update test content path to common path

* update analytics tests

* fix test failures caused by test code

* fix test failures

* fix test failures

* add visual test for CAAS with two pages

* update according to feedbacks

* update report in config file

* add screenshot for milo main live vs uar-integration live

* add timestamp js for time stampe recording

* add screenshot diff for uar stable and beta

* move uar screenshots into visual compare folder

---------

Co-authored-by: xiasun <[email protected]>
Co-authored-by: Aaron Mauchley <[email protected]>
  • Loading branch information
3 people authored Dec 1, 2023
1 parent 1eb7132 commit bbbcec7
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 44 deletions.
14 changes: 14 additions & 0 deletions features/visual-compare/uar/quiz.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
name: 'UAR Visual Comparison',
features: [
{
tcid: '0',
name: '@quiz screenshots',
path: '/drafts/quiz/quiz-2/',
stable: '@milo_live',
beta: '@uar_live',
tags: '@cc @uar-quiz-stable-vs-beta @uar-quiz-static',
data: 'data/uar/quiz/quiz-basic.yml',
},
],
};
6 changes: 6 additions & 0 deletions libs/timestamp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const fs = require('fs');

fs.writeFileSync(
'timestamp.json',
JSON.stringify([(new Date()).toLocaleString()], null, 2),
);
77 changes: 48 additions & 29 deletions libs/webutil.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,33 +155,33 @@ exports.WebUtil = class WebUtil {
* @param {Object} attProps - The attribute properties and expected values to verify.
* @returns {Boolean} - True if all attribute properties match the expected values, false otherwise.
*/
async verifyAttributes_(locator, attProps) {
this.locator = locator;
let result = true;
await Promise.allSettled(
Object.entries(attProps).map(async ([property, expectedValue]) => {
if (property === 'class' && typeof expectedValue === 'string') {
// If the property is 'class' and the expected value is an string,
// split the string value into individual classes
const classes = expectedValue.split(' ');
try {
await expect(await this.locator).toHaveClass(classes.join(' '));
} catch (error) {
console.error('Attribute class not found:', error);
result = false;
}
} else {
try {
await expect(await this.locator).toHaveAttribute(property, expectedValue);
} catch (error) {
console.error(`Attribute ${property} not found:`, error);
result = false;
}
async verifyAttributes_(locator, attProps) {
this.locator = locator;
let result = true;
await Promise.allSettled(
Object.entries(attProps).map(async ([property, expectedValue]) => {
if (property === 'class' && typeof expectedValue === 'string') {
// If the property is 'class' and the expected value is an string,
// split the string value into individual classes
const classes = expectedValue.split(' ');
try {
await expect(await this.locator).toHaveClass(classes.join(' '));
} catch (error) {
console.error('Attribute class not found:', error);
result = false;
}
}),
);
return result;
}
} else {
try {
await expect(await this.locator).toHaveAttribute(property, expectedValue);
} catch (error) {
console.error(`Attribute ${property} not found:`, error);
result = false;
}
}
}),
);
return result;
}

/**
* Slow/fast scroll of entire page JS evaluation method, aides with lazy loaded content.
Expand Down Expand Up @@ -292,16 +292,16 @@ exports.WebUtil = class WebUtil {
await this.page.screenshot({ path: `${folderPath}/${fileName}`, fullPage: true });
}

async takeScreenshotAndCompare(urlA, urlB, folderPath, fileName) {
async takeScreenshotAndCompare(urlA, callbackA, urlB, callbackB, folderPath, fileName) {
console.info(`[Test Page]: ${urlA}`);
await this.page.goto(urlA);
await this.page.waitForTimeout(3000);
await callbackA();
await this.page.screenshot({ path: `${folderPath}/${fileName}-a.png`, fullPage: true });
const baseImage = fs.readFileSync(`${folderPath}/${fileName}-a.png`);

console.info(`[Test Page]: ${urlB}`);
await this.page.goto(urlB);
await this.page.waitForTimeout(3000);
await callbackB();
await this.page.waitForSelector('.feds-footer-privacyLink');
await this.page.screenshot({ path: `${folderPath}/${fileName}-b.png`, fullPage: true });
const currImage = fs.readFileSync(`${folderPath}/${fileName}-b.png`);
Expand All @@ -314,4 +314,23 @@ exports.WebUtil = class WebUtil {
console.info('Differences found');
}
}

static compareScreenshots(stableArray, betaArray, folderPath) {
const comparator = getComparator('image/png');
for (let i = 0; i < stableArray.length; i += 1) {
if (betaArray[i].slice(-10) === stableArray[i].slice(-10)) {
const stableImage = fs.readFileSync(`${folderPath}/${stableArray[i]}`);
const betaImage = fs.readFileSync(`${folderPath}/${betaArray[i]}`);
const diffImage = comparator(stableImage, betaImage);

if (diffImage) {
fs.writeFileSync(`${folderPath}/${stableArray[i]}-diff.png`, diffImage.diff);
console.info('Differences found');
}
} else {
console.info('Screenshots are not matched');
console.info(`${stableArray[i]} vs ${betaArray[i]}`);
}
}
}
};
29 changes: 18 additions & 11 deletions selectors/uar/quiz.page.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default class Quiz {
this.uarResult = page.locator('.quiz-results h1');
this.uarResult2 = page.locator('//div[contains(@data-path,"marquee-product")]//strong | //div[contains(@data-path,"check-bullet")]//h1 | //div[contains(@data-path,"express-product")]//h1');
this.uarResult3 = page.locator('//div[contains(@data-path,"card")]//strong');
this.screenshots = [];
}

/**
Expand Down Expand Up @@ -41,7 +42,7 @@ export default class Quiz {
* @param {string} url
* @param {string} originalAnswer
*/
async clickEachAnswer(url, originalAnswer, keyNumber, isScreenshot = false) {
async clickEachAnswer(url, originalAnswer, keyNumber, version, isScreenshot = false) {
await this.page.goto(url);

const answers = originalAnswer.split('>').map((x) => x.trim());
Expand All @@ -64,13 +65,15 @@ export default class Quiz {

const index = answers.indexOf(answer);
const folderPath = 'screenshots/uar';
const desktopName = `${keyNumber} - new - desktop - ${index} - ${answer.replace('/', '')}.png`;
const tabletName = `${keyNumber} - new - tablet - ${index} - ${answer.replace('/', '')}.png`;
const mobileName = `${keyNumber} - new - mobile - ${index} - ${answer.replace('/', '')}.png`;
const desktopName = `${keyNumber} - ${version} - desktop - ${index} - ${answer.replace('/', '')}.png`;
const tabletName = `${keyNumber} - ${version} - tablet - ${index} - ${answer.replace('/', '')}.png`;
const mobileName = `${keyNumber} - ${version} - mobile - ${index} - ${answer.replace('/', '')}.png`;

await this.webUtil.takeScreenshot(folderPath, desktopName, 1920, 1080);
await this.webUtil.takeScreenshot(folderPath, tabletName, 768, 1024);
await this.webUtil.takeScreenshot(folderPath, mobileName, 375, 812);

this.screenshots.push(desktopName, tabletName, mobileName);
}

// click next button
Expand All @@ -79,13 +82,15 @@ export default class Quiz {
await this.page.waitForTimeout(500);
const index = answers.length - 1;
const folderPath = 'screenshots/uar';
const desktopName = `${keyNumber} - new - desktop - ${index} - ${answer.replace('/', '')}.png`;
const tabletName = `${keyNumber} - new - tablet - ${index} - ${answer.replace('/', '')}.png`;
const mobileName = `${keyNumber} - new - mobile - ${index} - ${answer.replace('/', '')}.png`;
const desktopName = `${keyNumber} - ${version} - desktop - ${index} - ${answer.replace('/', '')}.png`;
const tabletName = `${keyNumber} - ${version} - tablet - ${index} - ${answer.replace('/', '')}.png`;
const mobileName = `${keyNumber} - ${version} - mobile - ${index} - ${answer.replace('/', '')}.png`;

await this.webUtil.takeScreenshot(folderPath, desktopName, 1920, 1080);
await this.webUtil.takeScreenshot(folderPath, tabletName, 768, 1024);
await this.webUtil.takeScreenshot(folderPath, mobileName, 375, 812);

this.screenshots.push(desktopName, tabletName, mobileName);
}
}

Expand All @@ -97,7 +102,7 @@ export default class Quiz {
* Validate products on result page to match with expect products
* @param {string} name
*/
async checkResultPage(name, originalAnswer, keyNumber, isScreenshot = false) {
async checkResultPage(name, originalAnswer, keyNumber, version, isScreenshot = false) {
const newProduct = [];

const actualProduct = await this.uarResult.nth(0);
Expand Down Expand Up @@ -163,13 +168,15 @@ export default class Quiz {
await this.page.waitForTimeout(1000);

const folderPath = 'screenshots/uar';
const desktopName = `${keyNumber} - new - desktop - result.png`;
const tabletName = `${keyNumber} - new - tablet - result.png`;
const mobileName = `${keyNumber} - new - mobile - result.png`;
const desktopName = `${keyNumber} - ${version} - desktop - result.png`;
const tabletName = `${keyNumber} - ${version} - tablet - result.png`;
const mobileName = `${keyNumber} - ${version} - mobile - result.png`;

await this.webUtil.takeScreenshot(folderPath, desktopName, 1920, 1080);
await this.webUtil.takeScreenshot(folderPath, tabletName, 768, 1024);
await this.webUtil.takeScreenshot(folderPath, mobileName, 375, 812);

this.screenshots.push(desktopName, tabletName, mobileName);
}

console.info(`==========new============\n${newProduct.sort().join('')}`);
Expand Down
4 changes: 2 additions & 2 deletions tests/uar/quiz.screenshots.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ test.describe('Quiz flow test suite', () => {
});

await test.step(`New: Select each answer on test page according to ${key}`, async () => {
await quiz.clickEachAnswer(url, key, keyNumber, true);
await quiz.clickEachAnswer(url, key, keyNumber, 'new', true);
});

await test.step('New: Check results on test page', async () => {
newProduct = await quiz.checkResultPage(testdata[key], key, keyNumber, true);
newProduct = await quiz.checkResultPage(testdata[key], key, keyNumber, 'new', true);
});

expect.soft(newProduct).toContain(oldProduct);
Expand Down
4 changes: 2 additions & 2 deletions visual-compare-tests/caas/cards.vc.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ test.describe('Milo Caas block visual comparison test suite', () => {
// eslint-disable-next-line no-restricted-syntax
for (const feature of features) {
// eslint-disable-next-line no-loop-func
test(`${feature.name},${feature.tags}`, async ({ baseURL }) => {
test(`${feature.name},${feature.tags}`, async ({ page, baseURL }) => {
const folderPath = 'screenshots/caas';
// eslint-disable-next-line max-len
await webUtil.takeScreenshotAndCompare(baseURL + feature.stable, baseURL + feature.beta, folderPath, feature.name);
await webUtil.takeScreenshotAndCompare(baseURL + feature.stable, async () => { await page.waitForTimeout(3000); }, baseURL + feature.beta, async () => { await page.waitForTimeout(3000); }, folderPath, feature.name);
});
}
});
66 changes: 66 additions & 0 deletions visual-compare-tests/uar/quiz.vc.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable no-loop-func */
/* eslint-disable no-restricted-syntax */
import { expect, test } from '@playwright/test';
import Quiz from '../../selectors/uar/quiz.page.js';

const { features } = require('../../features/visual-compare/uar/quiz.spec.js');
const { WebUtil } = require('../../libs/webutil.js');
const envs = require('../../envs/envs.js');

test.describe('Quiz flow test suite', () => {
// reset timeout because we use this to run all test data
test.setTimeout(10 * 60 * 1000);
for (const feature of features) {
test(
`${feature.name}, ${feature.tags}`,
async ({ page }) => {
const stablePage = new Quiz(page);
const betaPage = new Quiz(page);
const stableURL = `${envs[feature.stable]}${feature.path}`;
console.info(stableURL);
const betaURL = `${envs[feature.beta]}${feature.path}`;
console.info(betaURL);

// load test data from static files
const testdata = await WebUtil.loadTestData(`${feature.data}`);

let keyNumber = 0;

for (const key of Object.keys(testdata)) {
console.log(key);
let stableProduct = '';
let betaProduct = '';
let stableProductScreenshots = [];
let betaProductScreenshots = [];
keyNumber += 1;
await test.step(`Old: Select each answer on test page according to ${key}`, async () => {
await stablePage.clickEachAnswer(stableURL, key, keyNumber, 'stable', true);
});

await test.step('Old: Check results on test page', async () => {
stableProduct = await stablePage.checkResultPage(testdata[key], key, keyNumber, 'stable', true);
});

stableProductScreenshots = stablePage.screenshots.slice();
stablePage.screenshots = [];

await test.step(`New: Select each answer on test page according to ${key}`, async () => {
await betaPage.clickEachAnswer(betaURL, key, keyNumber, 'beta', true);
});

await test.step('New: Check results on test page', async () => {
betaProduct = await betaPage.checkResultPage(testdata[key], key, keyNumber, 'beta', true);
});

betaProductScreenshots = betaPage.screenshots.slice();
betaPage.screenshots = [];

WebUtil.compareScreenshots(stableProductScreenshots, betaProductScreenshots, 'screenshots/uar');

expect.soft(betaProduct).toContain(stableProduct);
}
},
);
}
});

0 comments on commit bbbcec7

Please sign in to comment.