Skip to content

Commit

Permalink
refactor: set types for initializers/embedded
Browse files Browse the repository at this point in the history
  • Loading branch information
MrChocolatine committed Jun 4, 2021
1 parent 1acc864 commit 3f80791
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 49 deletions.
4 changes: 2 additions & 2 deletions addon/initializers/embedded.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ function normalizeConfig(userConfig:GivenConfig):ObjectConfig {
return Object.assign({ config: {} }, userConfig)
}

export function initialize():void {
const application:Application = arguments[1] || arguments[0]
export function initialize(...args: [ Application, Application? ]): void {
const application = args[1] || args[0]
const env = application.resolveRegistration('config:environment')

let appConfig:GivenConfig = get(env, 'embedded')
Expand Down
115 changes: 68 additions & 47 deletions tests/unit/initializers/embedded-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,25 @@ import { module, test } from 'qunit';
import Resolver from 'ember-resolver';
import { run } from '@ember/runloop';

import type { TestContext } from 'ember-test-helpers';

interface Context extends TestContext {
TestApplication: typeof Application;

// different key to not conflict with `application` from `TestContext`
app: TestContext['application'] & {
// Public types are currently incomplete, these 2 properties exist:
// https://github.com/emberjs/ember.js/blob/79f130f779a58969b98d079acf7d0e83c81dae63/packages/%40ember/application/lib/application.js#L376-L377
_booted: boolean;
_readinessDeferrals: number;

// The method added by our Initializer `embedded`
start?: (config?: Record<string, unknown>) => void;
};
}

module('Unit | Initializer | embedded', function (hooks) {
hooks.beforeEach(function () {
hooks.beforeEach(function (this: Context) {
this.TestApplication = class TestApplication extends Application {
modulePrefix = 'something_random';
};
Expand All @@ -16,185 +33,188 @@ module('Unit | Initializer | embedded', function (hooks) {
initialize,
});

this.application = this.TestApplication.create({
// `as any` to bypass temporarily the types check as public types are incomplete.
// Otherwise it complains about the missing properties `_booted` etc
this.app = this.TestApplication.create({
autoboot: false,
Resolver,
});
}) as any;

this.application.register('config:environment', {});
this.app.register('config:environment', {});
});

hooks.afterEach(function () {
run(this.application, 'destroy');
hooks.afterEach(function (this: Context) {
run(this.app, 'destroy');
});

test('by default, it does not change the normal behaviour', async function (assert) {
test('by default, it does not change the normal behaviour', async function (this: Context, assert) {
assert.expect(3);

await this.application.boot();
await this.app.boot();

assert.strictEqual(
this.application.start,
this.app.start,
undefined,
'No `start()` method has been added'
);

assert.deepEqual(
this.application.resolveRegistration('config:embedded'),
this.app.resolveRegistration('config:embedded'),
{},
'An empty embedded config is registered'
);

assert.ok(
this.application._booted === true && this.application._readinessDeferrals === 0,
this.app._booted === true && this.app._readinessDeferrals === 0,
'No deferral has been added'
);
});

test('without `delegateStart`, it does not change the normal behaviour', async function (assert) {
test('without `delegateStart`, it does not change the normal behaviour', async function (this: Context, assert) {
assert.expect(3);

this.application.register('config:environment', {
this.app.register('config:environment', {
embedded: {
delegateStart: false,
},
});

await this.application.boot();
await this.app.boot();

assert.strictEqual(
this.application.start,
this.app.start,
undefined,
'No `start()` method has been added'
);

assert.deepEqual(
this.application.resolveRegistration('config:embedded'),
this.app.resolveRegistration('config:embedded'),
{},
'An empty embedded config is registered'
);

assert.ok(
this.application._booted === true && this.application._readinessDeferrals === 0,
this.app._booted === true && this.app._readinessDeferrals === 0,
'No deferral has been added'
);
});

test('without `delegateStart`, the specified config is registered', async function (assert) {
test('without `delegateStart`, the specified config is registered', async function (this: Context, assert) {
assert.expect(1);

const myCustomConfig = {
donald: 'duck',
};

this.application.register('config:environment', {
this.app.register('config:environment', {
embedded: {
delegateStart: false,
config: myCustomConfig,
},
});

await this.application.boot();
await this.app.boot();

assert.deepEqual(
this.application.resolveRegistration('config:embedded'),
this.app.resolveRegistration('config:embedded'),
myCustomConfig,
'The embedded config matches the custom config'
);
});

test('with `delegateStart`, it defers the boot of the app', function (assert) {
test('with `delegateStart`, it defers the boot of the app', function (this: Context, assert) {
assert.expect(3);

this.application.register('config:environment', {
this.app.register('config:environment', {
embedded: {
delegateStart: true,
},
});

const { _readinessDeferrals: initialDeferrals } = this.application;
const { _readinessDeferrals: initialDeferrals } = this.app;

/**
* Cannot use `application.boot()` here as this would imply triggering the readiness deferral
* Cannot use `app.boot()` here as this would imply triggering the readiness deferral
* and the resulting promise (of the boot) would never resolve.
*/
initialize(this.application);
initialize(this.app);

assert.strictEqual(
typeof this.application.start,
typeof this.app.start,
'function',
'A `start()` method has been added'
);

assert.deepEqual(
this.application.resolveRegistration('config:embedded'),
this.app.resolveRegistration('config:embedded'),
undefined,
'The embedded config is not registered until the app is started'
);

const { _booted, _readinessDeferrals } = this.application;
const { _booted, _readinessDeferrals } = this.app;

assert.ok(
_booted === false && _readinessDeferrals === initialDeferrals + 1,
'A deferral has been added'
);
});

test('with `delegateStart`, the passed config is not registered until the app is started', function (assert) {
test('with `delegateStart`, the passed config is not registered until the app is started', function (this: Context, assert) {
assert.expect(1);

const myCustomConfig = {
donald: 'duck',
};

this.application.register('config:environment', {
this.app.register('config:environment', {
embedded: {
delegateStart: true,
config: myCustomConfig,
},
});

/**
* Cannot use `application.boot()` here as this would imply triggering the readiness deferral
* Cannot use `app.boot()` here as this would imply triggering the readiness deferral
* and the resulting promise (of the boot) would never resolve.
*/
initialize(this.application);
initialize(this.app);

assert.deepEqual(
this.application.resolveRegistration('config:embedded'),
this.app.resolveRegistration('config:embedded'),
undefined,
'The embedded config is not registered until the app is started'
);
});

test('at manual boot, the passed config is merged into the embedded config', function (assert) {
test('at manual boot, the passed config is merged into the embedded config', function (this: Context, assert) {
assert.expect(1);

const myCustomConfig = {
yo: 'my config',
hey: 'sup?',
};

this.application.register('config:environment', {
this.app.register('config:environment', {
embedded: {
delegateStart: true,
config: myCustomConfig,
},
});

/**
* Cannot use `application.boot()` here as this would imply triggering the readiness deferral
* Cannot use `app.boot()` here as this would imply triggering the readiness deferral
* and the resulting promise (of the boot) would never resolve.
*/
initialize(this.application);
initialize(this.app);

this.application.start({
// Previous tests confirm that, at this point, `.start()` is defined
this.app.start!({
yay: 'one more',
yo: 'new config',
});

assert.deepEqual(
this.application.resolveRegistration('config:embedded'),
this.app.resolveRegistration('config:embedded'),
{
yo: 'new config',
hey: 'sup?',
Expand All @@ -204,27 +224,28 @@ module('Unit | Initializer | embedded', function (hooks) {
);
});

test('at manual boot, one deferral is removed', function (assert) {
test('at manual boot, one deferral is removed', function (this: Context, assert) {
assert.expect(1);

this.application.register('config:environment', {
this.app.register('config:environment', {
embedded: {
delegateStart: true,
},
});

/**
* Cannot use `application.boot()` here as this would imply triggering the readiness deferral
* Cannot use `app.boot()` here as this would imply triggering the readiness deferral
* and the resulting promise (of the boot) would never resolve.
*/
initialize(this.application);
initialize(this.app);

const { _readinessDeferrals: initialDeferrals } = this.application;
const { _readinessDeferrals: initialDeferrals } = this.app;

this.application.start();
// Previous tests confirm that, at this point, `.start()` is defined
this.app.start!();

assert.strictEqual(
this.application._readinessDeferrals,
this.app._readinessDeferrals,
initialDeferrals - 1,
'A deferral has been removed'
);
Expand Down

0 comments on commit 3f80791

Please sign in to comment.