-
Notifications
You must be signed in to change notification settings - Fork 2
adding playwright VRT integration #86
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
base: 3.x
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # AGENTS | ||
|
|
||
| ## Entrypoint | ||
| - CLI entrypoint is `bin/fire` (executes `bin/fire.php`); it requires Composer autoload to exist, so run `composer install` before local runs. | ||
|
|
||
| ## Config + discovery | ||
| - `fire.yml` and optional `fire.local.yml` are read from the project root (four directories above `vendor/fourkitchens/fire`); if missing, only `InitCommand.php` is registered and the CLI prompts to run `fire init`. | ||
| - Local env auto-detection sets `local_environment` based on `.lando.yml` or `.ddev/config.yaml` in the project root. | ||
|
|
||
| ## Command sources | ||
| - Core commands live in `src/Robo/Plugin/Commands/*Command.php` and are discovered via Robo `CommandFileDiscovery`. | ||
| - Project-level custom commands are loaded from `fire/src/Commands` in the project root (path is computed by stripping `vendor/fourkitchens/` from the package path). | ||
|
|
||
| ## Config template | ||
| - `fire init` uses the template at `assets/templates/fire.yml`; update it if you change required config fields. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 24.15.0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| #toolbar-administration { | ||
| visibility: hidden; | ||
| } | ||
|
|
||
| .gin-secondary-toolbar__layout-container { | ||
| visibility: hidden; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| [ | ||
| { | ||
| "name": "Home", | ||
| "path": "/", | ||
| "screenshotName": "home-page" | ||
| }, | ||
| { | ||
| "name": "about-us", | ||
| "path": "/about-us", | ||
| "screenshotName": "about-us" | ||
| } | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| /* | ||
| * Automated Testing Kit configuration. | ||
| */ | ||
| var currentEnv = process.env.TERMINUS_ENV || 'local'; | ||
| var runOnPantheon = false; | ||
| if (currentEnv != 'local') { | ||
| runOnPantheon = true; | ||
| } | ||
|
|
||
| module.exports = { | ||
| operatingMode: "native", | ||
| drushCmd: "__DRUSH_CMD__", | ||
| articleAddUrl: 'node/add/article', | ||
| contactUsUrl: "form/contact", | ||
| logInUrl: "user/login", | ||
| logOutUrl: "user/logout", | ||
| imageAddUrl: 'media/add/image', | ||
| mediaDeleteUrl: 'media/{mid}/delete', | ||
| mediaEditUrl: 'media/{mid}/edit', | ||
| mediaList: 'admin/content/media', | ||
| menuAddUrl: 'admin/structure/menu/manage/main/add', | ||
| menuDeleteUrl: 'admin/structure/menu/item/{mid}/delete', | ||
| menuEditUrl: 'admin/structure/menu/item/{mid}/edit', | ||
| menuListUrl: 'admin/structure/menu/manage/main', | ||
| nodeDeleteUrl: 'node/{nid}/delete', | ||
| nodeEditUrl: 'node/{nid}/edit', | ||
| pageAddUrl: 'node/add/page', | ||
| registerUrl: "user/register", | ||
| resetPasswordUrl: "user/password", | ||
| termAddUrl: 'admin/structure/taxonomy/manage/terms/add', | ||
| termEditUrl: 'taxonomy/term/{tid}/edit', | ||
| termDeleteUrl: 'taxonomy/term/{tid}/delete', | ||
| termListUrl: 'admin/structure/taxonomy/manage/terms/overview', | ||
| termViewUrl: 'taxonomy/term/{tid}', | ||
| xmlSitemapUrl: 'admin/config/search/simplesitemap', | ||
| authDir: "tests/support", | ||
| dataDir: "tests/data", | ||
| supportDir: "tests/support", | ||
| testDir: "tests", | ||
| pantheon : { | ||
| isTarget: runOnPantheon, | ||
| site: "__PANTHEON_SITE__", | ||
| environment: currentEnv | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| // @ts-check | ||
| const { defineConfig, devices } = require('@playwright/test'); | ||
| import path from 'path' | ||
|
|
||
| /** | ||
| * Read environment variables from file. | ||
| * https://github.com/motdotla/dotenv | ||
| */ | ||
| require('dotenv').config(); | ||
|
|
||
| const configuredBaseURL = (process.env.REMOTE_ENV_BASE_URL || '__DEFAULT_BASE_URL__') | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this file reads process.env.REMOTE_ENV_BASE_URL to set the base URL. But the .env file the command generates writes CANDIDATE_URL and BASELINE_URL Mismatch? |
||
| .trim() | ||
| .replace(/\/+$/, '') | ||
|
|
||
| /** | ||
| * @see https://playwright.dev/docs/test-configuration | ||
| */ | ||
| module.exports = defineConfig({ | ||
| // Timeout. | ||
| timeout: 100000, | ||
| testDir: './tests', | ||
| /* 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: process.env.CI ? 'blob' : 'html', | ||
|
|
||
| expect: { | ||
| // timeout per assertion. | ||
| timeout: 100000, | ||
| toHaveScreenshot: { | ||
| stylePath: './css/screenshotGlobalStyle.css' | ||
| } | ||
| }, | ||
|
|
||
| /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ | ||
| use: { | ||
| /* Base URL to use in actions like `await page.goto('/')`. */ | ||
| baseURL: `${configuredBaseURL}/`, | ||
|
|
||
| /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ | ||
| trace: 'on', | ||
| launchOptions: { | ||
| slowMo: 0 | ||
| } | ||
| }, | ||
| /* Configure projects for major browsers */ | ||
| projects: [ | ||
| { | ||
| name: 'chromium', | ||
| use: { | ||
| ...devices['Desktop Chrome'], | ||
| userAgent: 'my-site-playwright-ci/1.0' | ||
| }, | ||
| }, | ||
|
|
||
| // { | ||
| // name: 'firefox', | ||
| // use: { ...devices['Desktop Firefox'] }, | ||
| // }, | ||
|
|
||
| // { | ||
| // name: 'webkit', | ||
| // use: { ...devices['Desktop Safari'] }, | ||
| // }, | ||
| ], | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| const { devices } = require('@playwright/test') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're mixing 'require' and 'export' in the same file. We should pick one standard. |
||
| // Helper function for lazy loading images. | ||
| const forceLoadLazyImages = async (page) => { | ||
| await page.evaluate(async () => { | ||
| document.querySelectorAll('[decoding="async"]').forEach((element) => { | ||
| element.decoding = 'sync' | ||
| }) | ||
|
|
||
| const images = Array.from(document.querySelectorAll('img[loading="lazy"]')) | ||
|
|
||
| for (const image of images) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, for loops can be slow sequence. Since this is JS we can fire these off in parallel and just await the work to be done. |
||
| image.loading = 'eager' | ||
| image.removeAttribute('loading') | ||
|
|
||
| try { | ||
| await image.decode() | ||
| } catch (error) { | ||
| // Ignore decode errors for lazy images. | ||
| } | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| // Returns devices profiles for VRT. | ||
| const vrtDeviceProfiles = (() => { | ||
| const desktopChromeProfile = { ...devices['Desktop Chrome'] } | ||
| const iPadProfile = { ...devices['iPad (gen 7)'] } | ||
| const iPhone12Profile = { ...devices['iPhone 12'] } | ||
|
|
||
| delete desktopChromeProfile.defaultBrowserType | ||
| delete iPadProfile.defaultBrowserType | ||
| delete iPhone12Profile.defaultBrowserType | ||
|
|
||
| return { | ||
| desktopChrome: desktopChromeProfile, | ||
| iPad: iPadProfile, | ||
| iPhone12: iPhone12Profile, | ||
| } | ||
| })() | ||
|
|
||
| const getVrtDeviceProfile = (key) => vrtDeviceProfiles[key] | ||
|
|
||
| export { | ||
| forceLoadLazyImages, | ||
| getVrtDeviceProfile, | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import * as aftUtilities from '../support/4k_utilities' | ||
| import commonPages from '../data/vrtCommonPages.json' | ||
|
|
||
| const { test, expect } = require('@playwright/test'); | ||
|
|
||
| //test.describe.configure({ mode: 'serial' }); | ||
|
|
||
| const runCommonVrtTest = async ({ page, path, screenshotName }) => { | ||
|
|
||
| await page.goto(path); | ||
| // Force-load lazy images. | ||
| await aftUtilities.forceLoadLazyImages(page); | ||
| await page.waitForLoadState('networkidle'); | ||
|
|
||
| await page.addStyleTag({ | ||
| content: ` | ||
| * { | ||
| animation: none !important; | ||
| transition: none !important; | ||
| } | ||
| ` | ||
| }); | ||
|
|
||
| await expect(page).toHaveScreenshot(screenshotName, { fullPage: true }); | ||
| } | ||
|
|
||
| const deviceProfiles = [ | ||
| { | ||
| title: 'Desktop', | ||
| profile: 'desktopChrome', | ||
| screenshotSuffix: 'desktop', | ||
| }, | ||
| { | ||
| title: 'iPad', | ||
| profile: 'iPad', | ||
| screenshotSuffix: 'ipad', | ||
| }, | ||
| { | ||
| title: 'iPhone 12', | ||
| profile: 'iPhone12', | ||
| screenshotSuffix: 'iphone-12', | ||
| }, | ||
| ] | ||
|
|
||
| for (const device of deviceProfiles) { | ||
| test.describe(`Common VRT - ${device.title}`, () => { | ||
| test.use({ ...aftUtilities.getVrtDeviceProfile(device.profile) }); | ||
|
|
||
| for (const commonPage of commonPages) { | ||
| test(`Common VRT - ${commonPage.name} - ${device.screenshotSuffix} @vrt`, async ({ page }) => { | ||
| await runCommonVrtTest({ | ||
| page, | ||
| path: commonPage.path, | ||
| screenshotName: `${commonPage.screenshotName}-${device.screenshotSuffix}.png`, | ||
| }); | ||
| }); | ||
| } | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to add a part here where we describe how to edit the common pages.