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

Inital setup of visual regression tests. #209

Conversation

tellthemachines
Copy link
Contributor

@tellthemachines tellthemachines commented Apr 2, 2020

Trac ticket: 49606

Adding visual regression tests for wp-admin pages. Uses jest-image-snapshot, which integrates seamlessly with our Jest/Puppeteer setup for e2e tests.

One thing to consider is that these tests are a little slow to run. If we find it's not useful to run them as part of the e2e tests every time, we might want to split them out so they can be run separately.

I have added only snapshots of static pages for now. All pages with dynamic content will need a custom setup where we specify areas of the page where changes should be ignored. (It's pretty straightforward to do, but I thought it better to keep the initial changeset simple.)

If we find the tests are throwing a lot of false positives, we can also fiddle with the resolution until they pass.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

@tellthemachines
Copy link
Contributor Author

Update: this is ready for review now!

I have separated out the config from the e2e tests, and added a dedicated script (test:visual) so we can run these tests independently, and they're not automatically part of CI checks for all code changes.

I have also added the generated snapshots folder to .gitignore, so that snapshots are only stored locally. The tests don't really work cross-environment as even tiny differences between envs throw up too many false positives. If we do want to run them on CI at any point, we can set them up to run first on trunk to generate the snapshots, and then diff with the feature branch. That also solves the problem of storing huge .png files in the repo 😄

The tests are currently only running on pages with mostly static content (assuming a dedicated test environment where new content isn't added all the time, and the only things that change with frequency are dashboard contents and update notifications) but we can probably include more pages as long as we explicitly ignore the dynamic elements in them.

@tellthemachines
Copy link
Contributor Author

Another thing we'll probably want to add soon is tests for mobile breakpoints; currently we're only testing 1000px wide screens.

Copy link

@talldan talldan left a comment

Choose a reason for hiding this comment

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

Not sure what's going on, but I had issues running the tests locally. I used the --puppeteer-interactive command and it looks like the tests couldn't login, which is unusual:
test-issues

When I tested manually I didn't notice any issues with the environment. So I don't know what's happening. 😬

Would be great to see some docs on how the tests work (I imagine you have to generate some initial snapshots first and then test against that on a feature branch?) and what options the command takes (can I specify a port for my environment?). Not sure where such docs would go though. 😄

The main README does have a few briefer docs.

On the whole though, it looks like really good progress, just wish I could get it working!

tests/visual-regression/config/bootstrap.js Show resolved Hide resolved
} );
}
}
await new Promise( ( resolve ) => setTimeout( resolve, 1000 ) );
Copy link

Choose a reason for hiding this comment

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

The alternative would be page.waitForTimeout( 1000 ):
https://github.com/puppeteer/puppeteer/blob/v5.5.0/docs/api.md#pagewaitfortimeoutmilliseconds

But was wondering why it's needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The styling changes take a little time to apply, so without the timeout, the screenshot would be taken before the elements were actually hidden.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, page.waitForTimeout is too new an API for our version of puppeteer 😬

Copy link

Choose a reason for hiding this comment

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

Ah, it might just be page.waitFor in this version. They deprecated that more recently in favour of separate waitForTimeout and waitForSelector functions.

tests/visual-regression/specs/visual-snapshots.test.js Outdated Show resolved Hide resolved
@@ -78,3 +78,6 @@ wp-tests-config.php

# Files for local environment config
/docker-compose.override.yml

# Visual regression test diffs
tests/visual-regression/specs/__image_snapshots__
Copy link

@talldan talldan Jan 22, 2021

Choose a reason for hiding this comment

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

I'm not sure how, but I guess this also has to be added to the upstream SVN repo, like an svn:ignore equivalent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a very good question 😅 hopefully someone knows the answer to.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, the folder will need to be excluded upstream when committing by updating svn props.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, and the changed svn props can also be committed afterwards, if easier. As far as I see svn:ignore __image_snapshots__ will have to be added to the parent dir, tests/visual-regression/specs.

@talldan
Copy link

talldan commented Jan 22, 2021

Not sure what's going on, but I had issues running the tests locally. I used the --puppeteer-interactive command and it looks like the tests couldn't login, which is unusual:

