@@ -21,6 +21,7 @@ jest.useFakeTimers();
2121afterEach ( ( ) => {
2222 document . getElementsByTagName ( "html" ) [ 0 ] . innerHTML = "" ;
2323 delete Loader [ "instance" ] ;
24+ if ( window . google ) delete window . google ;
2425} ) ;
2526
2627test . each ( [
@@ -65,59 +66,59 @@ test("uses default id if empty string", () => {
6566 expect ( new Loader ( { apiKey : "foo" , id : "" } ) . id ) . toBe ( DEFAULT_ID ) ;
6667} ) ;
6768
68- test ( "setScript adds a script to head with correct attributes" , ( ) => {
69+ test ( "setScript adds a script to head with correct attributes" , async ( ) => {
6970 const loader = new Loader ( { apiKey : "foo" } ) ;
7071
7172 loader [ "setScript" ] ( ) ;
73+ await 0 ;
7274
7375 const script = document . head . childNodes [ 0 ] as HTMLScriptElement ;
7476
7577 expect ( script . id ) . toEqual ( loader . id ) ;
76- expect ( script . src ) . toEqual ( loader . createUrl ( ) ) ;
77- expect ( script . defer ) . toBeTruthy ( ) ;
78- expect ( script . async ) . toBeTruthy ( ) ;
79- expect ( script . onerror ) . toBeTruthy ( ) ;
80- expect ( script . type ) . toEqual ( "text/javascript" ) ;
8178} ) ;
8279
83- test ( "setScript does not add second script with same id" , ( ) => {
84- new Loader ( { apiKey : "foo" , id : "bar" } ) [ "setScript" ] ( ) ;
85- new Loader ( { apiKey : "foo" , id : "bar" } ) [ "setScript" ] ( ) ;
86- 87- expect ( document . head . childNodes . length ) . toBe ( 1 ) ;
88- } ) ;
89- 90- test ( "setScript adds a script with id" , ( ) => {
80+ test ( "setScript adds a script with id" , async ( ) => {
9181 const loader = new Loader ( { apiKey : "foo" , id : "bar" } ) ;
9282 loader [ "setScript" ] ( ) ;
83+ await 0 ;
9384
9485 const script = document . head . childNodes [ 0 ] as HTMLScriptElement ;
95- expect ( script . id ) . toEqual ( loader . id ) ;
86+ expect ( script . localName ) . toEqual ( "script" ) ;
87+ expect ( loader . id ) . toEqual ( "bar" ) ;
88+ expect ( script . id ) . toEqual ( "bar" ) ;
89+ } ) ;
90+ 91+ test ( "setScript does not add second script with same id" , async ( ) => {
92+ new Loader ( { apiKey : "foo" , id : "bar" } ) [ "setScript" ] ( ) ;
93+ new Loader ( { apiKey : "foo" , id : "bar" } ) [ "setScript" ] ( ) ;
94+ await 0 ;
95+ new Loader ( { apiKey : "foo" , id : "bar" } ) [ "setScript" ] ( ) ;
96+ await 0 ;
97+ 98+ expect ( document . head . childNodes . length ) . toBe ( 1 ) ;
9699} ) ;
97100
98101test ( "load should return a promise that resolves even if called twice" , ( ) => {
99102 const loader = new Loader ( { apiKey : "foo" } ) ;
103+ loader . importLibrary = ( ( ) => Promise . resolve ( ) ) as any ;
100104
101105 expect . assertions ( 1 ) ;
102106 const promise = Promise . all ( [ loader . load ( ) , loader . load ( ) ] ) . then ( ( ) => {
103107 expect ( loader [ "done" ] ) . toBeTruthy ( ) ;
104108 } ) ;
105109
106- window . __googleMapsCallback ( null ) ;
107- 108110 return promise ;
109111} ) ;
110112
111113test ( "loadCallback callback should fire" , ( ) => {
112114 const loader = new Loader ( { apiKey : "foo" } ) ;
115+ loader . importLibrary = ( ( ) => Promise . resolve ( ) ) as any ;
113116
114117 expect . assertions ( 2 ) ;
115118 loader . loadCallback ( ( e : Event ) => {
116119 expect ( loader [ "done" ] ) . toBeTruthy ( ) ;
117120 expect ( e ) . toBeUndefined ( ) ;
118121 } ) ;
119- 120- window . __googleMapsCallback ( null ) ;
121122} ) ;
122123
123124test ( "script onerror should reject promise" , async ( ) => {
@@ -163,82 +164,78 @@ test("script onerror should reject promise with multiple loaders", async () => {
163164test ( "script onerror should retry" , async ( ) => {
164165 const loader = new Loader ( { apiKey : "foo" , retries : 1 } ) ;
165166 const deleteScript = jest . spyOn ( loader , "deleteScript" ) ;
167+ loader . importLibrary = ( ( ) => Promise . reject ( new Error ( "fake error" ) ) ) as any ;
166168 const rejection = expect ( loader . load ( ) ) . rejects . toBeInstanceOf ( Error ) ;
167169 // eslint-disable-next-line @typescript-eslint/no-empty-function
168- console . log = jest . fn ( ) ;
170+ console . error = jest . fn ( ) ;
169171
170- loader [ "loadErrorCallback" ] (
171- new ErrorEvent ( "ErrorEvent(" , { error : new Error ( "" ) } )
172- ) ;
173- loader [ "loadErrorCallback" ] (
174- new ErrorEvent ( "ErrorEvent(" , { error : new Error ( "" ) } )
175- ) ;
172+ // wait for the first failure
173+ await 0 ;
174+ expect ( loader [ "errors" ] . length ) . toBe ( 1 ) ;
175+ // trigger the retry delay:
176176 jest . runAllTimers ( ) ;
177177
178178 await rejection ;
179+ expect ( loader [ "errors" ] . length ) . toBe ( 2 ) ;
179180 expect ( loader [ "done" ] ) . toBeTruthy ( ) ;
181+ expect ( loader [ "failed" ] ) . toBeTruthy ( ) ;
180182 expect ( loader [ "loading" ] ) . toBeFalsy ( ) ;
181- expect ( loader [ "errors" ] . length ) . toBe ( 2 ) ;
182183 expect ( deleteScript ) . toHaveBeenCalledTimes ( 1 ) ;
183- expect ( console . log ) . toHaveBeenCalledTimes ( loader . retries ) ;
184+ expect ( console . error ) . toHaveBeenCalledTimes ( loader . retries ) ;
184185} ) ;
185186
186187test ( "script onerror should reset retry mechanism with next loader" , async ( ) => {
187188 const loader = new Loader ( { apiKey : "foo" , retries : 1 } ) ;
188189 const deleteScript = jest . spyOn ( loader , "deleteScript" ) ;
190+ loader . importLibrary = ( ( ) => Promise . reject ( new Error ( "fake error" ) ) ) as any ;
189191 // eslint-disable-next-line @typescript-eslint/no-empty-function
190- console . log = jest . fn ( ) ;
192+ console . error = jest . fn ( ) ;
191193
192194 let rejection = expect ( loader . load ( ) ) . rejects . toBeInstanceOf ( Error ) ;
193- loader [ "loadErrorCallback" ] (
194- new ErrorEvent ( "ErrorEvent(" , { error : new Error ( "" ) } )
195- ) ;
196- loader [ "loadErrorCallback" ] (
197- new ErrorEvent ( "ErrorEvent(" , { error : new Error ( "" ) } )
198- ) ;
195+ // wait for the first first failure
196+ await 0 ;
197+ expect ( loader [ "errors" ] . length ) . toBe ( 1 ) ;
198+ // trigger the retry delay:
199199 jest . runAllTimers ( ) ;
200200 await rejection ;
201201
202+ // try again...
202203 rejection = expect ( loader . load ( ) ) . rejects . toBeInstanceOf ( Error ) ;
203204 expect ( loader [ "done" ] ) . toBeFalsy ( ) ;
205+ expect ( loader [ "failed" ] ) . toBeFalsy ( ) ;
204206 expect ( loader [ "loading" ] ) . toBeTruthy ( ) ;
205207 expect ( loader [ "errors" ] . length ) . toBe ( 0 ) ;
206208
207- loader [ "loadErrorCallback" ] (
208- new ErrorEvent ( "ErrorEvent(" , { error : new Error ( "" ) } )
209- ) ;
210- loader [ "loadErrorCallback" ] (
211- new ErrorEvent ( "ErrorEvent(" , { error : new Error ( "" ) } )
212- ) ;
209+ // wait for the second first failure
210+ await 0 ;
211+ expect ( loader [ "errors" ] . length ) . toBe ( 1 ) ;
212+ // trigger the retry delay:
213213 jest . runAllTimers ( ) ;
214214
215215 await rejection ;
216216 expect ( deleteScript ) . toHaveBeenCalledTimes ( 3 ) ;
217- expect ( console . log ) . toHaveBeenCalledTimes ( loader . retries * 2 ) ;
217+ expect ( console . error ) . toHaveBeenCalledTimes ( loader . retries * 2 ) ;
218218} ) ;
219219
220220test ( "script onerror should not reset retry mechanism with parallel loaders" , async ( ) => {
221221 const loader = new Loader ( { apiKey : "foo" , retries : 1 } ) ;
222222 const deleteScript = jest . spyOn ( loader , "deleteScript" ) ;
223+ loader . importLibrary = ( ( ) => Promise . reject ( new Error ( "fake error" ) ) ) as any ;
223224 // eslint-disable-next-line @typescript-eslint/no-empty-function
224- console . log = jest . fn ( ) ;
225+ console . error = jest . fn ( ) ;
225226
226227 const rejection1 = expect ( loader . load ( ) ) . rejects . toBeInstanceOf ( Error ) ;
227228 const rejection2 = expect ( loader . load ( ) ) . rejects . toBeInstanceOf ( Error ) ;
228- loader [ "loadErrorCallback" ] (
229- new ErrorEvent ( "ErrorEvent(" , { error : new Error ( "" ) } )
230- ) ;
231- loader [ "loadErrorCallback" ] (
232- new ErrorEvent ( "ErrorEvent(" , { error : new Error ( "" ) } )
233- ) ;
229+ // wait for the first first failure
230+ await 0 ;
234231 jest . runAllTimers ( ) ;
235232
236233 await Promise . all ( [ rejection1 , rejection2 ] ) ;
237234 expect ( loader [ "done" ] ) . toBeTruthy ( ) ;
238235 expect ( loader [ "loading" ] ) . toBeFalsy ( ) ;
239236 expect ( loader [ "errors" ] . length ) . toBe ( 2 ) ;
240237 expect ( deleteScript ) . toHaveBeenCalledTimes ( 1 ) ;
241- expect ( console . log ) . toHaveBeenCalledTimes ( loader . retries ) ;
238+ expect ( console . error ) . toHaveBeenCalledTimes ( loader . retries ) ;
242239} ) ;
243240
244241test ( "reset should clear state" , ( ) => {
@@ -288,12 +285,12 @@ test("failed getter should be correct", () => {
288285 expect ( loader [ "failed" ] ) . toBeTruthy ( ) ;
289286} ) ;
290287
291- test ( "loader should not reset retry mechanism if successfully loaded" , ( ) => {
288+ test ( "loader should not reset retry mechanism if successfully loaded" , async ( ) => {
292289 const loader = new Loader ( { apiKey : "foo" , retries : 0 } ) ;
293290 const deleteScript = jest . spyOn ( loader , "deleteScript" ) ;
291+ loader . importLibrary = ( ( ) => Promise . resolve ( ) ) as any ;
294292
295- loader [ "done" ] = true ;
296- expect ( loader . load ( ) ) . resolves . toBeUndefined ( ) ;
293+ await expect ( loader . load ( ) ) . resolves . not . toBeUndefined ( ) ;
297294
298295 expect ( loader [ "done" ] ) . toBeTruthy ( ) ;
299296 expect ( loader [ "loading" ] ) . toBeFalsy ( ) ;
@@ -344,10 +341,11 @@ test("loader should wait if already loading", () => {
344341 loader . load ( ) ;
345342} ) ;
346343
347- test ( "setScript adds a nonce" , ( ) => {
344+ test ( "setScript adds a nonce" , async ( ) => {
348345 const nonce = "bar" ;
349346 const loader = new Loader ( { apiKey : "foo" , nonce } ) ;
350347 loader [ "setScript" ] ( ) ;
348+ await 0 ;
351349 const script = document . head . childNodes [ 0 ] as HTMLScriptElement ;
352350 expect ( script . nonce ) . toBe ( nonce ) ;
353351} ) ;
@@ -371,13 +369,25 @@ test("loader should not warn if done and google.maps is defined", async () => {
371369 expect ( console . warn ) . toHaveBeenCalledTimes ( 0 ) ;
372370} ) ;
373371
374- test ( "deleteScript removes script tag from head" , ( ) => {
372+ test ( "deleteScript removes script tag from head" , async ( ) => {
375373 const loader = new Loader ( { apiKey : "foo" } ) ;
376374 loader [ "setScript" ] ( ) ;
375+ await 0 ;
377376 expect ( document . head . childNodes . length ) . toBe ( 1 ) ;
378377 loader . deleteScript ( ) ;
379378 expect ( document . head . childNodes . length ) . toBe ( 0 ) ;
380379 // should work without script existing
381380 loader . deleteScript ( ) ;
382381 expect ( document . head . childNodes . length ) . toBe ( 0 ) ;
383382} ) ;
383+ 384+ test ( "importLibrary resolves correctly" , async ( ) => {
385+ window . google = { maps : { } } as any ;
386+ google . maps . importLibrary = async ( name ) => ( { [ name ] : "fake" } as any ) ;
387+ 388+ const loader = new Loader ( { apiKey : "foo" } ) ;
389+ const corePromise = loader . importLibrary ( "core" ) ;
390+ 391+ const core = await corePromise ;
392+ expect ( core ) . toEqual ( { core : "fake" } ) ;
393+ } ) ;
0 commit comments