-
-
Notifications
You must be signed in to change notification settings - Fork 386
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
Start for automated tests using pixelmatch #175
base: master
Are you sure you want to change the base?
Conversation
The labels uPlot draws on the canvas seem to look different based on operating system and installed fonts. This change uses Docker to get reliable results independent on the host the tests are executed on.
hey @frigus02 thanks a lot for starting this! i'll make some general comments for now before i dive into the code.
yes, i think this can be expanded further now to basically take a JSON snapshot of the uplot objects (excluding some stuff like Path2D cache objects) and deep-diff the expected and actual state, too.
i'm thinking instead of stringing together a bunch of heavy js libs (jsdom, canvas, canvas-5-polyfill), maybe running this via Puppeteer as one easily-updated dependency could make debugging easier, since we can opt in/out of headless and play with devtools in an actual browser instance. https://dev.to/benjaminmock/how-to-take-a-screenshot-of-a-page-with-javascript-1e7c
honestly, this is a pretty crappy feedback loop. i don't want to first make commits, push, and then have to rely on an external service to run and github UI to ensure i haven't made errors. i want to make sure there are no errors before i even make a commit, so the tests must be runnable locally. i would prefer to create some |
I considered Puppeteer as well and thought not starting a full browser would make tests faster. There are however advantages with running in a real browser, so I understand what you're saying.
Running this on push is obviously optional.
That's a nice idea. I does mean that the first test run would be slower because it has to build up the cache. But it doesn't require the PNGs to be committed. Overall it seems like this is not quite what you're looking for, which is completely understandable. I'll see if I can fine the muse to implement your suggested changes. If not, your ideas and this PR can serve as a starting point for the next person 🙂. |
another wild idea is to ditch the dom and canvas entirely and replace them with thin mocks which act as simple command buffers. then compare whats in those buffers to known references. if a mismatch happens, then the good and bad buffers can be re-played in a real browser for comparison. this would take some effort to set up but would be platform agnostic, zero dependency and run very fast, plus can be committed into the repo. i have never worked with Proxies, but mocking/command buffers feels like a great use case to make a general testing approch like this work. i haven't seen a testing framework use this strategy. could be a good tangent project!
i never fully understood why contributers pick up and work on open issues without attempting to ping me beforehand to discuss the impl specifics before doing all the work, hehe :). but as long as you got value out of it, that's great.
yeah, for sure. as you can tell i'm still tossing around different ideas, as well. i'll leace this pr open for now. |
Using proxies (or some other way of mocking DOM and canvas) sounds like an interesting idea. Yeah, I did this mainly for myself to be honest. If this would have fit your needs, it would have been a nice opportunity to contribute as well. |
i currently use https://github.com/developit/undom to test https://github.com/domvm/domvm with good success, and domvm needs a lot more dom than uPlot. so this is another option, but uPlot does not need to read back or traverse the dom, so i think something like a command buffer would work, too, for tests. i very well might cherry pick some of this PR, lots of good stuff in here :) i'll likely use this as a springboard to get into basic CI. |
thats exactly what jest-canvas-mock does : ) i started adding this to uPlot, but i'm stuck at ....
obvious problem: only a small part is rendered to canvas possible reasons:
@leeoniya you're the canvas expert here, do you have an idea .. ? |
thanks for trying this out, @milahu -- only the brave venture into this issue! here's another similar idea that might work better (canvas -> svg pathstring api facade): grafana/grafana#29552. in the end, though, i suspect we'll end up with using reference images, testing with a real browser (playwright or puppeteer) + pixelmatch due to incomplete or broken mocks :(. i think the tests should still run quickly as long as we don't have to spawn a browser instance for each test. we just need to make sure we can cleanup up after each run and re-use the existing process for the next test. i don't have too much time to look into this now & debug, unfortunately, but if you get something working i'll certainly take a look. |
naah .. my canvas solution is almost ready : ) i had an error in my "glue code" to import the canvas events from
my code was too simple/naive, so i had these mysterious silent fails,
we can still have that, but puppeteer / playwright is huuge overkill to only generate images from canvas, we have node-canvas |
I want to say a big thank you for building μPlot. It's working really nice for me.
In #72 you mentioned you're looking to add some (non-granular) tests. I wanted to play with pixel based snapshot tests for a while now and took this as an opportunity.
This PR uses jsdom to render all the existing demos and then pixelmatch to compare them to a stored snapshot. Everything is packaged in a GitHub workflow to run on push. If any snapshot doesn't match, the build fails and uploads diffs for all mismatched snapshots as an artifact to the build.
See recent push for an example: https://github.com/frigus02/uPlot/actions/runs/74668141
The whole thing runs in Docker to make font rendering consistent. I fond that otherwise labels are rendered slightly differently based on operating system and installed fonts.
npm test
runs tests and stores diffsnpm run test:update
runs tests and updates snapshotsCurrent status: some demos dont't work because they're generating random data. However this satisfied my desire to play, so I decided to stop here and see what you think 🙂.
Is this the direction you want tests to go? Did you expect something very different?
If this goes in the right direction, I'm happy to either finish it or for you to take over if you prefer.