@tellthemachines, I had a sudden brainwave. I think this might be related to the version of puppeteer in core—it's pretty outdated compared to Gutenberg, and IIRC the major changes were around page.waitForNavigation.

Thankfully updating should be an easy task as there are no tests to update 😄

Edit: I tried updating to the latest version locally, but still get that issue.

@tellthemachines
Copy link
Contributor Author

Not sure what's going on, but I had issues running the tests locally. I used the --puppeteer-interactive command and it looks like the tests couldn't login, which is unusual:

Hmm, that's funny, it works fine for me locally with npm run test:visual -- --puppeteer-interactive. Can you get it working ok without the interactive flag?

Would be great to see some docs on how the tests work (I imagine you have to generate some initial snapshots first and then test against that on a feature branch?)

That's the expected workflow with this setup, because testing across different environments is incredibly painful, but that's one of the things I'm looking for feedback on! Agree we should publish some docs when this is ready. Maybe in the handbook testing section?

@talldan
Copy link

talldan commented Jan 27, 2021

Hmm, that's funny, it works fine for me locally with npm run test:visual -- --puppeteer-interactive. Can you get it working ok without the interactive flag?

The issue also happens without the --puppeteer-interactive flag, I used that to determine what was going wrong.

Would be good to get more folks testing to see if it's just me. If it is just me then I know I need to spend some time fixing my dodgy local environment 😄

@danfarrow
Copy link

Would be good to get more folks testing to see if it's just me. If it is just me then I know I need to spend some time fixing my dodgy local environment smile

hi @talldan, I just checked this out. The tests are running, producing visual diffs etc. both with & without --puppeteer-interactive.

Let me know if you need any info about my setup for comparison.

@talldan
Copy link

talldan commented Jan 28, 2021

Thanks for mentioning that @danfarrow, could just be me then.

@draganescu
Copy link

I tested this and it works great

@hellofromtonya
Copy link
Contributor

hellofromtonya commented Mar 17, 2021

Results of running locally.

Env:

  • Using Docker image
  • OS: Mac Big Sur
  • Started freshed
    • Cleared Docker cache
    • Removed node_modules and cleared its cache
    • Removed vendor and cleared its cache
    • Ran:
npm install
composer install
npm run build
npm run build:dev
npm run env:start
npm run env:install
npm run test:visual

Attempt 1: First Run - Timeout

