[« return to the manuals](index.md)

# Introduction to LaxarJS Mocks

Before going into details, we will introduce the testing framework by showing an example and use that to describe the individual steps usually found in a widget test.
Coming from LaxarJS 1.x, the [migration guide](migration.md) may help.
If you are already familiar with the basics, you may want to browse the [API docs](../api/laxar-mocks.md) instead.


## An Example Test

The following is a simple test for a *plain* widget.
Consult your adapter's documentation to find any additional information for your integration technology.

Below the example, each of the enumerated points is described in more detail.
Note that some of the steps are optional, depending on your testing needs.

```js
// 1. Module Definition, Imports
import * as axMocks from 'laxar-mocks';

describe( 'An example-widget', () => {

   // 2. Testbed Setup, creates axMocks.widget for the widget under test
   beforeEach( axMocks.setupForWidget() );

   beforeEach( () => {
      // 3. Widget Configuration (as needed by the widget)
      axMocks.widget.configure( {
         example: {
            resource: 'exampleResource',
            action: 'exampleAction'
         }
      } );

      // 4. Optional: Configuring and/or Replacing Widget Services
      axMocks.widget.whenServicesAvailable( services => {
         services.axFlowService.constructAbsoluteUrl
            .and.callFake( target => target === 'next' ? '/step2' : '/default' );
         services.axId = suffix => `ABC-${suffix}`;
      } );
   } );

   // 5. Loading the Widget, and instantiating the controller
   beforeEach( axMocks.widget.load );

   // 6.  Optional: Simulating Startup Events
   beforeEach( axMocks.triggerStartupEvents );

   // 7. Optional: Rendering the Widget DOM
   let widgetDom;
   beforeEach( () => { widgetDom = axMocks.widget.render(); } );

   // 8. Tests
   it( 'subscribes to didReplace events for the example resource', () => {
      expect( axMocks.widget.axEventBus.subscribe )
         .toHaveBeenCalledWith( 'didReplace.exampleResource', jasmine.any( Function ) );
   } );

   it( 'uses the flow service to generate a "next" link', () => {
      expect( axMocks.widget.axFlowService.constructAbsoluteUrl )
         .toHaveBeenCalledWith( 'next', {} );
   } );

   // 9. Optional: DOM-Tests
   it( 'renders a link refering to the "next" target', () => {
      expect( widgetDom.querySelector( 'a' ).href ).toEqual( '/step2' );
   } );

   it( 'renders an input with matching label', () => {
      expect( widgetDom.querySelector( 'input' ).id ).toEqual( 'ABC-myInput' );
      expect( widgetDom.querySelector( 'label' ).for ).toEqual( 'ABC-myInput' );
   } );

   // 10. Testbed Tear-Down
   afterEach( axMocks.tearDown );

} );
```

The individual steps are explained below in more detail.


## 1. Module Definition, Imports

For simplicity, this test is written as an ES2015 module, but other styles (CommonJS, AMD) should work just fine.
The LaxarJS spec-loader takes care of loading the widget itself and its dependencies, such as controls.


## 2. Testbed Setup

LaxarJS mocks has already been provisioned with information on the widget's assets, so no arguments need to be passed here
To spare the user from handling of asynchronous tasks in the *Jasmine* environment, `axMocks.setupForWidget()` returns an asynchronous function suitable for use with `beforeEach`, so the parentheses *must not* be removed.


## 3. Widget Configuration

Next, we configure the features of the widget instance.
The same information that you would configure as `features` within a page when developing an application can be passed to the method `axMocks.widget.configure`.
For convenience it's also possible to use an *attribute path* together with a single value as arguments.
This is especially useful if the widget gets pre-configured in an outer `describe` block and is adjusted deeper in a nested structure.

This means that alternatively we could have written:

```js
beforeEach( () => {
   axMocks.widget.configure( 'example.resource', 'exampleResource' );
   axMocks.widget.configure( 'example.action', 'exampleAction' );
} );
```


## 4. *Optional:* Configuring and/or Replacing Widget Services

