agilgur5 / react-signature-canvas

A React wrapper component around signature_pad (in < 150 LoC). Unopinionated and heavily updated fork of react-signature-pad
https://agilgur5.github.io/react-signature-canvas/
Other
542 stars 119 forks source link

Add tests #33

Closed agilgur5 closed 5 years ago

agilgur5 commented 5 years ago

Place for notes as I'm implementing tests on the tests branch.

Some initial notes:

agilgur5 commented 5 years ago
agilgur5 commented 5 years ago

First big problem I ran into when creating the test harness was babel support. While babel support is built into jest with babel-jest, it's currently defaulted to Babel 7 and we're still on Babel 6. I don't quite want to upgrade the build toolchain yet (tests would be useful to ensure the output stays the same and that's a big project on it's own, don't want to mix that with tests), so I used the workaround available in https://jestjs.io/docs/en/getting-started#using-babel to install babel-jest@23 to work with Babel 6.

...But then I ran into a bunch of issues with configuration:


P.S. It turns out upgrading to Babel 7 in this specific repo shouldn't be too difficult as I think the only proposal we're using is class-properties. Per the upgrade guide for stage-2 would just add "plugins": [ ["@babel/plugin-proposal-class-properties", { "loose": true }] ] and remove stage-2 from "presets". Should replace react with @babel/preset-react too.

babel-preset-es2015 isn't quite as clear and took a bit of research to grok, but per the @babel/preset-env targets config docs, should just be able to use the default ({}) to transpile all ES2015+ code, which should be an equivalent transform to preset-es2015. If any polyfills are used in this library (I don't think so), "useBuiltIns": "usage" would be optimal so that they're re-used and not duplicated amongst users other polyfills.

agilgur5 commented 5 years ago

Oh yea, so I decided to use jest instead of ava because I figured it would be easier to configure due to all the built-in-ness of it. I also found a way to import jest in tests so it wouldn't rely as heavily on globals (but this required configuration and still pollutes global scope as the PR or similar has yet to be accepted, so still not quite as ideal as ava).

Now, of course, looking at all the above stuff, there still ended up being quite a bit to configure for the specific environment here, so that kinda sucked 😕 . The main differences seem to be that I don't need to install/configure something like nyc for code coverage as it's built into jest (and maybe will have less issues than nyc? 🤞) and don't need to configure jsdom either. Also, ava seems to only be able to be configured via package.json and doesn't support configuration through a separate file (which I strongly prefer), whereas jest has jest.config.js.

jest of course also has various expect matchers out-of-the-box (though I currently don't like the flexibility this feature entails) and also supports mocking / spying out-of-the-box too (which, while should be minimized, is indeed useful).

agilgur5 commented 5 years ago

And of course, just as I got the test harness to finally work, it bugged out on canvas support with the infamous TypeError: Cannot set property 'fillStyle' of null. I initially thought it would be automatically fixed if I upgraded to jest-environment-jsdom-fifteen, but that actually didn't solve anything. jsdom v13+ only supports canvas v2+, so I tried installing canvas-prebuilt@2 but that didn't work. Not sure if that's because prebuilt@2 is still in alpha (didn't try regular canvas@2) or if there might be a bug in jest-environment-jsdom-fifteen. Anyway, I downgraded back to the included version of jsdom (v11) in jest and then just installed canvas-prebuilt@1 and it was fixed and my simple mount test finally worked, phew!

We'll see if I might need some later versions of canvas to support all the features, but for now it works, so I'll commit and push a tests branch before going to bed. This took a lot more time than I thought (and I thought it would take a decent amount of time!), so I guess I won't be getting to actual adding any real testing today 😕😞.


Oh also worth to note is that jest is running mad slow right now, 6+ seconds for a single test that just mounts the component 😮 ... Not sure if this is because of jsdom or canvas or because of old versions of both or babel-jest or what, but it almost makes me want to try setting up ava as well just to see if it runs faster 😕 It seems like jest is spending most of its time in init phases and not in actually running the tests, but I'm not sure what that means.

agilgur5 commented 5 years ago

So canvas-prebuilt@2 actually isn't supported by jsdom v13+ and apparently canvas@2 includes a pre-built version, so canvas-prebuilt is only needed when @1 compatibility is needed.

I was getting some errors with dataURL fixtures when I realized the above^. But seems like those error isn't because of the canvas version as far as I can tell. toDataURL in the browser and toDataURL in node-canvas tests return two different things after the same fromData call, so I guess the implementations are just slightly different? I didn't expect dataURLs to be super accurate anyway, which is why I started with pointGroups/fromData first, but didn't think they'd be different either 😖

I also had some trouble with trimming the canvas, getting IndexSizeError: The source width is 0, but that turned out to be because I didn't give the SignatureCanvas element a width or height (edit: forgot I don't have any wrapper CSS in tests for percentage size). The lack of width and height was also why I was getting a dataURL of data:image/png;base64, with nothing else -- once I changed that the dataURLs actually existed, but still weren't the same.


wrapper methods and get methods are all tested now with 80%+ code coverage. Just have left:

agilgur5 commented 5 years ago

Got to 100% line/statement coverage last night, some notes:

Also changed some code style things:

agilgur5 commented 5 years ago

Found another weird issue that I figured out which was whether Enzyme's setProps is async or sync. The docs have a callback arg that make it seem async (like React's setState), but I accidentally wrote it both as async and sync in the code in different places... and it worked in both 😮 😖 .

The callback was indeed added because it was (sometimes?) working async per this issue. But the currently last comment on that issue says that it was updated to work synchronously in v3.4.3 for ease of testing. But v3.4.3 changelog doesn't explicitly say that...

Real confusing, but I just rewrote my code to use it sync everywhere then as it's more readable and works fine that way 🤷‍♂

agilgur5 commented 5 years ago

Oh and forgot to mention that I looked into Code Coverage reporting providers and set-up CodeCov as it seemed to very popular and easy (and no need for tokens for public repos w/ public CI) with a one-line bash uploader.

Can view the reporting here: https://codecov.io/gh/agilgur5/react-signature-canvas/ There's also a badge on the tests branch (though it is set to only check master, so is reporting as "unknown" right now as it hasn't landed in master)