Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MWPW-135084 POC Visual Comparison Test #375

Merged
merged 3 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
},
"homepage": "https://github.com/adobecom/college#readme",
"devDependencies": {
"@amwp/platform-ui-automation": "^0.0.2",
"@amwp/platform-ui-automation": "^0.0.3",
"@amwp/platform-ui-lib-adobe": "^0.0.2",
"@babel/core": "7.17.7",
"@babel/eslint-parser": "7.17.0",
Expand Down
34 changes: 34 additions & 0 deletions test/e2e/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## Scenario Test

E2E tests that simulate an end user's journey and ensure that UI elements exist as expected.

```
npx run test/e2e/frictionless -t "@smoke and @gnav"
```

## Visual Test

Scenario tests fall short of detecting layout and rendering issues. Visual tests fill the gaps.

Visual tests leverage the existing user steps. and verify the screenshots of selected elements.

```
npx run test/e2e/frictionless -t "@visual and @gnav"
```

For example, a feature file `test/e2e/frictionless/features/visual/gnav.feature`

```
Scenario: Navigate Gnav Menus
Given I go to the compress-pdf page
Then I screenshot the submenu of the 1st and 3rd menu items
Then I should see the same screenshots as baseline
```

The baseline screenshots are stored in the folder `test/e2e/frictionless/features/visual/gnav`. Each OS platform and browser has its own baseline. When the test is running, the current screenshots are stored in `reports/screenshot/visual/gnav`. The final step compares screenshots just taken with the baseline. The differences are stored under `reports` with the file name format `${platform}_${browser}_${image-name}.png`

It can also compare the rendering of two different browers. For exmaple, the following command will run the test with the Webkit browser and compare to Firefox's baseline.

```
npx run test/e2e/frictionless -t "@visual and @gnav" -b webkit --baseBrowser firefox
```
12 changes: 12 additions & 0 deletions test/e2e/frictionless/features/visual/gnav.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Feature: Frictionless Gnav Visual Tests

Background:
Given I have a new browser context

@MWPW-136087 @visual @gnav
Scenario: Navigate Gnav Menus
Given I go to the compress-pdf page
When I resize the browser window to 1920x1080
And I screenshot the submenu of the 1st and 3rd menu items
Then I should see the same screenshots as baseline

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion test/e2e/frictionless/profiles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ live:
baseUrl: https://${branch}--dc--adobecom.hlx.live

preview:
baseUrl: https://${branch}--dc--adobecom.hlx.page
baseUrl: https://${branch}--dc--adobecom.hlx.page

local:
baseUrl: http://localhost:3000
62 changes: 48 additions & 14 deletions test/e2e/frictionless/step-definitions/dc.steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ import { CompressPdfPage } from "../page-objects/compresspdf.page";
import { FrictionlessPage } from "../page-objects/frictionless.page";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <import/extensions> reported by reviewdog 🐶
Missing file extension "js" for "../page-objects/frictionless.page"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <quotes> reported by reviewdog 🐶
Strings must use singlequote.

Suggested change
import { FrictionlessPage } from "../page-objects/frictionless.page";
import { FrictionlessPage } from '../page-objects/frictionless.page';

import { cardinal } from "../support/cardinal";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <import/extensions> reported by reviewdog 🐶
Missing file extension "js" for "../support/cardinal"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <quotes> reported by reviewdog 🐶
Strings must use singlequote.

Suggested change
import { cardinal } from "../support/cardinal";
import { cardinal } from '../support/cardinal';

import { expect } from "@playwright/test";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <import/no-extraneous-dependencies> reported by reviewdog 🐶
'@playwright/test' should be listed in the project's dependencies. Run 'npm i -S @playwright/test' to add it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <import/newline-after-import> reported by reviewdog 🐶
Expected 1 empty line after import statement not followed by another import.

Suggested change
import { expect } from "@playwright/test";
import { expect } from "@playwright/test";

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <import/order> reported by reviewdog 🐶
@playwright/test import should occur before import of ../page-objects/pdftoppt.page

reviewdog suggestion errorGitHub comment range and suggestion line range must be same. L25-L25 v.s. L2-L25

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <quotes> reported by reviewdog 🐶
Strings must use singlequote.

Suggested change
import { expect } from "@playwright/test";
import { expect } from '@playwright/test';

const os = require("os");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <quotes> reported by reviewdog 🐶
Strings must use singlequote.

Suggested change
const os = require("os");
const os = require('os');

const path = require("path");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <quotes> reported by reviewdog 🐶
Strings must use singlequote.

Suggested change
const path = require("path");
const path = require('path');

const fs = require("fs");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <import/newline-after-import> reported by reviewdog 🐶
Expected 1 empty line after require statement not followed by another require.

Suggested change
const fs = require("fs");
const fs = require("fs");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <quotes> reported by reviewdog 🐶
Strings must use singlequote.

Suggested change
const fs = require("fs");
const fs = require('fs');

import { getComparator } from 'playwright-core/lib/utils';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <import/first> reported by reviewdog 🐶
Import in body of module; reorder to top.

reviewdog suggestion errorGitHub comment range and suggestion line range must be same. L29-L29 v.s. L1-L29

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <import/no-extraneous-dependencies> reported by reviewdog 🐶
'playwright-core' should be listed in the project's dependencies. Run 'npm i -S playwright-core' to add it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <import/order> reported by reviewdog 🐶
playwright-core/lib/utils import should occur before import of ../page-objects/pdftoppt.page

reviewdog suggestion errorGitHub comment range and suggestion line range must be same. L29-L29 v.s. L2-L29

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <import/extensions> reported by reviewdog 🐶
Missing file extension "js" for "playwright-core/lib/utils"


async function enableNetworkLogging(page) {
if (global.config.profile.enableAnalytics) {
Expand Down Expand Up @@ -253,20 +255,63 @@ Then(/^I dismiss the extension modal$/, async function () {
await this.page.closeExtensionModal.click();
});

Then(/^I should be able to open the submenu of the (.*) menu item(?:|s)$/, async function (items) {
Then(/^I (screenshot|should be able to open) the submenu of the (.*) menu item(?:|s)$/, async function (action, items) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [eslint] <func-names> reported by reviewdog 🐶
Unexpected unnamed async function.

this.context(FrictionlessPage);

let menuItems = items.replace(/ and /g, ",").split(",");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <quotes> reported by reviewdog 🐶
Strings must use singlequote.

Suggested change
let menuItems = items.replace(/ and /g, ",").split(",");
let menuItems = items.replace(/ and /g, ',').split(",");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <quotes> reported by reviewdog 🐶
Strings must use singlequote.

Suggested change
let menuItems = items.replace(/ and /g, ",").split(",");
let menuItems = items.replace(/ and /g, ",").split(',');

menuItems = menuItems.map((x) => x.trim()).filter((x) => x.length > 0);
for (let item of menuItems) {
for (let item of menuItems) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <prefer-const> reported by reviewdog 🐶
'item' is never reassigned. Use 'const' instead.

Suggested change
for (let item of menuItems) {
for (const item of menuItems) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <no-trailing-spaces> reported by reviewdog 🐶
Trailing spaces not allowed.

Suggested change
for (let item of menuItems) {
for (let item of menuItems) {

const index = cardinal(item);
await this.page.openSubMenu(index);
await expect(this.page.fedsPopup).toBeVisible();
await this.page.fedsPopup.screenshot({path: `fedsPopup-${item}.png`});
if (action === 'screenshot') {
const profile = global.config.profile;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <prefer-destructuring> reported by reviewdog 🐶
Use object destructuring.

Suggested change
const profile = global.config.profile;
const {profile} = global.config;

let outputDir = this.gherkinDocument.uri.split('/features/')[1].replace('.feature', '');
outputDir = `${profile.reportDir}/screenshots/${outputDir}/${os.platform()}/${profile.browser}`;
await this.page.fedsPopup.screenshot({path: `${outputDir}/gnav-submenu-${item}.png`});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <object-curly-spacing> reported by reviewdog 🐶
A space is required after '{'.

Suggested change
await this.page.fedsPopup.screenshot({path: `${outputDir}/gnav-submenu-${item}.png`});
await this.page.fedsPopup.screenshot({ path: `${outputDir}/gnav-submenu-${item}.png`});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <object-curly-spacing> reported by reviewdog 🐶
A space is required before '}'.

Suggested change
await this.page.fedsPopup.screenshot({path: `${outputDir}/gnav-submenu-${item}.png`});
await this.page.fedsPopup.screenshot({path: `${outputDir}/gnav-submenu-${item}.png` });

}
await this.page.closeSubMenu(index);
await expect(this.page.fedsPopup).not.toBeVisible();
}
});

/***
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <spaced-comment> reported by reviewdog 🐶
Expected exception block, space or tab after '/**' in comment.

Suggested change
/***
/** *

* This step is used to compare the current screenshots with the baseline
* screenshots.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <no-trailing-spaces> reported by reviewdog 🐶
Trailing spaces not allowed.

Suggested change
* screenshots.
* screenshots.

*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <no-trailing-spaces> reported by reviewdog 🐶
Trailing spaces not allowed.

Suggested change
*
*

* Baseline Folder: features/${feature-name}/${platform}/${browser}
* Current Folder: ${report-dir}/screenshots/${feature-name}/${platform}/${browser}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <no-trailing-spaces> reported by reviewdog 🐶
Trailing spaces not allowed.

Suggested change
* Current Folder: ${report-dir}/screenshots/${feature-name}/${platform}/${browser}
* Current Folder: ${report-dir}/screenshots/${feature-name}/${platform}/${browser}

* Diff Image: ${report-dir}/${platform}_${browser}_${image-name}.png
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <no-trailing-spaces> reported by reviewdog 🐶
Trailing spaces not allowed.

Suggested change
*
*

* Command line options:
* --baseBrowser: Use a different browser to compare with the current browser
*/
Then(/^I should see the same screenshots as baseline$/, async function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [eslint] <func-names> reported by reviewdog 🐶
Unexpected unnamed async function.

const comparator = getComparator('image/png');
let baseDir = this.gherkinDocument.uri.replace('.feature', '');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <prefer-const> reported by reviewdog 🐶
'baseDir' is never reassigned. Use 'const' instead.

Suggested change
let baseDir = this.gherkinDocument.uri.replace('.feature', '');
const baseDir = this.gherkinDocument.uri.replace('.feature', '');


const profile = global.config.profile;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <prefer-destructuring> reported by reviewdog 🐶
Use object destructuring.

Suggested change
const profile = global.config.profile;
const {profile} = global.config;

let outputDir = this.gherkinDocument.uri.split('/features/')[1].replace('.feature', '');
outputDir = `${profile.reportDir}/screenshots/${outputDir}/${os.platform()}/${profile.browser}`;
const images = fs.readdirSync(outputDir).filter(x => x.endsWith('.png'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <arrow-parens> reported by reviewdog 🐶
Expected parentheses around arrow function argument.

Suggested change
const images = fs.readdirSync(outputDir).filter(x => x.endsWith('.png'));
const images = fs.readdirSync(outputDir).filter((x) => x.endsWith('.png'));


const baseBrowser = profile.baseBrowser || profile.browser;

const errors = [];
for (let image of images) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <prefer-const> reported by reviewdog 🐶
'image' is never reassigned. Use 'const' instead.

Suggested change
for (let image of images) {
for (const image of images) {

const baseImage = fs.readFileSync(`${baseDir}/${os.platform()}/${baseBrowser}/${image}`);
const currImage = fs.readFileSync(`${outputDir}/${image}`);
let diffImage = comparator(baseImage, currImage);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <prefer-const> reported by reviewdog 🐶
'diffImage' is never reassigned. Use 'const' instead.

Suggested change
let diffImage = comparator(baseImage, currImage);
const diffImage = comparator(baseImage, currImage);

if (diffImage) {
errors.push(image);
fs.writeFileSync(`${profile.reportDir}/${os.platform()}_${profile.browser}_${image}`, diffImage.diff);
}
}
if (errors.length > 0) {
throw `Differences found: ${errors.join(', ')}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <no-throw-literal> reported by reviewdog 🐶
Expected an error object to be thrown.

}
});

Then(/^I should be able to use the "([^\"]*)" submenu$/, async function (menu) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <no-useless-escape> reported by reviewdog 🐶
Unnecessary escape character: ".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [eslint] <func-names> reported by reviewdog 🐶
Unexpected unnamed async function.

this.context(FrictionlessPage);
await this.page.openSubMenu(menu);
Expand Down Expand Up @@ -296,14 +341,3 @@ Then(/^I switch to the new page after clicking "Buy now" button in the header$/,
this.page.native = newPage;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [eslint] <no-trailing-spaces> reported by reviewdog 🐶
Trailing spaces not allowed.

Suggested change
this.page.native = newPage;
this.page.native = newPage;

});

Then(
/^I should not see the address bar contains "([^\"]*)"$/,
async function (fragment) {
const pattern = fragment.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
await expect(this.page.native).not.toHaveURL(new RegExp(pattern), {timeout: 10000});
}
);

Then(/^I go back$/, async function () {
await this.page.native.goBack();
});