...

/

Test Single-page Application Components

Test Single-page Application Components

Understand the specifics of a single-page application component and its testing, such as lifecycle hooks and event handlers.

We’ll be looking at class-based single-page application (SPA) components. Angular, React, and Vue all support class-based components.

SPA components generally expose lifecycle hooks (or methods) that can be used to do specific actions at certain times. For example, wait until the component is initialized (or mounted/displayed) before making a call to the API to fetch some data. And at the time of its destruction (or unmount), stop any further processing.

Click the following links for examples of component lifecycle hooks from the aforementioned SPA frameworks: :

‘ArticleComponent’

For this lesson, we’ll use an SPA component that displays an article, like in a blog. It loads the article at the time of its initialization. At the time of its destruction, it marks itself destroyed and doesn’t show the article.

In the code playground below, there’s an implementation of ArticleComponent and its tests. Let’s run them and see their breakdown below.

const specReporter = require('jasmine-spec-reporter').SpecReporter

module.exports = {
  srcDir: "src",
  srcFiles: [
    "**/*.?(m)js"
  ],
  specDir: "spec",
  specFiles: [
    "**/*[sS]pec.?(m)js"
  ],
  helpers: [
    "helpers/**/*.?(m)js"
  ],
  random: false,
  stopSpecOnExpectationFailure: false,
  browser: {
    name: "headlessChrome"
  },
  reporters: [new specReporter()]
}
Testing asynchronous SPA lifecycle hook methods

‘ArticleComponent’ Breakdown

Looking at the src/article.component.mjs, we see the following:

  • export class ArticleComponent {
      articleId; // or props.articleId
    
      article;
      loading;
      destroyed;
      //...
    }
    

    We start by declaring the class of the component and declaring some properties in it:

  • The articleId is the id of the article the component is to display. This is expected to be an input (or prop). That is, the component relies on it being there to do its job. Click the following links for examples of Angular Input, React props, and Vue props.

  • The article holds a reference to the article object that is fetched from the ArticleAPI.

  • The loading property lets us show and hide a loading spinner. This lets the user know something is going on in the background.

  • The destroyed property becomes true when the component is being destroyed. That serves as the signal to stop any further processing.

  • articleAPI;
    userMessenger;
    
    constructor(articleApi, userMessenger) {
      this.articleAPI = articleApi;
      this.userMessenger = userMessenger;
    }
    
    • The articleAPI is the instance that lets us call the server API endpoint to get the article or delete it.
  • The userMessenger is an instance of the UserMessenger class that shows a message to the user. It can be of the info or error category using the correspondingly named method of that class.

  • In the constructor, we populate the articleAPI and the userMessenger properties with the passed-in instances. ...

 async afterComponentInitialize() {
   this.loading = true;
   try {
     const article = await this.articleAPI.get(this.articleId);
     if(!this.destroyed) {
       this.article = article;
     }
   } catch {
     if(!this.destroyed) {