When first launching npm run test:visual (with PR and against master), fails for timeout:

 FAIL  tests/visual-regression/specs/visual-snapshots.test.js (62.582s)
  Admin Visual Snapshots
    ✕ All Posts (5007ms)
    ✓ Categories (2581ms)
    ✓ Tags (2561ms)
    ✓ Media Library (2670ms)
    ✓ Add New Media (2525ms)
    ✓ All Pages (2545ms)
    ✓ Comments (2646ms)
    ✓ Widgets (2972ms)
    ✓ Menus (2611ms)
    ✓ Plugins (2694ms)
    ✓ All Users (2571ms)
    ✓ Add New User (2628ms)
    ✓ Your Profile (2809ms)
    ✓ Available Tools (2461ms)
    ✓ Import (2692ms)
    ✓ Export (2495ms)
    ✓ Export Personal Data (2483ms)
    ✓ Erase Personal Data (2484ms)
    ✓ Reading Settings (2546ms)
    ✓ Discussion Settings (2697ms)
    ✓ Media Settings (2553ms)
    ✓ Privacy Settings (2490ms)

  ● Admin Visual Snapshots › All Posts

    : Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Error:

      42 | 	} );
      43 |
    > 44 | 	it( 'All Posts', async () => {
         | 	^
      45 | 		await visitAdminPage( '/edit.php' );
      46 | 		await hideElementVisibility( elementsToHide );
      47 | 		await removeElementFromLayout( elementsToRemove );

      at new Spec (../../node_modules/jest-jasmine2/build/jasmine/Spec.js:116:22)
      at Suite.<anonymous> (specs/visual-snapshots.test.js:44:2)

 › 22 snapshots written.
Snapshot Summary
 › 22 snapshots written from 1 test suite.

Test Suites: 1 failed, 1 total
Tests:       1 failed, 21 passed, 22 total
Snapshots:   22 written, 22 total
Time:        62.789s, estimated 63s

Attempt 2: Applying PR against master

  • Env: Applied the PR's against master and then rebuilding
  • Result: Categories and Your Profile tests fail for image size
  Admin Visual Snapshots
    ✓ All Posts (3820 ms)
    ✕ Categories (2892 ms)
    ✓ Tags (2662 ms)
    ✓ Media Library (2769 ms)
    ✓ Add New Media (2618 ms)
    ✓ All Pages (2630 ms)
    ✓ Comments (2749 ms)
    ✓ Widgets (3202 ms)
    ✓ Menus (2699 ms)
    ✓ Plugins (2631 ms)
    ✓ All Users (2607 ms)
    ✓ Add New User (2741 ms)
    ✕ Your Profile (3444 ms)
    ✓ Available Tools (2588 ms)
    ✓ Import (2657 ms)
    ✓ Export (2600 ms)
    ✓ Export Personal Data (2594 ms)
    ✓ Erase Personal Data (2596 ms)
    ✓ Reading Settings (2652 ms)
    ✓ Discussion Settings (3065 ms)
    ✓ Media Settings (2655 ms)
    ✓ Privacy Settings (2610 ms)

  ● Admin Visual Snapshots › Categories

    Expected image to be the same size as the snapshot (1000x750), but was different (1000x853).
    See diff for details: .../wordpress-develop/tests/visual-regression/specs/__image_snapshots__/__diff_output__/visual-snapshots-test-js-admin-visual-snapshots-categories-1-diff.png

      55 | 		await removeElementFromLayout( elementsToRemove );
      56 | 		const image = await page.screenshot( screenshotOptions );
    > 57 | 		expect( image ).toMatchImageSnapshot();
         | 		                ^
      58 | 	} );
      59 |
      60 | 	it( 'Tags', async () => {

      at Object.<anonymous> (specs/visual-snapshots.test.js:57:19)

  ● Admin Visual Snapshots › Your Profile

    Expected image to be the same size as the snapshot (1000x2161), but was different (1000x2182).
    See diff for details: ../wordpress-develop/tests/visual-regression/specs/__image_snapshots__/__diff_output__/visual-snapshots-test-js-admin-visual-snapshots-your-profile-1-diff.png

      146 | 		await removeElementFromLayout( elementsToRemove );
      147 | 		const image = await page.screenshot( screenshotOptions );
    > 148 | 		expect( image ).toMatchImageSnapshot();
          | 		                ^
      149 | 	} );
      150 |
      151 | 	it( 'Available Tools', async () => {

      at Object.<anonymous> (specs/visual-snapshots.test.js:148:19)

 › 2 snapshots failed.
Snapshot Summary
 › 2 snapshots failed from 1 test suite. Inspect your code changes or re-run jest with `-u` to update them.

Test Suites: 1 failed, 1 total
Tests:       2 failed, 20 passed, 22 total
Snapshots:   2 failed, 22 passed, 24 total
Time:        62.336 s, estimated 104 s

Attempt 3: When pulling and checking out PR

  • Env: Pulled and checked out the PR and then rebuilt
  • Result: Categories and Your Profile tests fail for image size (same as Attempt 2).
 FAIL  tests/visual-regression/specs/visual-snapshots.test.js (62.646s)
  Admin Visual Snapshots
    ✓ All Posts (3739ms)
    ✕ Categories (2894ms)
    ✓ Tags (2699ms)
    ✓ Media Library (2756ms)
    ✓ Add New Media (2606ms)
    ✓ All Pages (2661ms)
    ✓ Comments (2770ms)
    ✓ Widgets (3206ms)
    ✓ Menus (2704ms)
    ✓ Plugins (2658ms)
    ✓ All Users (2646ms)
    ✓ Add New User (2769ms)
    ✕ Your Profile (3425ms)
    ✓ Available Tools (2598ms)
    ✓ Import (2683ms)
    ✓ Export (2621ms)
    ✓ Export Personal Data (2599ms)
    ✓ Erase Personal Data (2600ms)
    ✓ Reading Settings (2661ms)
    ✓ Discussion Settings (3229ms)
    ✓ Media Settings (2659ms)
    ✓ Privacy Settings (2611ms)

  ● Admin Visual Snapshots › Categories

    Expected image to match or be a close match to snapshot but was 0.0018458197611292075% different from snapshot (17 differing pixels).
    See diff for details: .../wordpress-develop/tests/visual-regression/specs/__image_snapshots__/__diff_output__/visual-snapshots-test-js-admin-visual-snapshots-categories-1-diff.png

      55 | 		await removeElementFromLayout( elementsToRemove );
      56 | 		const image = await page.screenshot( screenshotOptions );
    > 57 | 		expect( image ).toMatchImageSnapshot();
         | 		                ^
      58 | 	} );
      59 |
      60 | 	it( 'Tags', async () => {

      at Object.<anonymous> (specs/visual-snapshots.test.js:57:19)

  ● Admin Visual Snapshots › Your Profile

    Expected image to be the same size as the snapshot (1000x2229), but was different (1000x2250).
    See diff for details: .../wordpress-develop/tests/visual-regression/specs/__image_snapshots__/__diff_output__/visual-snapshots-test-js-admin-visual-snapshots-your-profile-1-diff.png

      146 | 		await removeElementFromLayout( elementsToRemove );
      147 | 		const image = await page.screenshot( screenshotOptions );
    > 148 | 		expect( image ).toMatchImageSnapshot();
          | 		                ^
      149 | 	} );
      150 |
      151 | 	it( 'Available Tools', async () => {

      at Object.<anonymous> (specs/visual-snapshots.test.js:148:19)

 › 1 snapshot written.
 › 2 snapshots failed.
Snapshot Summary
 › 1 snapshot written from 1 test suite.
 › 2 snapshots failed from 1 test suite. Inspect your code changes or re-run jest with `-u` to update them.

Test Suites: 1 failed, 1 total
Tests:       2 failed, 20 passed, 22 total
Snapshots:   2 failed, 1 written, 21 passed, 24 total
Time:        62.729s

@hellofromtonya
Copy link
Contributor

hellofromtonya commented Mar 17, 2021

Update:

Steps before running the tests:

  • destroyed the docker instance
  • cleaned docker's cache/data
  • restarted docker
  • then walked through the steps above

Results:

  • First try: timeout (same as Attempt 1 above)
  • Second try: passed 🎉
 PASS  tests/visual-regression/specs/visual-snapshots.test.js (60.056s)
  Admin Visual Snapshots
    ✓ All Posts (3591ms)
    ✓ Categories (2794ms)
    ✓ Tags (2693ms)
    ✓ Media Library (2831ms)
    ✓ Add New Media (2494ms)
    ✓ All Pages (2540ms)
    ✓ Comments (2629ms)
    ✓ Widgets (2991ms)
    ✓ Menus (2596ms)
    ✓ Plugins (2537ms)
    ✓ All Users (2575ms)
    ✓ Add New User (2835ms)
    ✓ Your Profile (2805ms)
    ✓ Available Tools (2475ms)
    ✓ Import (2558ms)
    ✓ Export (2502ms)
    ✓ Export Personal Data (2514ms)
    ✓ Erase Personal Data (2499ms)
    ✓ Reading Settings (2587ms)
    ✓ Discussion Settings (2879ms)
    ✓ Media Settings (2550ms)
    ✓ Privacy Settings (2479ms)

 › 18 snapshots written.
Snapshot Summary
 › 18 snapshots written from 1 test suite.

Test Suites: 1 passed, 1 total
Tests:       22 passed, 22 total
Snapshots:   18 written, 4 passed, 22 total
Time:        60.166s
Ran all test suites.

Copy link
Contributor

@hellofromtonya hellofromtonya left a comment

Choose a reason for hiding this comment

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

The PR is ready. It lays the first baby step towards the ability to do visual regression testing, i.e. first locally and then later through the CI.

@danfarrow
Copy link

danfarrow commented Mar 17, 2021

Expected image to match or be a close match... but was 0.0018458197611292075% different

🤣

@JustinyAhin
Copy link
Member

JustinyAhin commented Apr 8, 2021

Results of running locally.

Env:
Fresh WordPress Develop fork
Using Docker image
OS: Mac M1 Big Sur

I ran these commands:

npm install
composer install
npm run build
npm run build:dev
npm run env:start
npm run env:install

Then I ran this command npm run test:visual but got a bunch of errors:

Error: Cannot find module 'puppeteer'
Require stack:
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/jest-environment-puppeteer/lib/readConfig.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/jest-environment-puppeteer/lib/global.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/jest-environment-puppeteer/setup.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/@jest/transform/build/ScriptTransformer.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/@jest/transform/build/index.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/@jest/core/node_modules/jest-runtime/build/index.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/@jest/core/build/cli/index.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/@jest/core/build/jest.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/jest/node_modules/jest-cli/build/cli/index.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/jest/node_modules/jest-cli/build/index.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/jest/build/jest.js
- /Users/segbedji/dev/wp/wordpress-develop/node_modules/@wordpress/scripts/scripts/test-e2e.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:815:15)
    at Function.Module._load (internal/modules/cjs/loader.js:667:27)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at getPuppeteer (/Users/segbedji/dev/wp/wordpress-develop/node_modules/jest-environment-puppeteer/lib/readConfig.js:58:14)
    at setup (/Users/segbedji/dev/wp/wordpress-develop/node_modules/jest-environment-puppeteer/lib/global.js:21:50)
    at async /Users/segbedji/dev/wp/wordpress-develop/node_modules/@jest/core/build/runGlobalHook.js:82:11
    at async waitForPromiseWithCleanup (/Users/segbedji/dev/wp/wordpress-develop/node_modules/@jest/transform/build/ScriptTransformer.js:207:5)
    at async /Users/segbedji/dev/wp/wordpress-develop/node_modules/@jest/core/build/runGlobalHook.js:72:9
    at async pEachSeries (/Users/segbedji/dev/wp/wordpress-develop/node_modules/p-each-series/index.js:8:23)
child_process.js:674
    throw err;
    ^

Error: Command failed: wp-scripts test-e2e --config tests/visual-regression/jest.config.js 
    at checkExecSyncError (child_process.js:635:11)
    at execSync (child_process.js:671:15)
    at Object.<anonymous> (/Users/segbedji/dev/wp/wordpress-develop/tests/visual-regression/run-tests.js:9:1)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
    at internal/main/run_main_module.js:17:47 {
  status: 1,
  signal: null,
  output: [ null, null, null ],
  pid: 68953,
  stdout: null,
  stderr: null
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] test:visual: `node ./tests/visual-regression/run-tests.js`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] test:visual script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/segbedji/.npm/_logs/2021-04-08T16_01_53_408Z-debug.log

