✨ Accept additional snapshot execute options for various states #514
✨ Accept additional snapshot execute options for various states #514
Conversation
After navigation, before and after resizing, and before the snapshot is taken
|
Possible to get a release with this? |
|
We were going to release this today, but we decided to hold off until Monday since some other stuff will be going out with it and we want to be available if an unforeseen issue comes up. |
|
Giving this a shot and getting the following error: Not sure I updated the - name: About
url: http://localhost:3000/about
waitForTimeout: 100
execute:
afterNavigation: 'function sleep(ms) {return new Promise(resolve => setTimeout(resolve, ms));} window.scrollTo({ top: document.body.scrollHeight, behavior: "smooth" }); await sleep(1000); window.scrollTo(0,0); await sleep(100);'
widths:
- 375 |
|
Looks like a bug 🙃 Will fix and release a new version shortly 👍 |
|
Documentation challenge, maybe, but: Wouldn't the |
|
p.s. The reason why this is important for me is because unfortunately I have several places on the 30-40 or so pages that I'm testing which need to re-run JavaScript in order to properly render for the current breakpoint. However, architecturally, it looks like Percy:
This is great, but one minor problem with this setup is that it results in me needing to manually define repetitive/duplicate entries over and over again when I could just have a single - name: "library-quotes-mobile"
url: "http://example.com/content-section-library/quotes/"
widths: [375] # IMPORTANT: Separate captures are necessary to validate desktop/mobile due to the JS required to render each layout separately.
- name: "library-quotes-desktop"
url: "http://example.com/content-section-library/quotes/"
widths: [1280] # See important note above.But it would be simpler (and far easier to maintain) if I could just do the following: - name: "library-quotes"
url: "http://example.com/content-section-library/quotes/"
execute:
afterResize: "Example.Layout.triggerResize()"Note that now in this case I'm not repeating my (Sorry for all the notifications 😬) |
|
I'm not sure I understand the need to break up the entries. This is what we do: - name: "library-quotes"
url: "http://example.com/content-section-library/quotes/"
execute:
afterNavigation: |
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
let sections = Math.ceil(document.body.scrollHeight/window.innerHeight);
for(var i = 1; i <=sections; i++){
window.scrollTo({top: (document.body.scrollHeight/sections)*i, behavior: "smooth"});
await sleep(500);
// in case the height changes
sections = Math.ceil(document.body.scrollHeight/window.innerHeight);
}
window.scrollTo(0, 0);
await sleep(100);
widths:
- 375
- 768
- 1200
- 1500 |
|
I have components already in the page (not React, but jQuery, it’s an old site…) that have corresponding JavaScript code that is responsible for helping to configure/layout those components depending on the current page width (breakpoint). Re-read what I said above (just so you’re familiar with my concern about the problem domain). I’m new to this, but basically, Percy has two contexts: 1.) The CLI that launches a custom Chromium instance that scrapes HTML/JavaScript/CSS/etc and 2.) The cloud-based rendering browsers. My issue is that the jQuery component must run JavaScript in order to reposition, rearrange, move (extract, append, relocate, etc) various DOM elements when it notices a resize event in the browser. From what I understand of how Percy’s architecture works, this can only be done (reliably) in context 1, in the CLI running the local Chromium browser doing the scraping. That’s why I asked the question above. Because |
|
Ah ok, I think I see what you are saying. You need to run the JS in the rendering context (ie for each of the bowsers + widths being tested on) since you actually want to change the DOM as width changes (rather than relying on CSS, etc). Yes, that I don't know how / if Percy handles. I would think if they don't currently handle, and this is a common use case, then some sort of syntactic sugar could be introduced to get the same effect that you are looking for where you have to split up the entries in the yaml file. |
|
Right, so that’s fine. I thankfully have ways around it (just a duplicate entry). Not a huge deal. And would be cool to have a more succinct syntax. But still, it makes me curious… if configs like EDIT: Or it could be that it does run in the remote Percy browser context, it just doesn’t have access to the app’s bundled JS, it’s just raw JS that runs in situ (even if it modifies DOM) and can only run in isolation before/after each resize. |
|
repasting my yaml as I left off a key: - name: "library-quotes"
url: "http://example.com/content-section-library/quotes/"
execute:
afterNavigation: |
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
let sections = Math.ceil(document.body.scrollHeight/window.innerHeight);
for(var i = 1; i <=sections; i++){
window.scrollTo({top: (document.body.scrollHeight/sections)*i, behavior: "smooth"});
await sleep(500);
// in case the height changes
sections = Math.ceil(document.body.scrollHeight/window.innerHeight);
}
window.scrollTo(0, 0);
await sleep(100);
afterResize: |
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
let sections = Math.ceil(document.body.scrollHeight/window.innerHeight);
for(var i = 1; i <=sections; i++){
window.scrollTo({top: (document.body.scrollHeight/sections)*i, behavior: "smooth"});
await sleep(500);
// in case the height changes
sections = Math.ceil(document.body.scrollHeight/window.innerHeight);
}
window.scrollTo(0, 0);
await sleep(100);
widths:
- 375
- 768
- 1200
- 1500 |
|
And this only runs once at snapshot time, or does it run for each width (and thus behind the scenes technically sending multiple DOM snapshots bundled into the same alias, just loaded under each width)? |
|
Also, just had a chance to try this out @wwilsman and I think there's a bug where This works: - name: "name"
url: http://localhost:3000/about
waitForSelector: ".vqa-ready"
execute:
afterNavigation: "$('body').addClass('vqa-ready');"But this does not: - name: "name"
url: http://localhost:3000/about
additionalSnapshots:
- suffix: "-toggled"
waitForSelector: ".vqa-ready"
execute:
afterNavigation: "$('body').addClass('vqa-ready');" |
|
Hey @patricknelson! I'll try to clear up how the snapshot command executes those functions for you!
For additional snapshots, the page has already been navigated to and responsive assets have already been captured. As such, the navigation and resize functions are not accepted under additional snapshots. In fact, the only accepted function for Also to note, none of these execute options are sent to Percy's renderers. These functions are meant to aid in asset discovery. Once the DOM is captured, it and any captured assets are sent with basic snapshot options: https://github.com/percy/cli/blob/v1.0.0-beta.76/packages/client/src/client.js#L306-L309 Also also, you can utilize YAML anchors and references to avoid duplication. You'll just have to adjust your yaml to have a top-level With all that said, the snapshot command is not meant to replace a complete test suite. So if you have a complex site or app, I would highly recommend to set up a testing framework and integrate a Percy SDK with that (Puppeteer, Playwright, or Cypress are quick and easy to set up). Here are our currently supported SDKs: https://docs.percy.io/docs/sdks#end-to-end-testing-frameworks |
|
Thank you @wwilsman! This breakdown is extremely helpful. The very simplicity & approachability of the YAML config is precisely what makes it so appealing for our large site. It's just those darned edge cases that throw a wrench into things, requiring a deeper nuts-and-bolts understanding of the complete YAML config schema as well as what each config param actually does. So, thank you for this explanation. What is the purpose of - name: "test"
url: "http://example.com/test/"
additionalSnapshots:
- suffix: "-example"
execute: "$('body').addClass('vqa-ready')"
waitForSelector: ".vqa-ready" |
|
The We definitely want to and need to document this snapshot command more. For example, you can actually wait on things right inside # The `waitFor` helper is available for all `execute` functions.
# It resolves when the callback returns a truthy value, or rejects after the timeout
execute: |
await waitFor(() => $('body').hasClass('vqa-ready'), 1000);
// ... do other stuff after waitingHere is the function signature for that execute helper, which also accepts a couple other options as the second argument: https://github.com/percy/cli/blob/v1.0.0-beta.76/packages/core/src/utils.js#L99 |
|
On that note an example of how to use waitFor to sleep would be cool. We have your own sleep implementation that we use between scrolls. |
|
Hmm, interesting.. ok, got it! Basically: If you ever need to wait for a selector to be present that would be caused by That said: Are those core library utilities you linked to above (including |
|
@patricknelson you can count on @cancan101 the // wait until window has scrolled down to the section
// note that without a timeout, it will continue to poll until true
await waitFor(() => window.scrollY === sectionTop) |
|
I actually do want to wait for a specific amount of time to allow lazy loaded images, etc to load. I would also be worried with using the example code as you presented in case the height of the page changes as it scroll leading the equality comparison never evaluating as true. Anyway, I would put in a vote to inject a time delay function to the namespace. ;-) |
|
@wwilsman your comments above are so helpful, it'd be awesome if the public facing site also had these things documented as well (both the technical breakdown you made here as well as the official support for |
Bumps [tsd](https://github.com/SamVerschueren/tsd) from 0.20.0 to 0.21.0. - [Release notes](https://github.com/SamVerschueren/tsd/releases) - [Commits](tsdjs/tsd@v0.20.0...v0.21.0) --- updated-dependencies: - dependency-name: tsd dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

What is this?
This PR adds the ability to specify additional execute options to run scripts at specific states during the snapshot process. By default, the original
executefunction would only be evaluated right before a snapshot is taken. Now, there are additional options forafterNavigation,beforeResize,afterResize, andbeforeSnapshot. Ifexecuteis provided as a function without these additional options, it is treated as a shorthand forexecute.beforeSnapshot.Thanks to @cancan101 for the idea! With these new options, it makes it easier for people to handle lazy-loaded images before the page gets resized. Closes #513