-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
bootstrapper.unit.ts
151 lines (132 loc) · 4.8 KB
/
bootstrapper.unit.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: @loopback/boot
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
import {Application} from '@loopback/core';
import {RepositoryMixin} from '@loopback/repository';
import {expect} from '@loopback/testlab';
import {BootBindings, Booter, BootMixin, Bootstrapper} from '../..';
describe('boot-strapper unit tests', () => {
// RepositoryMixin is added to avoid warning message printed logged to console
// due to the fact that RepositoryBooter is a default Booter loaded via BootMixin.
class BootApp extends BootMixin(RepositoryMixin(Application)) {}
let app: BootApp;
let bootstrapper: Bootstrapper;
const booterKey = `${BootBindings.BOOTER_PREFIX}.TestBooter`;
const anotherBooterKey = `${BootBindings.BOOTER_PREFIX}.AnotherBooter`;
beforeEach(getApplication);
beforeEach(getBootStrapper);
it('finds and runs registered booters', async () => {
const ctx = await bootstrapper.boot();
const booterInst = await ctx.get<TestBooter>(booterKey);
expect(booterInst.phasesCalled).to.eql([
'TestBooter:configure',
'TestBooter:load',
]);
});
it('binds booters passed in BootExecutionOptions', async () => {
const ctx = await bootstrapper.boot({booters: [AnotherBooter]});
const anotherBooterInst = await ctx.get<AnotherBooter>(anotherBooterKey);
expect(anotherBooterInst).to.be.instanceof(AnotherBooter);
expect(anotherBooterInst.phasesCalled).to.eql(['AnotherBooter:configure']);
});
it('no booters run when BootOptions.filter.booters is []', async () => {
const ctx = await bootstrapper.boot({filter: {booters: []}});
const booterInst = await ctx.get<TestBooter>(booterKey);
expect(booterInst.phasesCalled).to.eql([]);
});
it('only runs booters passed in via BootOptions.filter.booters', async () => {
const ctx = await bootstrapper.boot({
booters: [AnotherBooter],
filter: {booters: ['AnotherBooter']},
});
const testBooterInst = await ctx.get<TestBooter>(booterKey);
const anotherBooterInst = await ctx.get<AnotherBooter>(anotherBooterKey);
const phasesCalled = testBooterInst.phasesCalled.concat(
anotherBooterInst.phasesCalled,
);
expect(phasesCalled).to.eql(['AnotherBooter:configure']);
});
it('only runs phases passed in via BootOptions.filter.phases', async () => {
const ctx = await bootstrapper.boot({filter: {phases: ['configure']}});
const booterInst = await ctx.get<TestBooter>(booterKey);
expect(booterInst.phasesCalled).to.eql(['TestBooter:configure']);
});
it('sets application states', async () => {
const boot = app.boot();
expect(app.state).to.eql('booting');
await boot;
expect(app.state).to.eql('booted');
// No-op
await app.boot();
expect(app.state).to.eql('booted');
const start = app.start();
expect(app.state).to.equal('starting');
await start;
expect(app.state).to.equal('started');
const stop = app.stop();
expect(app.state).to.equal('stopping');
await stop;
expect(app.state).to.equal('stopped');
});
it('awaits booted if the application is booting', async () => {
const boot = app.boot();
expect(app.state).to.eql('booting');
const bootAgain = app.boot();
await boot;
await bootAgain;
expect(app.state).to.eql('booted');
});
it('throws error with invalid application states', async () => {
await app.start();
await expect(app.boot()).to.be.rejectedWith(
/Cannot boot the application as it is started\. Valid states are created,booted\./,
);
});
/**
* Sets 'app' as a new instance of Application. Registers TestBooter as a booter.
*/
function getApplication() {
app = new BootApp();
app.booters(TestBooter);
}
/**
* Sets 'bootstrapper' as a new instance of a Bootstrapper
*/
function getBootStrapper() {
bootstrapper = new Bootstrapper(app, __dirname);
}
/**
* A TestBooter for testing purposes. Implements configure and load.
*/
class TestBooter implements Booter {
private configureCalled = false;
private loadCalled = false;
async configure() {
this.configureCalled = true;
}
async load() {
this.loadCalled = true;
}
get phasesCalled() {
const result = [];
if (this.configureCalled) result.push('TestBooter:configure');
if (this.loadCalled) result.push('TestBooter:load');
return result;
}
}
/**
* A TestBooter for testing purposes. Implements configure.
*/
class AnotherBooter implements Booter {
private configureCalled = false;
async configure() {
this.configureCalled = true;
}
get phasesCalled() {
const result = [];
if (this.configureCalled) result.push('AnotherBooter:configure');
return result;
}
}
});