How to unit test <compose> element?

How to create a mock object in order to test the code in TestComponent? I followed this Aurelia doc aurelia.io/docs/testing/components/ But it says: ‘TypeError: Cannot read property ‘innerHTML’ of null’
This is what I have:

app.js

<template>
<compose view-model="./component/TestComponent" model.bind="TestData"></compose>
</template>

TestComponent.html

<template>
 <div class="menuItem">
    <h4>ID: ${data.menu.id}</h4>
    <div class="value">${data.menu.value}</div>
    <div class="path">${data.menu.path}</div>
 </div>
<template>

TestComponent.spec.js

import {StageComponent} from 'aurelia-testing';
import {bootstrap} from 'aurelia-bootstrapper';

describe('TestComponent', () => {
let component;

beforeEach(() => {
  component = StageComponent
    .withResources('component/TestComponent')
    .inView('<TestComponent></TestComponent>')
    .boundTo({"menu": {"id": "3", "value": "Sample", "path": "Middle"}});
});

it('should render value', done => {
  component.create(bootstrap).then(() => {
    const nameElement = document.querySelector('.value');
    expect(nameElement.innerHTML).toBe('Sample');
    done();
  }).catch(e => { console.log(e.toString()) });
});

afterEach(() => {
  component.dispose();
});
});

Mock data:

{"menu": {
  "id": "3",
  "value": "Sample",
  "path": "Middle"
}}
1 Like

AFAIK, composeable elements does not work with @bindables. You have not shared the view-model of TestComponent, but I believe there is an activate method in the view-model. If the method is there in the view-model, compose will try call that method in order to activate/initialize the component before attaching that to DOM.

When you are testing such composeable element in isolation, the activate won’t be called by default, as from view it is not being used from a compose element. Thus, while unit testing we need to explicitly call the activate hook by yourself. The .boundTo shown in your example won’t work like it works for normal custom elements. Moreover I think your .inView needs to be changed to '<test-component></test-component>'.

1 Like

The view-model is:

    export class TestComponent {
          activate(model){
            this.data = TestData;
        }
    }

Where you got “test-component” from?

1 Like

Normally, you get the model bound via <compose model.bind="model" .. in the model parameter of the activate method. Not sure what the TestData is, as you have shown in the example.

And regarding test-component, it is the convention used by Aurelia. How else are you going to use the custom element?

BTW there is another alternative as well. That is instead of unit testing your component in complete isolation, you can test it from compose instead. In that case, you need to use something like this:

...
.withResources('component/TestComponent')
.inView('<compose view-model="component/TestComponent" model.bind="TestData"></compose>')
.boundTo({TestData: {menu: {id: "3", value: "Sample", path: "Middle"}}})
...
2 Likes