Next, some of the LaxarJS widget services are modified for the test.
Because LaxarJS Mocks automatically injects service mocks with appropriate Jasmine spies for all widget services provided by LaxarJS, you will often be able to skip this step.
In this case, we'd like to test the URLs generated by the widget, so we modify the `axFlowService` mock to generate URLs of our choosing, that we can check against our expectations below.

*Note* that this callback has to complete *synchronously*.
You cannot complete the surrounding `beforeEach` block by calling its `done` parameter from this callback because LaxarJS Mocks *only stores* the callback for now, and will only run it when `axMocks.widget.load` is called.


## 5. Loading the Widget

Here we tell LaxarJS to actually instantiate the widget controller.
Since the API of the LaxarJS widget loader is asynchronous, the `axMocks.widget.load` method is asynchronous as well and thus expects a *Jasmine* `done` callback.
Again, to keep tests simple, `load` doesn't need to be called directly, but can be passed directly to `beforeEach`.
Make sure to load the widget only *after* all configuration and service mocks have been prepared, because afterwards calls to `axMocks.widget.configure` and `axMocks.widget.whenServicesAvailable` will have no effect.


## 6. *Optional:* Simulating Startup Events

When a page is loaded within a *LaxarJS* application, the runtime publishes several *lifecycle events*.
Many widgets don't actually care for these events and only subscribe to custom events such as *didReplace* or *takeActionRequest*.
Other widgets may depend on [core events](http://laxarjs.org/docs/laxar-latest/manuals/events/#pattern-reference) like *didChangeLocale* or *didNavigate* with certain parameters.

For testing a widget's response to core events without duplicating too much of the associated logic within every test, the function `axMocks.triggerStartupEvents` publishes all events that the runtime would publish, in the same order.

The method also allows to modify these events or skip some of them completely.
For further information on event configuration have a look at the [API docs](../api/laxar-mocks.md#triggerStartupEvents).


## 7. *Optional:* Rendering the Widget DOM

Naturally this step does not apply to activities, since they do not influence the DOM and in particular have no visual representation.
Calling `axMocks.widget.render()` for activities isn't harmful, but simply has no effect.

For widgets, their template is processed by the underlying technology adapter, wrapped in a `DIV` element and the resulting DOM node returned.
This is not different from the rendering process in a regular application.
Instead of appending the DOM to a widget area, it is appended to the body element of the test.
It is removed again before the next test run would render its DOM or when calling `axMocks.tearDown`.


## 8. Tests

Now you're set up to write your actual tests.
At this point the widget controller is instantiated, the (optional) DOM fragment has been rendered and all relevant runtime events were published.

Probably you want to group your tests into functional use cases via *Jasmine* `describe` functions.
In this case it is sometimes a good thing to postpone the calls to `axMocks.widget.load`, `axMocks.widget.render` and `axMocks.triggerStartupEvents`.
This allows you to structure the test in isolated `describe` blocks, to adjust configuration and service mocks for each block as needed and only afterwards to actually instantiate the widget and fire up your tests.


## 9. *Optional:* DOM-Tests

Using the DOM rendered in step 8, you can now run DOM-tests to check your widget's HTML representation.
This is only relevant for widgets that you would like to write DOM-tests for.
We recommend using the standard DOM APIs for this, but nothing prevents you from using a helper library such as jQuery.


## 10. Testbed Tear-Down

Every widget test should call `axMocks.tearDown` in a *Jasmine* `afterEach` block or simply pass it to `afterEach` as a callback.
This ensures that after each test run the DOM is cleaned up and the widget with all its dependencies is destroyed.
If this is omitted, it cannot be guaranteed previous test runs do not influence the current test run.

Note that you should *avoid changing global state* in your widget module, as LaxarJS Mocks cannot detect nor revert those changes during tear-down.
However, side-effecting widget services such as `axStorage` are provided as mocks and are automatically reset between test runs.


## More Information

For more in-depth documentation, refer to the [API docs](../api/laxar-mocks.md).
