12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
15
- import { getGoogleIdToken } from '../src/toolbox_core/authMethods' ;
16
15
import { GoogleAuth } from 'google-auth-library' ;
17
16
18
- jest . mock ( 'google-auth-library' , ( ) => ( { GoogleAuth : jest . fn ( ) } ) ) ;
17
+ type GetGoogleIdToken = ( url : string ) => Promise < string > ;
19
18
20
19
describe ( 'getGoogleIdToken' , ( ) => {
21
20
const mockUrl = 'https://example.com' ;
22
21
const mockToken = 'mock-id-token' ;
23
22
23
+ let getGoogleIdToken : GetGoogleIdToken ;
24
+ let MockedGoogleAuth : jest . MockedClass < typeof GoogleAuth > ;
24
25
let mockGetIdTokenClient : jest . Mock ;
25
26
let mockFetchIdToken : jest . Mock ;
26
27
27
28
beforeEach ( ( ) => {
28
- // Reset mocks before each test
29
- mockFetchIdToken = jest . fn ( ) . mockResolvedValue ( mockToken ) ;
30
- mockGetIdTokenClient = jest . fn ( ) . mockResolvedValue ( {
31
- idTokenProvider : {
32
- fetchIdToken : mockFetchIdToken ,
33
- } ,
34
- } ) ;
35
- ( GoogleAuth as jest . MockedClass < typeof GoogleAuth > ) . mockImplementation (
36
- ( ) =>
37
- ( {
29
+ jest . resetModules ( ) ;
30
+
31
+ mockFetchIdToken = jest . fn ( ) ;
32
+ mockGetIdTokenClient = jest . fn ( ) ;
33
+
34
+ jest . mock ( 'google-auth-library' , ( ) => {
35
+ return {
36
+ GoogleAuth : jest . fn ( ) . mockImplementation ( ( ) => ( {
38
37
getIdTokenClient : mockGetIdTokenClient ,
39
- } ) as unknown as GoogleAuth
40
- ) ;
38
+ } ) ) ,
39
+ } ;
40
+ } ) ;
41
+
42
+ // With the mocks fully configured, dynamically require the modules.
43
+ // This ensures our code runs against the fresh mocks we just set up.
44
+ const authMethods = require ( '../src/toolbox_core/authMethods' ) ;
45
+ const { GoogleAuth : GA } = require ( 'google-auth-library' ) ;
46
+ getGoogleIdToken = authMethods . getGoogleIdToken ;
47
+ MockedGoogleAuth = GA ;
48
+
49
+ mockGetIdTokenClient . mockResolvedValue ( {
50
+ idTokenProvider : { fetchIdToken : mockFetchIdToken } ,
51
+ } ) ;
52
+ mockFetchIdToken . mockResolvedValue ( mockToken ) ;
41
53
} ) ;
42
54
43
55
it ( 'should return a Bearer token on successful fetch' , async ( ) => {
44
56
const token = await getGoogleIdToken ( mockUrl ) ;
45
57
expect ( token ) . toBe ( `Bearer ${ mockToken } ` ) ;
46
- expect ( GoogleAuth ) . toHaveBeenCalledTimes ( 1 ) ;
58
+
59
+ expect ( MockedGoogleAuth ) . toHaveBeenCalledTimes ( 1 ) ;
47
60
expect ( mockGetIdTokenClient ) . toHaveBeenCalledWith ( mockUrl ) ;
61
+ expect ( mockGetIdTokenClient ) . toHaveBeenCalledTimes ( 1 ) ;
48
62
expect ( mockFetchIdToken ) . toHaveBeenCalledWith ( mockUrl ) ;
63
+ expect ( mockFetchIdToken ) . toHaveBeenCalledTimes ( 1 ) ;
49
64
} ) ;
50
65
51
66
it ( 'should propagate errors from getIdTokenClient' , async ( ) => {
@@ -61,4 +76,22 @@ describe('getGoogleIdToken', () => {
61
76
62
77
await expect ( getGoogleIdToken ( mockUrl ) ) . rejects . toThrow ( errorMessage ) ;
63
78
} ) ;
79
+
80
+ it ( 'should fetch the token only once when called multiple times' , async ( ) => {
81
+ const token1 = await getGoogleIdToken ( mockUrl ) ;
82
+ const token2 = await getGoogleIdToken ( mockUrl ) ;
83
+ await getGoogleIdToken ( mockUrl ) ;
84
+
85
+ expect ( token1 ) . toBe ( `Bearer ${ mockToken } ` ) ;
86
+ expect ( token2 ) . toBe ( `Bearer ${ mockToken } ` ) ;
87
+
88
+ // `GoogleAuth` constructor was only ever called once.
89
+ expect ( MockedGoogleAuth ) . toHaveBeenCalledTimes ( 1 ) ;
90
+
91
+ // The client is only fetched once.
92
+ expect ( mockGetIdTokenClient ) . toHaveBeenCalledTimes ( 1 ) ;
93
+
94
+ // With our current mock, the token fetching method is called each time.
95
+ expect ( mockFetchIdToken ) . toHaveBeenCalledTimes ( 3 ) ;
96
+ } ) ;
64
97
} ) ;
0 commit comments