I don't really get the why of this error, as npm install worked correctly initially.

I clear the /node_modules folder and ran the visual test command again, but still got the same error.

@hellofromtonya
Copy link
Contributor

Re-ran npm run test:visual locally and still passes.

 PASS  tests/visual-regression/specs/visual-snapshots.test.js (56.001 s)
  Admin Visual Snapshots
    ✓ All Posts (4034 ms)
    ✓ Categories (2343 ms)
    ✓ Tags (2300 ms)
    ✓ Media Library (2395 ms)
    ✓ Add New Media (2349 ms)
    ✓ All Pages (2316 ms)
    ✓ Comments (2337 ms)
    ✓ Widgets (3819 ms)
    ✓ Menus (2425 ms)
    ✓ Plugins (2507 ms)
    ✓ All Users (2312 ms)
    ✓ Add New User (2353 ms)
    ✓ Your Profile (2447 ms)
    ✓ Available Tools (2294 ms)
    ✓ Import (2486 ms)
    ✓ Export (2298 ms)
    ✓ Export Personal Data (2298 ms)
    ✓ Erase Personal Data (2299 ms)
    ✓ Reading Settings (2300 ms)
    ✓ Discussion Settings (2409 ms)
    ✓ Media Settings (2290 ms)
    ✓ Privacy Settings (2299 ms)

 › 22 snapshots written.
Snapshot Summary
 › 22 snapshots written from 1 test suite.

Test Suites: 1 passed, 1 total
Tests:       22 passed, 22 total
Snapshots:   22 written, 22 total
Time:        56.062 s

Preparing this PR for commit.

@hellofromtonya
Copy link
Contributor

npm build failures seem to be due to the package-lock.json changes. As an experiment (done in PR #1803), I reverted that file, deleted the node_modules folder, and then did npm install to regenerate the lock file with the package deps added by this PR. npm builds passed 🎉

@hellofromtonya
Copy link
Contributor

Committed via changeset https://core.trac.wordpress.org/changeset/51989.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants