-
-
Notifications
You must be signed in to change notification settings - Fork 241
/
Copy pathutil.ts
165 lines (158 loc) · 6.27 KB
/
util.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import { View } from "tns-core-modules/ui/core/view";
import { topmost } from "tns-core-modules/ui/frame";
import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { NgModule, Type } from "@angular/core";
import { NativeScriptModule } from "../../nativescript.module";
import { platformBrowserDynamicTesting } from "@angular/platform-browser-dynamic/testing";
import { NS_COMPILER_PROVIDERS } from "../../platform";
import { NATIVESCRIPT_TESTING_PROVIDERS, NativeScriptTestingModule } from "../index";
import { CommonModule } from "@angular/common";
/**
* Get a reference to the root application view.
*/
export function testingRootView(): View {
return topmost().currentPage.content;
}
/**
* Declared test contexts. When the suite is done this map should be empty if all lifecycle
* calls have happened as expected.
* @private
*/
const activeTestFixtures: ComponentFixture<any>[][] = [];
/**
* Return a promise that resolves after (durationMs) milliseconds
*/
export function promiseWait(durationMs: number) {
return () => new Promise((resolve) => setTimeout(() => resolve(), durationMs));
}
/**
* Perform basic TestBed environment initialization. Call this once in the main entry point to your tests.
*/
export function nTestBedInit() {
TestBed.initTestEnvironment(
NativeScriptTestingModule,
platformBrowserDynamicTesting(NS_COMPILER_PROVIDERS)
);
}
/**
* Helper for configuring a TestBed instance for rendering components for test. Ideally this
* would not be needed, and in truth it's just a wrapper to eliminate some boilerplate. It
* exists because when you need to specify `entryComponents` for a test the setup becomes quite
* a bit more complex than if you're just doing a basic component test.
*
* More about entryComponents complexity: https://github.com/angular/angular/issues/12079
*
* Use:
* ```
* beforeEach(nTestBedBeforeEach([MyComponent,MyFailComponent]));
* ```
*
* **NOTE*** Remember to pair with {@see nTestBedAfterEach}
*
* @param components Any components that you will create during the test
* @param providers Any services your tests depend on
* @param imports Any module imports your tests depend on
* @param entryComponents Any entry components that your tests depend on
*/
export function nTestBedBeforeEach(
components: any[],
providers: any[] = [],
imports: any[] = [],
entryComponents: any[] = []) {
return (done) => {
activeTestFixtures.push([]);
// If there are no entry components we can take the simple path.
if (entryComponents.length === 0) {
TestBed.configureTestingModule({
declarations: [...components],
providers: [...providers],
imports: [NativeScriptModule, ...imports]
});
} else {
// If there are entry components, we have to reset the testing platform.
//
// There's got to be a better way... (o_O)
TestBed.resetTestEnvironment();
@NgModule({
declarations: entryComponents,
exports: entryComponents,
entryComponents: entryComponents
})
class EntryComponentsTestModule {
}
TestBed.initTestEnvironment(
EntryComponentsTestModule,
platformBrowserDynamicTesting(NS_COMPILER_PROVIDERS)
);
TestBed.configureTestingModule({
declarations: components,
imports: [
NativeScriptModule, NativeScriptTestingModule, CommonModule,
...imports
],
providers: [...providers, ...NATIVESCRIPT_TESTING_PROVIDERS],
});
}
TestBed.compileComponents()
.then(() => done())
.catch((e) => {
console.log(`Failed to instantiate test component with error: ${e}`);
console.log(e.stack);
done();
});
};
}
/**
* Helper for a basic component TestBed clean up.
* @param resetEnv When true the testing environment will be reset
* @param resetFn When resetting the environment, use this init function
*/
export function nTestBedAfterEach(resetEnv = true, resetFn = nTestBedInit) {
return () => {
if (activeTestFixtures.length === 0) {
throw new Error(
`There are no more declared fixtures.` +
`Did you call "nTestBedBeforeEach" and "nTestBedAfterEach" an equal number of times?`
);
}
const root = testingRootView() as LayoutBase;
const fixtures = activeTestFixtures.pop();
fixtures.forEach((fixture) => {
root.removeChild(fixture.nativeElement);
fixture.destroy();
});
TestBed.resetTestingModule();
if (resetEnv) {
TestBed.resetTestEnvironment();
resetFn();
}
};
}
/**
* Render a component using the TestBed helper, and return a promise that resolves when the
* ComponentFixture is fully initialized.
*/
export function nTestBedRender<T>(componentType: Type<T>): Promise<ComponentFixture<T>> {
const fixture = TestBed.createComponent(componentType);
fixture.detectChanges();
return fixture.whenRenderingDone()
// TODO(jd): it seems that the whenStable and whenRenderingDone utilities of ComponentFixture
// do not work as expected. I looked at how to fix it and it's not clear how to provide
// a {N} specific subclass, because ComponentFixture is newed directly rather than injected
// What to do about it? Maybe fakeAsync can help? For now just setTimeout for 100ms (x_X)
.then(promiseWait(100))
.then(() => {
const list = activeTestFixtures[activeTestFixtures.length - 1];
if (!list) {
console.warn(
"nTestBedRender called without nTestBedBeforeEach/nTestBedAfter each. " +
"You are responsible for calling 'fixture.destroy()' when your test is done " +
"in order to clean up the components that are created."
);
} else {
list.push(fixture);
}
return fixture;
});
}