How to setup injected interpolation for karma?


#1

I’m currently taking the plunge into upgrading to the latest webpack and karma versions, basing my changes on the generated skeleton from aurelia-cli. So far, things have gone well, except for when I’m checking the “innerText” of an element that uses string interpolation from an injected class (evaluates to empty).

Has anyone else run into this? I’m able to reproduce it in the aurelia-cli skeleton. This did not used to be an issue.

app.js:

import {inject} from 'aurelia-framework';
import {AppLocalization} from './localizations/app-localization';

@inject(AppLocalization)
export class App {
  constructor(appLocalization) {
    this.appLocalization = appLocalization;
  }

  activate() {
    console.log(this.appLocalization.HELLO_WORLD); // This properly prints the value to the console
  }
}

app.html:

<template>
  <h1 id="msg-id">${appLocalization.HELLO_WORLD}</h1>
</template>

localizations/app-localization.js:

/**
 * Screen specific strings
 */
export class AppLocalization {
  constructor() {
    this.HELLO_WORLD = 'Hello World!';
  }
}

app.spec.js:

import {App} from '../../src/app';
import {PLATFORM, DOM} from 'aurelia-pal';
import {StageComponent} from 'aurelia-testing';
import {bootstrap} from 'aurelia-bootstrapper';
describe('the app', () => {
  let component;

  describe('and testing screen components', () => {
    beforeEach(() => {
      // Configure Component (Screen)
      component = StageComponent
        .withResources(PLATFORM.moduleName('app'))
        .inView('<app></app>');

      component.bootstrap(aurelia => {
        aurelia.use.standardConfiguration();
      });
    });

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

    it('should display the correct header for the screen', done => {
      component.create(bootstrap)
        .then(() => component.viewModel.activate())
        .then(() => {
          const element = document.querySelector('#msg-id');
          expect(element).toBeDefined();
          expect(element.innerText).toBe('Hello World!');
          done();
          return null;
        }).catch(done.fail);
    });
  });
});

Test fails with message:

Error: expect(received).toBe(expected)

    Expected value to be (using ===):
      "Hello World!"
    Received:
      undefined

#2

Note: I’ve also tried registering an instance of AppLocalization into the test itself, but the same issue persists:

   let localization;

    beforeEach(() => {
      // Configure Component (Screen)
      localization = new AppLocalization();
      component = StageComponent
        .withResources(PLATFORM.moduleName('app'))
        .inView('<app></app>');

      component.bootstrap(aurelia => {
        aurelia.use.standardConfiguration();
        aurelia.container.registerInstance(AppLocalization, localization);
      });
    });

#3

Can you help provide a repro repo? And also it’s recommended generally to use textContent over innerText.


#4

Sure I’ll look into that and keep you posted, thanks! Ok good to know.


#5

Hi @bigopon , a repro repo can be found here: https://github.com/LilSebastian5000/aurelia-webpack4-karma-interpolation-failure


#6

Hey @bigopon I was wondering if you had a chance to take a look at this? Thanks!


#7

I think I did but i don’t know why I didn’t follow up! I’ll have a look again and let you know.


#8

When I ran the tests, the last one gave the error described. It is because of the way app instance was constructed in the test:


  it('says hello', () => {
    expect(new App().message).toBe('Hello World!');
  });

Note that App instance is constructed by new operator, directly, without any dependency-injection involvement. This means dependencies declared via @inject won’t be passed in the arguments to construct the App instance:

@inject(AppLocalization)
export class App {
  constructor(appLocalization) { /* <-- new App() will not have this argument */
    this.appLocalization = appLocalization; /* <-- making this undefined thus failed test */
  }
  ...
}

What you can do is to bootstrap the app instance using built-in bootstrapping helper with StageComponent:

component.create(bootstrap)
  .then(() => {
    // test here
    // expect(component.viewModel.message).toBe('Hello World!');
  });

Or if you want to test in simpler way, you can do:

const container = new Container;
const app = container.get(App);
expect(app.message).toBe('Hello World!');

There are about few ways to go for this, so if you have any more Q, post it here and folks will be happy to help :smile: (sorry for the silent period, not sure why I didn’t reply)


#9

Thank you for your help! I really appreciate it