Jordan Hawker

ember-sinon-qunit v4: Consolidation & Simplification September 06, 2019

If you’re an Ember developer, it’s likely that you use QUnit to test your projects. If you also SinonJS to create spies/stubs for mocking out methods in your tests, this post is for you. As many people who’ve used Sinon discovered over the years, one of the risks of a test mocking strategy is failing to clean up after yourself. This can cause mocks to leak between tests, creating failures that are difficult to debug.

I created ember-sinon-qunit back in 2015 to give developers an easy way to create and cleanup mocks by injecting Sinon’s “sandbox” concept into the QUnit test() method. Two years later, Steve Calvert released ember-sinon-sandbox, providing an approach to this problem that incorporated the new hooks-style testing in ember-qunit. Earlier this year, he also released ember-sinon-sinoff as a continued evolution of that pattern. Let me show you a few examples for comparison:

image

The old pattern used by ember-sinon-qunit (shown above) required setup for every test and confusingly replace ember-qunit’s test function with its own wrapper. ember-sinon-sandbox improved on this by replacing the test wrapper with proper QUnit hooks:

image

This eliminated the test wrapper entirely and adopted the now-familiar hooks testing pattern. The result felt a lot more ergonomic and less confusing for developers. The same pattern existed for ember-sinon-sinoff as well:

image

You may have noticed a common problematic thread in each of these approaches, however. First of all, you have to do this in every test module, which means that developers may see you using Sinon in one test, add it to the new feature they’re developing, and forget to import the extra code necessary for the “automatic” cleanup to take place. While the one-time setup introduced in Steve’s addons provided a better alternative to solve this problem, a second issue existed. By proxying Sinon functionality into the test context via this, these addons were now responsible for maintaining the full surface area of Sinon as it continued to evolve over the years. This became very apparent when several issues were filed to add fake timers and other features to ember-sinon-qunit, all of which were perfectly reasonable requests.

This spring, we decided that this problem needed a single, unified solution that maximized the developer experience and worked with any style of Ember testing. After a lot of discussion on how to solve all of these problems, I’m proud to announce the v4 release of ember-sinon-qunit! We’ve completely reworked this addon from the ground up, deprecating the old approach as well as both of the other addons in favor of what we believe to be the most developer-friendly approach. Developers will now be able to hook up our Sinon integration once (in test-helper.js) for their entire project and never have to remember cleanup again!

ember-sinon-qunit’s one-time setup is adapted from the “Global” approaches Steve introduced in his addons, so those users may find this pattern familiar. However, once you’ve done this, any test can use the imported sinon object directly without relying on anything being injected into the test context! Take a look:

image

Once you’ve executed the setupSinon method, you never have to think about cleanup again! No matter how many test modules you add to the project, developers won’t have to worry about accidentally forgetting to clean up their spies and other mocks. The tests themselves become a lot cleaner as a result.

image

By eliminating the injected Sinon methods (or sandbox object), we’ve altogether removed the need to maintain a proxy for that library’s API. Developers are now free to use Sinon the way they would in any non-Ember project; by simply importing the sinon object into their tests and using any feature they need! You can see all of the above examples together in this gist.

Whether you’re an existing user of ember-sinon-qunit, ember-sinon-sandbox, ember-sinon-sinoff, or have simply been using Sinon by itself, we’ve got a migration path ready for you. Check out our new and improved README to learn how you can adopt this new pattern today. While the old patterns in ember-sinon-qunit were deprecated, they are still supported for backwards compatibility until the next major version, allowing you to adopt our new approach today while removing the old test wrappers over time. We also have an open issue to create a codemod for vanilla Sinon users trying to migrate from the old createSandbox method.

Developers shouldn’t have to think about whether they’re accidentally introducing state leakage between tests; the tools should just protect them by default. Steve and I hope you find this new approach easier to use than ever, so go check out the brand new ember-sinon-qunit today!