@@ -3,18 +3,50 @@ import {Component, ElementRef, inject, ViewChild} from '@angular/core';
3
3
import { SharedResizeObserver } from './shared-resize-observer' ;
4
4
5
5
describe ( 'SharedResizeObserver' , ( ) => {
6
+ const currentObservers = new Map < ResizeObserverBoxOptions , MockResizeObserver > ( ) ;
6
7
let fixture : ComponentFixture < TestComponent > ;
7
8
let instance : TestComponent ;
8
9
let resizeObserver : SharedResizeObserver ;
10
+ let originalResizeObserver : typeof ResizeObserver ;
9
11
let el1 : Element ;
10
12
let el2 : Element ;
11
13
12
- async function waitForResize ( ) {
13
- fixture . detectChanges ( ) ;
14
- await new Promise ( r => setTimeout ( r , 16 ) ) ;
14
+ /**
15
+ * Mocked out resize observer that allows us to trigger the callback manually. It helps reduce
16
+ * test flakines caused by browsers that invoke the callbacks with inconsistent timings.
17
+ */
18
+ class MockResizeObserver implements ResizeObserver {
19
+ constructor ( private _callback : ResizeObserverCallback , options ?: ResizeObserverOptions ) {
20
+ currentObservers . set ( options ?. box || 'content-box' , this ) ;
21
+ }
22
+
23
+ observe ( element : Element ) {
24
+ // The native observer triggers the callback when an element is observed for the first time.
25
+ this . triggerCallback ( element ) ;
26
+ }
27
+
28
+ unobserve ( ) { }
29
+ disconnect ( ) { }
30
+
31
+ triggerCallback ( target : Element ) {
32
+ this . _callback (
33
+ [
34
+ {
35
+ target,
36
+ borderBoxSize : [ ] ,
37
+ contentBoxSize : [ ] ,
38
+ devicePixelContentBoxSize : [ ] ,
39
+ contentRect : { } as DOMRect ,
40
+ } ,
41
+ ] ,
42
+ this ,
43
+ ) ;
44
+ }
15
45
}
16
46
17
47
beforeEach ( ( ) => {
48
+ originalResizeObserver = ResizeObserver ;
49
+ window . ResizeObserver = MockResizeObserver ;
18
50
TestBed . configureTestingModule ( {
19
51
declarations : [ TestComponent ] ,
20
52
} ) ;
@@ -26,6 +58,11 @@ describe('SharedResizeObserver', () => {
26
58
el2 = instance . el2 . nativeElement ;
27
59
} ) ;
28
60
61
+ afterEach ( ( ) => {
62
+ window . ResizeObserver = originalResizeObserver ;
63
+ currentObservers . clear ( ) ;
64
+ } ) ;
65
+
29
66
it ( 'should return the same observable for the same element and same box' , ( ) => {
30
67
const observable1 = resizeObserver . observe ( el1 ) ;
31
68
const observable2 = resizeObserver . observe ( el1 ) ;
@@ -60,21 +97,21 @@ describe('SharedResizeObserver', () => {
60
97
const observable = resizeObserver . observe ( el1 ) ;
61
98
const resizeSpy1 = jasmine . createSpy ( 'resize handler 1' ) ;
62
99
observable . subscribe ( resizeSpy1 ) ;
63
- await waitForResize ( ) ;
100
+ fixture . detectChanges ( ) ;
64
101
expect ( resizeSpy1 ) . toHaveBeenCalled ( ) ;
65
102
const resizeSpy2 = jasmine . createSpy ( 'resize handler 2' ) ;
66
103
observable . subscribe ( resizeSpy2 ) ;
67
- await waitForResize ( ) ;
104
+ fixture . detectChanges ( ) ;
68
105
expect ( resizeSpy2 ) . toHaveBeenCalled ( ) ;
69
106
} ) ) ;
70
107
71
108
it ( 'should receive events on resize' , waitForAsync ( async ( ) => {
72
109
const resizeSpy = jasmine . createSpy ( 'resize handler' ) ;
73
110
resizeObserver . observe ( el1 ) . subscribe ( resizeSpy ) ;
74
- await waitForResize ( ) ;
111
+ fixture . detectChanges ( ) ;
75
112
resizeSpy . calls . reset ( ) ;
76
- instance . el1Width = 1 ;
77
- await waitForResize ( ) ;
113
+ currentObservers . get ( 'content-box' ) ?. triggerCallback ( el1 ) ;
114
+ fixture . detectChanges ( ) ;
78
115
expect ( resizeSpy ) . toHaveBeenCalled ( ) ;
79
116
} ) ) ;
80
117
@@ -83,26 +120,24 @@ describe('SharedResizeObserver', () => {
83
120
const resizeSpy2 = jasmine . createSpy ( 'resize handler 2' ) ;
84
121
resizeObserver . observe ( el1 ) . subscribe ( resizeSpy1 ) ;
85
122
resizeObserver . observe ( el2 ) . subscribe ( resizeSpy2 ) ;
86
- await waitForResize ( ) ;
123
+ fixture . detectChanges ( ) ;
87
124
resizeSpy1 . calls . reset ( ) ;
88
125
resizeSpy2 . calls . reset ( ) ;
89
- instance . el1Width = 1 ;
90
- await waitForResize ( ) ;
126
+ currentObservers . get ( 'content-box' ) ?. triggerCallback ( el1 ) ;
127
+ fixture . detectChanges ( ) ;
91
128
expect ( resizeSpy1 ) . toHaveBeenCalled ( ) ;
92
129
expect ( resizeSpy2 ) . not . toHaveBeenCalled ( ) ;
93
130
} ) ) ;
94
131
} ) ;
95
132
96
133
@Component ( {
97
134
template : `
98
- <div #el1 [style.height.px]="1" [style.width.px]="el1Width" ></div>
99
- <div #el2 [style.height.px]="1" [style.width.px]="el2Width" ></div>
135
+ <div #el1></div>
136
+ <div #el2></div>
100
137
` ,
101
138
} )
102
139
export class TestComponent {
103
140
@ViewChild ( 'el1' ) el1 : ElementRef < Element > ;
104
141
@ViewChild ( 'el2' ) el2 : ElementRef < Element > ;
105
142
resizeObserver = inject ( SharedResizeObserver ) ;
106
- el1Width = 0 ;
107
- el2Width = 0 ;
108
143
}
0 commit comments