1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15- import { getGoogleIdToken } from '../src/toolbox_core/authMethods' ;
1615import { GoogleAuth } from 'google-auth-library' ;
1716
18- jest . mock ( 'google-auth-library' , ( ) => ( { GoogleAuth : jest . fn ( ) } ) ) ;
17+ type GetGoogleIdToken = ( url : string ) => Promise < string > ;
1918
2019describe ( 'getGoogleIdToken' , ( ) => {
2120 const mockUrl = 'https://example.com' ;
2221 const mockToken = 'mock-id-token' ;
2322
23+ let getGoogleIdToken : GetGoogleIdToken ;
24+ let MockedGoogleAuth : jest . MockedClass < typeof GoogleAuth > ;
2425 let mockGetIdTokenClient : jest . Mock ;
2526 let mockFetchIdToken : jest . Mock ;
2627
2728 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 ( ( ) => ( {
3837 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 ) ;
4153 } ) ;
4254
4355 it ( 'should return a Bearer token on successful fetch' , async ( ) => {
4456 const token = await getGoogleIdToken ( mockUrl ) ;
4557 expect ( token ) . toBe ( `Bearer ${ mockToken } ` ) ;
46- expect ( GoogleAuth ) . toHaveBeenCalledTimes ( 1 ) ;
58+
59+ expect ( MockedGoogleAuth ) . toHaveBeenCalledTimes ( 1 ) ;
4760 expect ( mockGetIdTokenClient ) . toHaveBeenCalledWith ( mockUrl ) ;
61+ expect ( mockGetIdTokenClient ) . toHaveBeenCalledTimes ( 1 ) ;
4862 expect ( mockFetchIdToken ) . toHaveBeenCalledWith ( mockUrl ) ;
63+ expect ( mockFetchIdToken ) . toHaveBeenCalledTimes ( 1 ) ;
4964 } ) ;
5065
5166 it ( 'should propagate errors from getIdTokenClient' , async ( ) => {
@@ -61,4 +76,22 @@ describe('getGoogleIdToken', () => {
6176
6277 await expect ( getGoogleIdToken ( mockUrl ) ) . rejects . toThrow ( errorMessage ) ;
6378 } ) ;
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+ } ) ;
6497} ) ;
0 commit comments