1
+ /**
2
+ * @license
3
+ * Copyright 2020 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ import { FirebaseError } from '@firebase/util' ;
19
+ import { expect , use } from 'chai' ;
20
+ import * as chaiAsPromised from 'chai-as-promised' ;
21
+ import { SinonStub , stub , useFakeTimers } from 'sinon' ;
22
+ import { DEFAULT_API_TIMEOUT , Endpoint , HttpMethod , performApiRequest } from '.' ;
23
+ import { mockEndpoint } from '../../test/api/helper' ;
24
+ import { mockAuth } from '../../test/mock_auth' ;
25
+ import * as mockFetch from '../../test/mock_fetch' ;
26
+ import { ServerError } from './errors' ;
27
+ import { AuthErrorCode } from '../core/errors' ;
28
+
29
+ use ( chaiAsPromised ) ;
30
+
31
+ describe ( 'performApiRequest' , ( ) => {
32
+ const request = {
33
+ requestKey : 'request-value'
34
+ } ;
35
+
36
+ const serverResponse = {
37
+ responseKey : 'response-value'
38
+ } ;
39
+
40
+ context ( 'with regular requests' , ( ) => {
41
+ beforeEach ( mockFetch . setUp ) ;
42
+ afterEach ( mockFetch . tearDown ) ;
43
+
44
+ it ( 'should set the correct request, method and HTTP Headers' , async ( ) => {
45
+ const mock = mockEndpoint ( Endpoint . SIGN_UP , serverResponse ) ;
46
+ const response = await performApiRequest < typeof request , typeof serverResponse > ( mockAuth , HttpMethod . POST , Endpoint . SIGN_UP , request ) ;
47
+ expect ( response ) . to . eql ( serverResponse ) ;
48
+ expect ( mock . calls . length ) . to . eq ( 1 ) ;
49
+ expect ( mock . calls [ 0 ] . method ) . to . eq ( HttpMethod . POST ) ;
50
+ expect ( mock . calls [ 0 ] . request ) . to . eql ( request ) ;
51
+ expect ( mock . calls [ 0 ] . headers ) . to . eql ( {
52
+ 'Content-Type' : 'application/json'
53
+ } ) ;
54
+ } ) ;
55
+
56
+ it ( 'should translate server errors to auth errors' , async ( ) => {
57
+ const mock = mockEndpoint (
58
+ Endpoint . SIGN_UP ,
59
+ {
60
+ error : {
61
+ code : 400 ,
62
+ message : ServerError . EMAIL_EXISTS ,
63
+ errors : [
64
+ {
65
+ message : ServerError . EMAIL_EXISTS
66
+ }
67
+ ]
68
+ }
69
+ } ,
70
+ 400
71
+ ) ;
72
+ const promise = performApiRequest < typeof request , typeof serverResponse > ( mockAuth , HttpMethod . POST , Endpoint . SIGN_UP , request ) ;
73
+ await expect ( promise ) . to . be . rejectedWith (
74
+ FirebaseError ,
75
+ 'Firebase: The email address is already in use by another account. (auth/email-already-in-use).'
76
+ ) ;
77
+ expect ( mock . calls [ 0 ] . request ) . to . eql ( request ) ;
78
+ } ) ;
79
+
80
+ it ( 'should handle unknown server errors' , async ( ) => {
81
+ const mock = mockEndpoint (
82
+ Endpoint . SIGN_UP ,
83
+ {
84
+ error : {
85
+ code : 400 ,
86
+ message : 'Awesome error' ,
87
+ errors : [
88
+ {
89
+ message : 'Awesome error'
90
+ }
91
+ ]
92
+ }
93
+ } ,
94
+ 400
95
+ ) ;
96
+ const promise = performApiRequest < typeof request , typeof serverResponse > ( mockAuth , HttpMethod . POST , Endpoint . SIGN_UP , request ) ;
97
+ await expect ( promise ) . to . be . rejectedWith (
98
+ FirebaseError ,
99
+ 'Firebase: An internal AuthError has occurred. (auth/internal-error).'
100
+ ) ;
101
+ expect ( mock . calls [ 0 ] . request ) . to . eql ( request ) ;
102
+ } ) ;
103
+
104
+ it ( 'should support custom error handling per endpoint' , async ( ) => {
105
+ const mock = mockEndpoint (
106
+ Endpoint . SIGN_UP ,
107
+ {
108
+ error : {
109
+ code : 400 ,
110
+ message : ServerError . EMAIL_EXISTS ,
111
+ errors : [
112
+ {
113
+ message : ServerError . EMAIL_EXISTS
114
+ }
115
+ ]
116
+ }
117
+ } ,
118
+ 400
119
+ ) ;
120
+ const promise = performApiRequest < typeof request , typeof serverResponse > ( mockAuth , HttpMethod . POST , Endpoint . SIGN_UP , request , { [ ServerError . EMAIL_EXISTS ] : AuthErrorCode . ARGUMENT_ERROR } ) ;
121
+ await expect ( promise ) . to . be . rejectedWith (
122
+ FirebaseError ,
123
+ 'Firebase: Error (auth/argument-error).'
124
+ ) ;
125
+ expect ( mock . calls [ 0 ] . request ) . to . eql ( request ) ;
126
+ } ) ;
127
+ } ) ;
128
+
129
+ context ( 'with network issues' , ( ) => {
130
+ let fetchStub : SinonStub ;
131
+
132
+ beforeEach ( ( ) => {
133
+ fetchStub = stub ( self , 'fetch' ) ;
134
+ } ) ;
135
+
136
+ afterEach ( ( ) => {
137
+ fetchStub . restore ( ) ;
138
+ } ) ;
139
+
140
+ it ( 'should handle timeouts' , async ( ) => {
141
+ const clock = useFakeTimers ( ) ;
142
+ fetchStub . callsFake ( ( ) => {
143
+ return new Promise < never > ( ( ) => null ) ;
144
+ } ) ;
145
+ const promise = performApiRequest < typeof request , never > ( mockAuth , HttpMethod . POST , Endpoint . SIGN_UP , request ) ;
146
+ clock . tick ( DEFAULT_API_TIMEOUT + 1 ) ;
147
+ await expect ( promise ) . to . be . rejectedWith ( FirebaseError , 'Firebase: The operation has timed out. (auth/timeout).' ) ;
148
+ clock . restore ( ) ;
149
+ } ) ;
150
+
151
+ it ( 'should handle network failure' , async ( ) => {
152
+ fetchStub . callsFake ( ( ) => {
153
+ return new Promise < never > ( ( _ , reject ) => reject ( new Error ( 'network error' ) ) ) ;
154
+ } ) ;
155
+ const promise = performApiRequest < typeof request , never > ( mockAuth , HttpMethod . POST , Endpoint . SIGN_UP , request ) ;
156
+ await expect ( promise ) . to . be . rejectedWith ( FirebaseError , 'Firebase: A network AuthError (such as timeout]: interrupted connection or unreachable host) has occurred. (auth/network-request-failed).' ) ;
157
+ } ) ;
158
+ } ) ;
159
+ } ) ;
0 commit comments