Unit Testing

Unit tests are written with the Jasmine testing framework and run via Karma to verify JavaScript functionality within Web components is working as expected.

Unit Tests

Web components use a test-driven development (TDD) approach to component building. It has three primary steps:

  1. Write a failing test that describes some behavior of the component
  2. Write the component code required to make that test pass
  3. Refactor component code as needed ensuring the test still passes.

This approach is sometimes referred to as “Red, Green, Refactor”.

Creating the Component Test File

If creating a new Web component with the gulp generate:new-mdswc-component task, you should have [component-name].test.js in the /test/unit/components folder. The auto-generated file contains a few suggested test specifications to help you start off.

Adding the Component Test File to the Test Suite

Before running the suite of unit tests, the component test file must be imported into the unit test entry file located at /library/test/unit/mds_test_entry.js and registered on the window object

import componentName from '../../components/component_name/component_name';

window.componentName = componentName;

Running Tests

From the /library directory in your local checkout of the MDS repository, run npm test to run the entire test suite.

Focusing Tests

Jasmine offers the ability to focus on a specific test or describe block to speed up the time it takes for tests to run. The unit testing template already has the outer describe block focused using the fdescribe syntax. For examples, this code would run the tests specific to MdsInput only:

fdescribe('MdsInput', () => {
    let input;
    // Test instance methods
    ...
});

Removing the f allows the full library tests suite to run:

describe('MdsInput', () => {
    let input;
    // Test instance methods
    ...
});

Component API Test

Begin with a unit test that verifies all the default props of your component’s API, ensuring that future changes to the component’s API require updating the test to make sure it still passes.

During the TDD Component Build phase the appearance of the component should not be considered. The purpose of these tests is to exercise the JavaScript functionality of the component. The most important aspects to test are:

  • Props API, as a whole object, not individual props
  • Component-specific prop validation and error messages
  • Custom event triggering
  • Prop state changes based on method calls
  • Template rendering changes based on prop configurations

Component authors should not over test components. A large portion of component functionality is managed by the MDSWCBase and should not be tested by each individual component unless a bug or component-specific issue is discovered. In general, individual component unit tests should not test the following:

  • Prop override precedence
  • MWC Logger bindings
  • MWC Labeler bindings
  • Slot rendering performance
  • Basic prop type validation
  • Sub-components (e.g. testing functionality of Icon in a Button)

Test Coverage

You can monitor how much of your source code is currently covered by tests by reviewing the HTML report located at: /library/test/unit/reports/coverage/report-html/index.html.

View this report in your browser and drill down into the component you’re working on to see current test coverage. Note: This report isn’t part of the webroot/localhost, so it needs to be opened from the filesystem.

Test Coverage Target

You should attain 100% test coverage with your unit tests. If there is code in your component that isn’t being tested, remove it or write a test for it.

Exceptions to 100% test coverage include situations where a test is intermittently failing due to issues with the testing framework. Examples include:

  • Binding to CSS animation events like animationend - in early testing this has proved to be an unreliable aspect to test in Karma

In these cases, adapt the source code so you can test everything except the part causing the intermittent failure. In the screenshot below, the bindDomRemovalAfterDismissal method and the removeFromDom method are both covered by tests, only the invocation of the removeFromDom method is left out of the tests due to the unreliability of the animationend event.

bindDomRemovalAfterDismissal method and the removeFromDom method are both covered by tests, only the invocation of the removeFromDom method is left out of the tests due to the unreliability of the animationend event.

Reproducing Bugs

If a bug is found within a component, create a new test that attempts to recreate the scenario in which the bug occurred. Once you recreate the bug, fix the source code to make the test pass.

Jasmine Tips

  • Use async if you require await for a component to be rendered first. Refer to test template file.
  • Use fit to focus on one specific test for debugging.
  • Use xit to exclude a test or mark a test as pending.
  • Refer to the Jasmine Doc Site for more documentation.
  • Change karma.conf.js settings to enable console.logging and debugging information in the console when running tests. The following settings will log both Karma debugging information and browser console logs to the console:
    • logLevel: config.LOG_DEBUG,
    • browserConsoleLogOptions: { level: 'debug' },
©2019 Morningstar, Inc. All rights reserved. Terms of Use