diff --git a/libs/screenshot/compare.mjs b/libs/screenshot/compare.mjs index c03a6bb7..0526aaec 100644 --- a/libs/screenshot/compare.mjs +++ b/libs/screenshot/compare.mjs @@ -20,7 +20,13 @@ async function downloadImage(url, localPath) { } async function getSavedImages(s3Url, curEntries) { - const response = await axios.get(`${s3Url}/results.json`); + let response; + try { + response = await axios.get(`${s3Url}/results.json`); + } catch (error) { + console.error(`Failed to get previous results.json from ${s3Url}`); + process.exit(1); + } const preEntries = response.data; if (Object.keys(curEntries).length !== Object.keys(preEntries).length) { @@ -36,7 +42,8 @@ async function getSavedImages(s3Url, curEntries) { } const basename = path.basename(preEntries[key][0].a); - entry.a = `${preEntries[key][0].a}`.replace('.png', '-a.png'); + entry.a = `${preEntries[key][0].a.includes('-a.png') + ? preEntries[key][0].a : preEntries[key][0].a.replace('.png', '-a.png')}`; console.log(`Downloading ${s3Url}/${basename}`); // eslint-disable-next-line no-await-in-loop await downloadImage(`${s3Url}/${basename}`, entry.a); @@ -45,44 +52,53 @@ async function getSavedImages(s3Url, curEntries) { async function main() { const localPath = process.argv[2]; - const s3Url = `${S3URL}/${localPath}`; - if (!localPath || !s3Url) { - console.log('Usage: node compare.js '); + if (!localPath) { + console.log('Usage: node compare.mjs '); process.exit(1); } const curEntries = JSON.parse(fs.readFileSync(`${localPath}/results.json`)); - if (s3Url) { - await getSavedImages(s3Url, curEntries); + const firstEntry = Object.values(curEntries)[0][0]; + + if (firstEntry.a && !firstEntry.b) { + const s3Url = `${S3URL}/${localPath}`; + + if (s3Url) { + await getSavedImages(s3Url, curEntries); + } } const results = {}; // eslint-disable-next-line no-restricted-syntax for (const [key, value] of Object.entries(curEntries)) { - const result = {}; - const entry = value[0]; - console.log(entry); - - const baseImage = fs.readFileSync(entry.a); - const currImage = fs.readFileSync(entry.b); - result.order = 1; - result.a = entry.a; - result.b = entry.b; - result.urls = entry.urls; - - const comparator = getComparator('image/png'); - const diffImage = comparator(baseImage, currImage); - - if (diffImage) { - const diffName = `${entry.b}`.replace('.png', '-diff.png'); - fs.writeFileSync(diffName, diffImage.diff); - result.diff = diffName; - console.info('Differences found'); + const resultsArray = []; + // eslint-disable-next-line no-restricted-syntax + for (const entry of value) { + const result = {}; + console.log(entry); + + const baseImage = fs.readFileSync(entry.a); + const currImage = fs.readFileSync(entry.b); + result.order = 1; + result.a = entry.a; + result.b = entry.b; + result.urls = entry.urls; + + const comparator = getComparator('image/png'); + const diffImage = comparator(baseImage, currImage); + + if (diffImage) { + const diffName = `${entry.b}`.replace('.png', '-diff.png'); + fs.writeFileSync(diffName, diffImage.diff); + result.diff = diffName; + console.info('Differences found'); + } + resultsArray.push(result); } - results[key] = [result]; + results[key] = resultsArray; } fs.writeFileSync(`${localPath}/results.json`, JSON.stringify(results, null, 2)); diff --git a/libs/screenshot/take.js b/libs/screenshot/take.js index 5d1342d1..5e53a718 100644 --- a/libs/screenshot/take.js +++ b/libs/screenshot/take.js @@ -1,16 +1,10 @@ -/* eslint-disable import/no-extraneous-dependencies */ -/* eslint-disable import/no-import-module-exports */ -// eslint-disable-next-line import/extensions -import { getComparator } from 'playwright-core/lib/utils'; - -const fs = require('fs'); - /** * Take a screenshot of a page * @param {Page} page - The page object * @param {string} folderPath - The folder path to save the screenshot, e.g., screenshots/milo * @param {string} fileName - The file name of the screenshot * @param {object} options - The screenshot options, see https://playwright.dev/docs/api/class-page#page-screenshot + * @returns {object} The screenshot result */ async function take(page, folderPath, fileName, options = {}) { const urls = []; @@ -28,6 +22,16 @@ async function take(page, folderPath, fileName, options = {}) { return result; } +/** + * Take a screenshot of a page + * @param {Page} page - The page object + * @param {string} url - The URL of the page to take a screenshot + * @param {function} callback - The callback function to run before taking the screenshot + * @param {string} folderPath - The folder path to save the screenshot, e.g., screenshots/milo + * @param {string} fileName - The file name of the screenshot + * @param {object} options - The screenshot options, see https://playwright.dev/docs/api/class-page#page-screenshot + * @returns {object} The screenshot result + */ async function takeOne(page, url, callback, folderPath, fileName, options = {}) { const urls = []; const result = {}; @@ -50,6 +54,17 @@ async function takeOne(page, url, callback, folderPath, fileName, options = {}) return result; } +/** + * Take screenshots of two pages + * @param {Page} page - The page object + * @param {string} urlStable - The URL of the stable page + * @param {function} callbackStable - The callback function to run before taking the screenshot of the stable page + * @param {string} urlBeta - The URL of the beta page + * @param {function} callbackBeta - The callback function to run before taking the screenshot of the beta page + * @param {string} folderPath - The folder path to save the screenshots, e.g., screenshots/milo + * @param {string} fileName - The file name of the screenshots + * @returns {object} The screenshot results + */ async function takeTwo(page, urlStable, callbackStable, urlBeta, callbackBeta, folderPath, fileName) { const urls = []; const result = {}; @@ -75,84 +90,8 @@ async function takeTwo(page, urlStable, callbackStable, urlBeta, callbackBeta, f return result; } -async function takeTwoAndCompare(page, urlStable, callbackStable, urlBeta, callbackBeta, folderPath, fileName) { - const urls = []; - const result = {}; - - console.info(`[Test Page]: ${urlStable}`); - await page.goto(urlStable); - urls.push(urlStable); - if (typeof callbackStable === 'function') { await callbackStable(); } - const nameStable = `${folderPath}/${fileName}-a.png`; - await page.screenshot({ path: nameStable, fullPage: true }); - const baseImage = fs.readFileSync(nameStable); - result.order = 1; - result.a = nameStable; - - console.info(`[Test Page]: ${urlBeta}`); - await page.goto(urlBeta); - urls.push(urlBeta); - if (typeof callbackBeta === 'function') { await callbackBeta(); } - const nameBeta = `${folderPath}/${fileName}-b.png`; - await page.screenshot({ path: nameBeta, fullPage: true }); - const currImage = fs.readFileSync(nameBeta); - result.b = nameBeta; - - const comparator = getComparator('image/png'); - const diffImage = comparator(baseImage, currImage); - - if (diffImage) { - const diffName = `${folderPath}/${fileName}-diff.png`; - fs.writeFileSync(diffName, diffImage.diff); - result.diff = diffName; - console.info('Differences found'); - } - - result.urls = urls.join(' | '); - return result; -} - -function compareScreenshots(stableArray, betaArray) { - const results = []; - const comparator = getComparator('image/png'); - for (let i = 0; i < stableArray.length; i += 1) { - if (betaArray[i].a.slice(-10) === stableArray[i].a.slice(-10)) { - const result = {}; - const urls = []; - result.order = i + 1; - result.a = `${stableArray[i].a}`; - result.b = `${betaArray[i].a}`; - urls.push(stableArray[i].urls); - urls.push(betaArray[i].urls); - const stableImage = fs.readFileSync(`${stableArray[i].a}`); - const betaImage = fs.readFileSync(`${betaArray[i].a}`); - const diffImage = comparator(stableImage, betaImage); - - if (diffImage) { - result.diff = `${stableArray[i].a}-diff.png`; - fs.writeFileSync(`${stableArray[i].a}-diff.png`, diffImage.diff); - console.info('Differences found'); - } - result.urls = urls.join(' | '); - results.push(result); - } else { - console.info('Screenshots are not matched'); - console.info(`${stableArray[i].a} vs ${betaArray[i].a}`); - } - } - return results; -} - -function writeResultsToFile(folderPath, testInfo, results) { - const resultFilePath = `${folderPath}/results-${testInfo.workerIndex}.json`; - fs.writeFileSync(resultFilePath, JSON.stringify(results, null, 2)); -} - module.exports = { - takeTwoAndCompare, - compareScreenshots, takeOne, takeTwo, take, - writeResultsToFile, }; diff --git a/libs/screenshot/uploads3.js b/libs/screenshot/uploads3.js index 1eb13e67..bef785fd 100644 --- a/libs/screenshot/uploads3.js +++ b/libs/screenshot/uploads3.js @@ -106,6 +106,16 @@ async function main() { console.log('Upload results.json'); await uploadFile(resultsPath, bucket, s3Path, creds, resultsPath, 'application/json'); + + const timestampPath = path.join(dir, 'timestamp.json'); + + fs.writeFileSync( + timestampPath, + JSON.stringify([(new Date()).toLocaleString()], null, 2), + ); + + console.log('Upload timestamp.json'); + await uploadFile(timestampPath, bucket, s3Path, creds, timestampPath, 'application/json'); } main(); diff --git a/libs/screenshot/utils.js b/libs/screenshot/utils.js new file mode 100644 index 00000000..29535841 --- /dev/null +++ b/libs/screenshot/utils.js @@ -0,0 +1,42 @@ +// eslint-disable-next-line import/no-extraneous-dependencies, import/extensions, import/no-import-module-exports +import { getComparator } from 'playwright-core/lib/utils'; + +const fs = require('fs'); + +function compareScreenshots(stableArray, betaArray) { + const results = []; + const comparator = getComparator('image/png'); + for (let i = 0; i < stableArray.length; i += 1) { + if (betaArray[i].a.slice(-10) === stableArray[i].a.slice(-10)) { + const result = {}; + const urls = []; + result.order = i + 1; + result.a = `${stableArray[i].a}`; + result.b = `${betaArray[i].a}`; + urls.push(stableArray[i].urls); + urls.push(betaArray[i].urls); + const stableImage = fs.readFileSync(`${stableArray[i].a}`); + const betaImage = fs.readFileSync(`${betaArray[i].a}`); + const diffImage = comparator(stableImage, betaImage); + + if (diffImage) { + result.diff = `${stableArray[i].a}-diff.png`; + fs.writeFileSync(`${stableArray[i].a}-diff.png`, diffImage.diff); + console.info('Differences found'); + } + result.urls = urls.join(' | '); + results.push(result); + } else { + console.info('Screenshots are not matched'); + console.info(`${stableArray[i].a} vs ${betaArray[i].a}`); + } + } + return results; +} + +function writeResultsToFile(folderPath, testInfo, results) { + const resultFilePath = `${folderPath}/results-${testInfo.workerIndex}.json`; + fs.writeFileSync(resultFilePath, JSON.stringify(results, null, 2)); +} + +module.exports = { compareScreenshots, writeResultsToFile }; diff --git a/tests/visual/caas/cards.test.js b/tests/visual/caas/cards.test.js index 52453523..1dee641a 100644 --- a/tests/visual/caas/cards.test.js +++ b/tests/visual/caas/cards.test.js @@ -1,7 +1,8 @@ /* eslint-disable import/named */ import { test } from '@playwright/test'; import { features } from '../../../features/visual/caas/cards.spec.js'; -import { takeTwoAndCompare, writeResultsToFile } from '../../../libs/screenshot/take.js'; +import { takeTwo } from '../../../libs/screenshot/take.js'; +import { writeResultsToFile } from '../../../libs/screenshot/utils.js'; const folderPath = 'screenshots/caas'; const results = {}; @@ -12,7 +13,7 @@ test.describe('Milo Caas block visual comparison test suite', () => { // eslint-disable-next-line no-loop-func test(`${feature.name},${feature.tags}`, async ({ page, baseURL }, testInfo) => { const name = `${feature.name}-${testInfo.project.name}`; - const result = await takeTwoAndCompare( + const result = await takeTwo( page, baseURL + feature.stable, async () => { await page.waitForTimeout(3000); }, diff --git a/tests/visual/feds/feds.test.js b/tests/visual/feds/feds.test.js index c0848ee4..616aa130 100644 --- a/tests/visual/feds/feds.test.js +++ b/tests/visual/feds/feds.test.js @@ -1,7 +1,8 @@ /* eslint-disable import/named */ import { expect, test } from '@playwright/test'; import { features } from '../../../features/visual/feds/feds.spec.js'; -import { takeOne, writeResultsToFile } from '../../../libs/screenshot/take.js'; +import { takeOne } from '../../../libs/screenshot/take.js'; +import { writeResultsToFile } from '../../../libs/screenshot/utils.js'; import FedsHeader from '../../../selectors/feds/feds.header.page.js'; const folderPath = 'screenshots/feds'; diff --git a/tests/visual/milo/milo.test.js b/tests/visual/milo/milo.test.js index 6ea6b6f3..46996017 100644 --- a/tests/visual/milo/milo.test.js +++ b/tests/visual/milo/milo.test.js @@ -1,7 +1,8 @@ /* eslint-disable import/named */ import { test } from '@playwright/test'; import { features } from '../../../features/visual/milo/milo.spec.js'; -import { takeOne, writeResultsToFile } from '../../../libs/screenshot/take.js'; +import { takeOne } from '../../../libs/screenshot/take.js'; +import { writeResultsToFile } from '../../../libs/screenshot/utils.js'; const folderPath = 'screenshots/milo'; const results = {}; diff --git a/tests/visual/uar/quiz.test.js b/tests/visual/uar/quiz.test.js index 0a88d1e5..2d857a26 100644 --- a/tests/visual/uar/quiz.test.js +++ b/tests/visual/uar/quiz.test.js @@ -6,7 +6,7 @@ import Quiz from '../../../selectors/uar/quiz.page.js'; const { features } = require('../../../features/visual/uar/quiz.spec.js'); const { WebUtil } = require('../../../libs/webutil.js'); -const { compareScreenshots, writeResultsToFile } = require('../../../libs/screenshot/take.js'); +const { compareScreenshots, writeResultsToFile } = require('../../../libs/screenshot/utils.js'); const envs = require('../../../envs/envs.js'); const folderPath = 'screenshots/uar';