328 Testing JavaScript with Jasmine [1.5d]

Updated . Posted . Visible to the public.

Jasmine Show archive.org snapshot is a great tool to unit test your JavaScript components without writing an expensive end-to-end test for every little thing.

Important

Work on this lesson in builder mode.

Jasmine is a purely client-side tool. It cannot ask Rails to render a view or access the database. Any HTTP calls must be mocked.

Learning goals

  • You can explain what JavaScript unit tests cover that end-to-end tests shouldn't: a component's details and edge cases, without a server or a database.
  • You can write a unit spec for a component: create the DOM it needs, instantiate it, dispatch events, assert with matchers, and clean up afterwards.
  • You can control time in a spec instead of waiting, and test asynchronous code with async/await.
  • You can isolate a component from the network by replacing fetch with a spy that returns fake responses, and assert which requests were made.
  • You can build a component with a small, testable API (e.g. a custom element or an Unpoly compiler) and cover every edge case with specs.
  • You know that Jasmine is our default runner and how it relates to the alternatives used elsewhere.

What we test with Jasmine

Just as unit tests are a direct way to closely look at your classes, Jasmine is a very direct way to look at your JavaScript components.

For example, when you want to test that a date picker opens a calendar sheet on click, Jasmine lets you quickly instantiate the date picker and emit a click event. You do not need to login with a user, or find a screen that has a date picker.

Like with the unit tests, we would still add an E2E test for the happy path, just to ensure successful integration. However, all the details and edge cases of a component would be tested in Jasmine only.

Resources

Read what's new to you, skim what's familiar, skip what you already master. Stop when you can meet the learning goals.

Your agent can also generate an overview, a tutorial or an explanation for anything here, tailored to what you already know. Just ask.

Jasmine

Our Jasmine cards

Exercises

Integrate Jasmine

Integrate Jasmine into your MovieDB app and perform the following exercises.

Tip

If you've forked your MovieDB in the beginning, Jasmine is already integrated in your code base.

Movie counter

In Working with the DOM you implemented a button to count the number of movies in a list.

Write a Jasmine spec for that button.

Tip

  • Create the required DOM directly from your Jasmine spec. You cannot ask Rails to render a view.
  • You can use Element#dispatchEvent() Show archive.org snapshot to emit events on a DOM element programmatically. For click events there is also the shortcut element.click().

Loading elements after a delay

Use custom elements or Unpoly compilers to build a <delayed-load> element. It should afford an API like this:

<delayed-load id="news" url="/foo" delay="5000">
  This will load soon...
</delayed-load>

It should work like this:

  • After the given delay (5 seconds in the example), the component makes a request to /foo.
  • The server is expected to respond with HTML containing an element with the same [id] (news in the example).
  • The component parses the server response (using DOMParser) and extracts the element with the matching [id] attribute.
  • The component replaces the <delayed-load> component with the matching element from the server.
  • If the server takes more than 5 seconds to respond, no additional request should be made while another request is already pending. Once the response is received, the component should wait a full 5 seconds before making a request.

There are some edge cases to consider:

  • When the server responds with a non-2xx status code, the inner text of <delayed-load> will be replaced by a message like Error 404 while loading.
  • When the server does not respond with HTML containing an element with matching [id], the inner text of <delayed-load> will be replaced by a message like Element not found.
  • When the element is removed from the DOM before the delay, no request is made.

Write Jasmine specs for every case.

Tip

  • Don't actually wait for time to pass in your test. Instead, mock the time using jasmine.clock.
  • Your specs should test which HTTP requests are sent by the component. Use Jasmine spies to mock the window.fetch() method, inspect its calls and return a promise for a Response Show archive.org snapshot .

Alternatives

Jasmine is our default, and it is already set up in MovieDB. Most of the JavaScript world uses Vitest Show archive.org snapshot or Jest instead. The shape of a spec is the same β€” describe, it, expect β€” and the concepts (spies, fake timers, DOM setup) transfer; the runner, configuration and mocking APIs differ. If you join a project with Vitest, you'll be productive within an hour.

Profile picture of Henning Koch
Henning Koch
Last edit
Henning Koch
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra Curriculum (2021-12-23 16:16)