|
13 | 13 | // limitations under the License. |
14 | 14 |
|
15 | 15 | import * as assert from 'assert'; |
16 | | -import {describe, it} from 'mocha'; |
| 16 | +import {describe, it, beforeEach, afterEach} from 'mocha'; |
| 17 | +import * as sinon from 'sinon'; |
17 | 18 | import { |
18 | 19 | GoogleToken, |
19 | 20 | TokenOptions, |
20 | 21 | Transporter, |
| 22 | + TokenData, |
21 | 23 | } from '../../src/gtoken/googleToken'; |
22 | | -import {GaxiosOptions, GaxiosResponse, request} from 'gaxios'; |
| 24 | +import {GaxiosOptions, GaxiosResponse} from 'gaxios'; |
| 25 | +import * as tokenHandler from '../../src/gtoken/tokenHandler'; |
| 26 | +import * as revokeTokenModule from '../../src/gtoken/revokeToken'; |
23 | 27 |
|
24 | 28 | describe('GoogleToken', () => { |
| 29 | + const sandbox = sinon.createSandbox(); |
| 30 | + let tokenHandlerStub: sinon.SinonStubbedInstance<tokenHandler.TokenHandler>; |
| 31 | + let revokeTokenStub: sinon.SinonStub; |
| 32 | + |
| 33 | + beforeEach(() => { |
| 34 | + // Stub the TokenHandler constructor to control its behavior |
| 35 | + tokenHandlerStub = sandbox.createStubInstance(tokenHandler.TokenHandler); |
| 36 | + sandbox.stub(tokenHandler, 'TokenHandler').returns(tokenHandlerStub); |
| 37 | + revokeTokenStub = sandbox.stub(revokeTokenModule, 'revokeToken'); |
| 38 | + }); |
| 39 | + |
| 40 | + afterEach(() => { |
| 41 | + sandbox.restore(); |
| 42 | + }); |
| 43 | + |
25 | 44 | it('should initialize with default options if none are provided', () => { |
26 | 45 | const token: GoogleToken = new GoogleToken(); |
27 | 46 | const options: TokenOptions = token.googleTokenOptions; |
@@ -60,6 +79,30 @@ describe('GoogleToken', () => { |
60 | 79 | assert.ok(typeof options.transporter.request === 'function'); |
61 | 80 | }); |
62 | 81 |
|
| 82 | + it('should set iss from email if provided', () => { |
| 83 | + const providedOptions: TokenOptions = { |
| 84 | + |
| 85 | + }; |
| 86 | + const token: GoogleToken = new GoogleToken(providedOptions); |
| 87 | + const options: TokenOptions = token.googleTokenOptions; |
| 88 | + assert.strictEqual(options.iss, '[email protected]'); |
| 89 | + }); |
| 90 | + |
| 91 | + it('should not override iss with email if both are provided', () => { |
| 92 | + const providedOptions: TokenOptions = { |
| 93 | + |
| 94 | + |
| 95 | + }; |
| 96 | + const token: GoogleToken = new GoogleToken(providedOptions); |
| 97 | + const options: TokenOptions = token.googleTokenOptions; |
| 98 | + assert.strictEqual(options.iss, '[email protected]'); |
| 99 | + }); |
| 100 | + |
| 101 | + it('should convert array of scopes to a space-delimited string', () => { |
| 102 | + const token = new GoogleToken({scope: ['scope1', 'scope2']}); |
| 103 | + assert.strictEqual(token.googleTokenOptions.scope, 'scope1 scope2'); |
| 104 | + }); |
| 105 | + |
63 | 106 | it('should use a custom transporter if provided in options', () => { |
64 | 107 | const customTransporter: Transporter = { |
65 | 108 | request: async <T>(opts: GaxiosOptions) => { |
@@ -89,4 +132,122 @@ describe('GoogleToken', () => { |
89 | 132 | providedOptions.email, |
90 | 133 | ); |
91 | 134 | }); |
| 135 | + |
| 136 | + describe('Getters', () => { |
| 137 | + it('should return undefined for token properties if no token is set', () => { |
| 138 | + const token = new GoogleToken(); |
| 139 | + assert.strictEqual(token.accessToken, undefined); |
| 140 | + assert.strictEqual(token.idToken, undefined); |
| 141 | + assert.strictEqual(token.tokenType, undefined); |
| 142 | + assert.strictEqual(token.refreshToken, undefined); |
| 143 | + }); |
| 144 | + |
| 145 | + it('should return correct values from the cached token', () => { |
| 146 | + const tokenData: TokenData = { |
| 147 | + access_token: 'access', |
| 148 | + id_token: 'id', |
| 149 | + token_type: 'Bearer', |
| 150 | + refresh_token: 'refresh', |
| 151 | + }; |
| 152 | + tokenHandlerStub.token = tokenData; |
| 153 | + const token = new GoogleToken(); |
| 154 | + assert.strictEqual(token.accessToken, 'access'); |
| 155 | + assert.strictEqual(token.idToken, 'id'); |
| 156 | + assert.strictEqual(token.tokenType, 'Bearer'); |
| 157 | + assert.strictEqual(token.refreshToken, 'refresh'); |
| 158 | + }); |
| 159 | + }); |
| 160 | + |
| 161 | + describe('Expiration methods', () => { |
| 162 | + it('should delegate hasExpired to the token handler', () => { |
| 163 | + tokenHandlerStub.hasExpired.returns(true); |
| 164 | + const token = new GoogleToken(); |
| 165 | + assert.strictEqual(token.hasExpired(), true); |
| 166 | + assert.ok(tokenHandlerStub.hasExpired.calledOnce); |
| 167 | + }); |
| 168 | + |
| 169 | + it('should delegate isTokenExpiring to the token handler', () => { |
| 170 | + tokenHandlerStub.isTokenExpiring.returns(false); |
| 171 | + const token = new GoogleToken(); |
| 172 | + assert.strictEqual(token.isTokenExpiring(), false); |
| 173 | + assert.ok(tokenHandlerStub.isTokenExpiring.calledOnce); |
| 174 | + }); |
| 175 | + }); |
| 176 | + |
| 177 | + describe('getToken', () => { |
| 178 | + it('should call tokenHandler.getToken and return a promise', async () => { |
| 179 | + const tokenData: TokenData = {access_token: 'new-token'}; |
| 180 | + tokenHandlerStub.getToken.resolves(tokenData); |
| 181 | + const token = new GoogleToken(); |
| 182 | + const result = await token.getToken({forceRefresh: true}); |
| 183 | + assert.strictEqual(result, tokenData); |
| 184 | + assert.ok(tokenHandlerStub.getToken.calledOnceWith(true)); |
| 185 | + }); |
| 186 | + |
| 187 | + it('should work with a callback on success', done => { |
| 188 | + const tokenData: TokenData = {access_token: 'new-token'}; |
| 189 | + tokenHandlerStub.getToken.resolves(tokenData); |
| 190 | + const token = new GoogleToken(); |
| 191 | + token.getToken((err, result) => { |
| 192 | + assert.ifError(err); |
| 193 | + assert.strictEqual(result, tokenData); |
| 194 | + assert.ok(tokenHandlerStub.getToken.calledOnceWith(false)); |
| 195 | + done(); |
| 196 | + }); |
| 197 | + }); |
| 198 | + |
| 199 | + it('should work with a callback on error', done => { |
| 200 | + const error = new Error('getToken failed'); |
| 201 | + tokenHandlerStub.getToken.rejects(error); |
| 202 | + const token = new GoogleToken(); |
| 203 | + token.getToken((err, result) => { |
| 204 | + assert.strictEqual(err, error); |
| 205 | + assert.strictEqual(result, undefined); |
| 206 | + done(); |
| 207 | + }); |
| 208 | + }); |
| 209 | + }); |
| 210 | + |
| 211 | + describe('revokeToken', () => { |
| 212 | + it('should call revokeToken and reset the handler', async () => { |
| 213 | + const tokenData: TokenData = {access_token: 'token-to-revoke'}; |
| 214 | + tokenHandlerStub.token = tokenData; |
| 215 | + revokeTokenStub.resolves(); |
| 216 | + const token = new GoogleToken(); |
| 217 | + await token.revokeToken(); |
| 218 | + assert.ok(revokeTokenStub.calledOnceWith('token-to-revoke')); |
| 219 | + // Check that a new handler was created (initial creation + reset) |
| 220 | + assert.ok( |
| 221 | + (tokenHandler.TokenHandler as unknown as sinon.SinonStub).calledTwice, |
| 222 | + ); |
| 223 | + }); |
| 224 | + |
| 225 | + it('should reject if there is no token to revoke', async () => { |
| 226 | + const token = new GoogleToken(); |
| 227 | + await assert.rejects(() => token.revokeToken(), /No token to revoke/); |
| 228 | + }); |
| 229 | + |
| 230 | + it('should work with a callback on success', done => { |
| 231 | + const tokenData: TokenData = {access_token: 'token-to-revoke'}; |
| 232 | + tokenHandlerStub.token = tokenData; |
| 233 | + revokeTokenStub.resolves(); |
| 234 | + const token = new GoogleToken(); |
| 235 | + token.revokeToken(err => { |
| 236 | + assert.ifError(err); |
| 237 | + assert.ok(revokeTokenStub.calledOnce); |
| 238 | + done(); |
| 239 | + }); |
| 240 | + }); |
| 241 | + |
| 242 | + it('should work with a callback on error', done => { |
| 243 | + const error = new Error('Revoke failed'); |
| 244 | + revokeTokenStub.rejects(error); |
| 245 | + tokenHandlerStub.token = {access_token: 'token'}; |
| 246 | + const token = new GoogleToken(); |
| 247 | + token.revokeToken(err => { |
| 248 | + assert.strictEqual(err, error); |
| 249 | + done(); |
| 250 | + }); |
| 251 | + }); |
| 252 | + }); |
92 | 253 | }); |
0 commit comments