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

Add fixture pausing and --open option to replace --manual #71

Closed
wants to merge 43 commits into from

Conversation

bearfriend
Copy link
Contributor

@bearfriend bearfriend commented Jul 13, 2023

US152298: Visual-diff: ability to debug in the browser

  • Removes --manual option (still accessible via --watch)
  • Adds --open option to run tests in headed playwright browsers without --watch
  • Fixes various issues with taking screenshots in headed Chrome and both headed and headless Firefox
  • Adds fixture pausing in headed browser modes with UI controls to
    • start or skip test files
    • run or skip individual tests
    • retry failed tests
    • run all remaining tests

@bearfriend bearfriend marked this pull request as ready for review July 13, 2023 12:43
@bearfriend bearfriend requested a review from a team as a code owner July 13, 2023 12:43
package.json Outdated Show resolved Hide resolved
src/server/pause.js Outdated Show resolved Hide resolved
src/server/pause.js Outdated Show resolved Hide resolved
src/server/wtr-config.js Show resolved Hide resolved
@@ -30,6 +30,7 @@ export async function focusElem(elem) {

export async function hoverAt(x, y) {
await sendMouse({ type: 'move', position: [x, y] });
if (window.d2lTest) window.d2lTest.hovering = true;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indicates to screenshotAndCompare that the current test performed a hover. For Chrome, this means we need to move all styles inline for the screenshot.

async function pause() {
const test = window.d2lTest || {};

test.update?.();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

test should probably be testControls

});
mocha.setup({ // eslint-disable-line no-undef

chai.Assertion.addChainableMethod('soon',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This lets you do expect(elem).to.be.soon.golden() to delay comparing until the next frame + an updateComplete. I found this was necessary in Firefox for some of the vdiff tests in core.

Copy link
Member

Choose a reason for hiding this comment

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

Interesting. Did they share anything in common with each other? My worry with adding this would be that it'd become a "silver bullet" for flaky tests, when in reality the problem was more related to the consumer not properly awaiting updateComplete after making an update or not awaiting an event after triggering a change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, that's totally fair. The (mostly) common thread was changing things outside the component itself that would cause it to update (like scrolling or inserting HTML into the fixture's light DOM), but not until the next frame, so updateComplete isn't necessarily doing anything helpful here, but seemed good to include, except when you consider the potential for misuse.

Anyway, I think we can get rid of it and change these floating-buttons test like this:

	// fixed with oneEvent()
	it('does not float at bottom of container', async() => {
		const elem = await fixture(floatingButtonsFixture);
		window.scrollTo(0, document.body.scrollHeight);
		await oneEvent(window, 'scroll');
		await expect(elem).to.be.golden();
	});

	// doesn't make sense to me that this one would need a nextFrame(), but it does fix it
	it('does not float when small amount of content', async() => {
		const elem = await fixture(floatingButtonsShortFixture);
		await nextFrame();
		await expect(elem).to.be.golden();
	});

	// fixed with nextFrame()
	it('floats when content added to dom', async() => {
		const elem = await fixture(floatingButtonsShortFixture);
		const contentElem = document.querySelector('#floating-buttons-short-content').querySelector('p');
		contentElem.innerHTML += '<br><br>I love Coffee...';
		await nextFrame();
		await expect(elem).to.be.golden();
	});

To be honest I kind of just wanted to get a custom chai property to work 😆

Copy link
Member

Choose a reason for hiding this comment

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

Haha cool. Yeah I'm totally fine with tests needing to await nextFrame() themselves if they do things that would require waiting for a repaint. At least that's logical.

Comment on lines +63 to +64
window.d2lTest.fail();
await window.d2lTest.retryResponse;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rejects the result promise being await-ed to show the Retry button.

window.d2lTest?.pass();
}

const disallowedProps = ['width', 'inline-size'];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't love this, since width in particular could be a hover style, but setting the computed width causes issues in grid layouts like lists. We could get fancier down the line as-needed.

Also, I think the headed tests passing is ok as "best effort". It's really more to step through and debug anyway.

}
});

['before', 'after'].forEach(pseudoEl => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pesudo elements are... pseudo, so they aren't children and can't have inline styles.


const files = globSync(pattern, { ignore: 'node_modules/**', posix: true });

const delay = ms => ms && new Promise(r => setTimeout(r, ms));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No longer necessary

Suggested change
const delay = ms => ms && new Promise(r => setTimeout(r, ms));

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this can mostly be turned into a web component to make it less gross (scoped styles, less window, oop etc.), but it would require a fair amount of rework that we can do later.


async function ScreenshotAndCompare(opts) {
await document.fonts.ready; // firefox fonts
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For some reason Firefox fonts go back into loading, so we need to double check they are done before the screenshot.

Copy link
Member

Choose a reason for hiding this comment

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

Weird! Hopefully this is a no-op in non-Firefox anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah it should be.

});
mocha.setup({ // eslint-disable-line no-undef

chai.Assertion.addChainableMethod('soon',
Copy link
Member

Choose a reason for hiding this comment

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

Interesting. Did they share anything in common with each other? My worry with adding this would be that it'd become a "silver bullet" for flaky tests, when in reality the problem was more related to the consumer not properly awaiting updateComplete after making an update or not awaiting an event after triggering a change.


async function ScreenshotAndCompare(opts) {
await document.fonts.ready; // firefox fonts
Copy link
Member

Choose a reason for hiding this comment

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

Weird! Hopefully this is a no-op in non-Firefox anyway.

function inlineStyles(elem) {
// headed chrome takes screenshots by first moving the element, which
// breaks the hover state. So, copy current styles inline before screenshot
if (window.d2lTest.hovering && window.chrome) {
Copy link
Member

Choose a reason for hiding this comment

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

Nit: invert this and return to reduce nesting

let count = 0;
function inlineStyles(elem) {
// headed chrome takes screenshots by first moving the element, which
// breaks the hover state. So, copy current styles inline before screenshot
Copy link
Member

Choose a reason for hiding this comment

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

Whoa, crazy that we'd need to do this. I'm sure you tried this, but instead of making all the styles inline, could we just try to re-apply the hover after Chrome moves it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, it's not just that it moves. It seems to be locking it down in some way, which makes sense, but it just loses the hover.

@bearfriend
Copy link
Contributor Author

bearfriend commented Jul 19, 2023

Since the base (#65) got reworked the conflicts are a bit much, and this is a doing lots of smaller things so I'll just close this and re-open the individual bits as their own PRs.

@bearfriend bearfriend closed this Jul 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants