1
- import { Component , DebugElement , ElementRef , OnInit , Type , NgZone } from '@angular/core' ;
1
+ import { Component , ElementRef , OnInit , Type , NgZone } from '@angular/core' ;
2
2
import { ComponentFixture , TestBed } from '@angular/core/testing' ;
3
3
import { By } from '@angular/platform-browser' ;
4
4
import { BrowserAnimationsModule , NoopAnimationsModule } from '@angular/platform-browser/animations' ;
5
5
import { Router } from '@angular/router' ;
6
6
import { RouterTestingModule } from '@angular/router/testing' ;
7
7
import { fireEvent , FireFunction , FireObject , getQueriesForElement , prettyDOM } from '@testing-library/dom' ;
8
- import { RenderOptions , RenderResult } from './models' ;
8
+ import { RenderComponentOptions , RenderDirectiveOptions , RenderResult } from './models' ;
9
9
import { createSelectOptions , createType } from './user-events' ;
10
10
11
11
@Component ( { selector : 'wrapper-component' , template : '' } )
12
12
class WrapperComponent implements OnInit {
13
- constructor ( private elemtRef : ElementRef ) { }
13
+ constructor ( private elementRef : ElementRef ) { }
14
14
15
15
ngOnInit ( ) {
16
- this . elemtRef . nativeElement . removeAttribute ( 'ng-version' ) ;
16
+ this . elementRef . nativeElement . removeAttribute ( 'ng-version' ) ;
17
17
}
18
18
}
19
19
20
- export async function render < T > ( template : string , renderOptions : RenderOptions < T > ) : Promise < RenderResult > ;
21
- export async function render < T > ( component : Type < T > , renderOptions ?: RenderOptions < T > ) : Promise < RenderResult > ;
22
- export async function render < T > (
23
- templateOrComponent : string | Type < T > ,
24
- renderOptions : RenderOptions < T > = { } ,
25
- ) : Promise < RenderResult > {
20
+ export async function render < ComponentType > (
21
+ component : Type < ComponentType > ,
22
+ renderOptions ?: RenderComponentOptions < ComponentType > ,
23
+ ) : Promise < RenderResult < ComponentType , ComponentType > > ;
24
+ export async function render < DirectiveType , WrapperType = WrapperComponent > (
25
+ component : Type < DirectiveType > ,
26
+ renderOptions ?: RenderDirectiveOptions < DirectiveType , WrapperType > ,
27
+ ) : Promise < RenderResult < DirectiveType , WrapperType > > ;
28
+
29
+ export async function render < SutType , WrapperType = SutType > (
30
+ sut : Type < SutType > ,
31
+ renderOptions : RenderComponentOptions < SutType > | RenderDirectiveOptions < SutType , WrapperType > = { } ,
32
+ ) : Promise < RenderResult < SutType > > {
26
33
const {
27
34
detectChanges = true ,
28
35
declarations = [ ] ,
29
36
imports = [ ] ,
30
37
providers = [ ] ,
31
38
schemas = [ ] ,
32
39
queries,
40
+ template,
33
41
wrapper = WrapperComponent ,
34
42
componentProperties = { } ,
35
43
componentProviders = [ ] ,
36
44
excludeComponentDeclaration = false ,
37
- routes,
38
- } = renderOptions ;
39
-
40
- const isTemplate = typeof templateOrComponent === 'string' ;
41
- const componentDeclarations = declareComponents ( {
42
- templateOrComponent,
43
- wrapper,
44
- isTemplate,
45
- excludeComponentDeclaration,
46
- } ) ;
45
+ routes
46
+ } = renderOptions as RenderDirectiveOptions < SutType , WrapperType > ;
47
47
48
48
TestBed . configureTestingModule ( {
49
- declarations : [ ... declarations , ... componentDeclarations ] ,
50
- imports : addAutoImports ( { imports, routes } ) ,
49
+ declarations : addAutoDeclarations ( sut , { declarations, excludeComponentDeclaration , template , wrapper } ) ,
50
+ imports : addAutoImports ( { imports, routes} ) ,
51
51
providers : [ ...providers ] ,
52
52
schemas : [ ...schemas ] ,
53
53
} ) ;
@@ -61,9 +61,8 @@ export async function render<T>(
61
61
} ) ;
62
62
}
63
63
64
- const fixture = isTemplate
65
- ? createWrapperComponentFixture ( templateOrComponent as string , { wrapper, componentProperties } )
66
- : createComponentFixture ( templateOrComponent as Type < T > , { componentProperties } ) ;
64
+ const fixture = createComponentFixture ( sut , { template, wrapper } ) ;
65
+ setComponentProperties ( fixture , { componentProperties } ) ;
67
66
68
67
await TestBed . compileComponents ( ) ;
69
68
@@ -93,12 +92,16 @@ export async function render<T>(
93
92
94
93
const href = typeof elementOrPath === 'string' ? elementOrPath : elementOrPath . getAttribute ( 'href' ) ;
95
94
96
- await zone . run ( ( ) => router . navigate ( [ basePath + href ] ) ) ;
95
+ let result ;
96
+ await zone . run ( ( ) => result = router . navigate ( [ basePath + href ] ) ) ;
97
97
fixture . detectChanges ( ) ;
98
+ return result ;
98
99
}
100
+ const debugElement = fixture . debugElement . query ( By . directive ( sut ) ) ;
99
101
100
102
return {
101
103
fixture,
104
+ debugElement,
102
105
container : fixture . nativeElement ,
103
106
debug : ( element = fixture . nativeElement ) => console . log ( prettyDOM ( element ) ) ,
104
107
detectChanges : ( ) => fixture . detectChanges ( ) ,
@@ -107,86 +110,54 @@ export async function render<T>(
107
110
type : createType ( eventsWithDetectChanges ) ,
108
111
selectOptions : createSelectOptions ( eventsWithDetectChanges ) ,
109
112
navigate,
110
- } as any ;
113
+ } ;
111
114
}
112
115
113
- /**
114
- * Creates the wrapper component and sets its the template to the to-be-tested component
115
- */
116
- function createWrapperComponentFixture < T > (
117
- template : string ,
118
- {
119
- wrapper,
120
- componentProperties,
121
- } : {
122
- wrapper : RenderOptions < T > [ 'wrapper' ] ;
123
- componentProperties : RenderOptions < T > [ 'componentProperties' ] ;
124
- } ,
125
- ) : ComponentFixture < any > {
126
- TestBed . overrideComponent ( wrapper , {
127
- set : {
128
- template : template ,
129
- } ,
130
- } ) ;
131
-
132
- const fixture = TestBed . createComponent ( wrapper ) ;
133
- // get the component selector, e.g. <foo color="green"> and <foo> results in foo
134
- const componentSelector = template . match ( / \< ( .* ?) \ / ) || template . match ( / \< ( .* ?) \> / ) ;
135
- if ( ! componentSelector ) {
136
- throw Error ( `Template ${ template } is not valid.` ) ;
116
+ function createComponentFixture < SutType > (
117
+ component : Type < SutType > ,
118
+ { template, wrapper } : Pick < RenderDirectiveOptions < SutType , any > , 'template' | 'wrapper' > ,
119
+ ) : ComponentFixture < SutType > {
120
+ if ( template ) {
121
+ TestBed . overrideTemplate ( wrapper , template ) ;
122
+ return TestBed . createComponent ( wrapper ) ;
137
123
}
138
-
139
- const sut = fixture . debugElement . query ( By . css ( componentSelector [ 1 ] ) ) ;
140
- setComponentProperties ( sut , { componentProperties } ) ;
141
- return fixture ;
124
+ return TestBed . createComponent ( component ) ;
142
125
}
143
126
144
- /**
145
- * Creates the components and sets its properties
146
- */
147
- function createComponentFixture < T > (
148
- component : Type < T > ,
149
- {
150
- componentProperties = { } ,
151
- } : {
152
- componentProperties : RenderOptions < T > [ 'componentProperties' ] ;
153
- } ,
154
- ) : ComponentFixture < T > {
155
- const fixture = TestBed . createComponent ( component ) ;
156
- setComponentProperties ( fixture , { componentProperties } ) ;
157
- return fixture ;
158
- }
159
-
160
- /**
161
- * Set the component properties
162
- */
163
- function setComponentProperties < T > (
164
- fixture : ComponentFixture < T > | DebugElement ,
165
- {
166
- componentProperties = { } ,
167
- } : {
168
- componentProperties : RenderOptions < T > [ 'componentProperties' ] ;
169
- } ,
127
+ function setComponentProperties < SutType > (
128
+ fixture : ComponentFixture < SutType > ,
129
+ { componentProperties = { } } : Pick < RenderDirectiveOptions < SutType , any > , 'componentProperties' > ,
170
130
) {
171
131
for ( const key of Object . keys ( componentProperties ) ) {
172
132
fixture . componentInstance [ key ] = componentProperties [ key ] ;
173
133
}
174
134
return fixture ;
175
135
}
176
136
177
- function declareComponents ( { isTemplate, wrapper, excludeComponentDeclaration, templateOrComponent } ) {
178
- if ( isTemplate ) {
179
- return [ wrapper ] ;
180
- }
137
+ function addAutoDeclarations < SutType > (
138
+ component : Type < SutType > ,
139
+ {
140
+ declarations,
141
+ excludeComponentDeclaration,
142
+ template,
143
+ wrapper,
144
+ } : Pick <
145
+ RenderDirectiveOptions < SutType , any > ,
146
+ 'declarations' | 'excludeComponentDeclaration' | 'template' | 'wrapper'
147
+ > ,
148
+ ) {
149
+ const wrappers = ( ) => {
150
+ return template ? [ wrapper ] : [ ] ;
151
+ } ;
181
152
182
- if ( excludeComponentDeclaration ) {
183
- return [ ] ;
184
- }
153
+ const components = ( ) => {
154
+ return excludeComponentDeclaration ? [ ] : [ component ] ;
155
+ } ;
185
156
186
- return [ templateOrComponent ] ;
157
+ return [ ... declarations , ... wrappers ( ) , ... components ( ) ] ;
187
158
}
188
159
189
- function addAutoImports ( { imports, routes } : Pick < RenderOptions < any > , 'imports' | 'routes' > ) {
160
+ function addAutoImports ( { imports, routes } : Pick < RenderComponentOptions < any > , 'imports' | 'routes' > ) {
190
161
const animations = ( ) => {
191
162
const animationIsDefined =
192
163
imports . indexOf ( NoopAnimationsModule ) > - 1 || imports . indexOf ( BrowserAnimationsModule ) > - 1 ;
0 commit comments