How to get or create global DI container for testing

In Aurelia 1 I was able to configure a global DI container like:

import {Container} from "aurelia-dependency-injection";
const container = new Container();
container.makeGlobal();
const bytesFormatValueConverter = container.get(ByteFormatValueConverter);

How do I do this in Aurelia 2?

There’s no global container in v2, but you call always have something like this in your jest setup (based on your other question):

import { DI, IContainer } from 'aurelia';

declare global {
  export let container: IContainer
}

beforeEach(() => {
  global.container = DI.createContainer();
})

Then you will have a new container for each test at the global property container

How do I make

const container = DI.createContainer()
const numberValueFormatter = container.get(NumberValueConverter)
numberValueFormatter.setLocale("de")

and

const { appHost, startPromise, tearDown } = createFixture(
    '<div>${numberUnderTest | number}</div>',
    class App {
        numberUnderTest = 13.37;
    },
    [NumberValueConverter]
);

using the same instance of NumberValueConverter?

Do you need to create it before starting the app? If not, the following suffices

let numberValueFormater: NumberValueConverter;

it('....', function () {
  const { container } = createFixture(...)

  numberValueFormater = container.get(NumberValueConverter);
})

If they need to be the same then you can create a single test context and use it for all fixtures:

import { TextContext } from '@aurelia/testing';

const testContext = TestContext.create();
const formatter = testContext.container.get(NumberValueFormatter);

it('...', function () {
  const {} = createFixture('<div>', class {}, [], testContext)
})

Though this way of reusing container is discouraged, since you are likely to be in for a surprise later as the same container in the global test context is gonna be used for everything.

The second approach is what I want. But when I pass testContext I get the error: AUR0009

const testContext = TestContext.create();
    const numberValueFormatter = testContext.container.get(NumberValueConverter);
    numberValueFormatter.setLocale("de")

    beforeAll(() => {
        bootstrapTestEnvironment();
    });

    // Integration Test
    it('works within a view', async () => {
        const { appHost, startPromise, tearDown } = createFixture(
            '<div>${numberUnderTest | number}</div>',
            class App {
                numberUnderTest = 13.37;
            },
            [NumberValueConverter],
            true,
            testContext
        );
...

When I don’t pass textContext the test passes.

I missed the order of the parameters, it should be

it('...', function () {
  const {} = createFixture(
    '<div>',
    class {},
    [],
+   true, 
    testContext
  )
})

edit: nvm I saw you have the same code

An example how it works is here https://stackblitz.com/edit/au2-conventions-5uskd3?file=src%2Fmy-app.spec.ts

The reason you got 0009 with IPlatform is because TestContext.create() was called before bootstrapTestEnvironment(), which is what prepares the registration for IPlatform

It works! :star_struck:
This should be definitely added to the documentation!

Well we definitely don’t want to encourage a reusable test context, and it likely won’t work with multiple tests I think. We probably need to have a better way to specify the root container instead. Maybe it can be an improvement for your type of usage.

I don’t want a reusable test context but a mutable Singleton for the test.

Does it have to be a singleton? Whatabout

let testContext: TestContext;
let converter: NumberValueConverter;

beforeEach(() => {
  testContext = TestContext.create();
  converter = testContext.container.get(NumberValueConverter);
})

it('...', function () {
  const {} = createFixture(..., ..., ..., ..., testContext)
})

This is also fine. I mean, better.

1 Like