From 93d52128b21606468d302155e568f3775c2d2051 Mon Sep 17 00:00:00 2001 From: KrasimirKralev <263465593+KrasimirKralev@users.noreply.github.com> Date: Fri, 21 Aug 2026 08:26:17 +0000 Subject: [PATCH] test(oauth): cover stored-credential validation guards --- tests/oauth-credential-validation.test.ts | 79 +++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/oauth-credential-validation.test.ts diff --git a/tests/oauth-credential-validation.test.ts b/tests/oauth-credential-validation.test.ts new file mode 100644 index 00000000..f09a1ad1 --- /dev/null +++ b/tests/oauth-credential-validation.test.ts @@ -0,0 +1,79 @@ +import { describe, expect, it } from 'vitest'; +import { isStoredOAuthClientInformation, isStoredOAuthTokens } from '../src/oauth-credential-validation.js'; + +function validTokens(overrides: Record = {}): unknown { + return { access_token: 'tok', token_type: 'bearer', ...overrides }; +} + +describe('isStoredOAuthTokens', () => { + it('accepts the minimal required shape', () => { + expect(isStoredOAuthTokens(validTokens())).toBe(true); + }); + + it('accepts every optional field at its valid type', () => { + expect( + isStoredOAuthTokens( + validTokens({ + refresh_token: 'refresh', + scope: 'read write', + issuer: 'https://issuer.example', + expires_in: 3600, + expires_at: 1_700_000_000, + expiresAt: 1_700_000_000, + }) + ) + ).toBe(true); + }); + + it('rejects non-record inputs', () => { + expect(isStoredOAuthTokens(null)).toBe(false); + expect(isStoredOAuthTokens(undefined)).toBe(false); + expect(isStoredOAuthTokens('bearer')).toBe(false); + expect(isStoredOAuthTokens(42)).toBe(false); + expect(isStoredOAuthTokens(['access_token'])).toBe(false); + }); + + it('rejects a missing, empty, or non-string access_token', () => { + expect(isStoredOAuthTokens({ token_type: 'bearer' })).toBe(false); + expect(isStoredOAuthTokens(validTokens({ access_token: '' }))).toBe(false); + expect(isStoredOAuthTokens(validTokens({ access_token: 123 }))).toBe(false); + }); + + it('rejects a missing, empty, or non-string token_type', () => { + expect(isStoredOAuthTokens({ access_token: 'tok' })).toBe(false); + expect(isStoredOAuthTokens(validTokens({ token_type: '' }))).toBe(false); + expect(isStoredOAuthTokens(validTokens({ token_type: 123 }))).toBe(false); + }); + + it('rejects an optional string field carrying a non-string value', () => { + expect(isStoredOAuthTokens(validTokens({ refresh_token: 1 }))).toBe(false); + expect(isStoredOAuthTokens(validTokens({ scope: 1 }))).toBe(false); + expect(isStoredOAuthTokens(validTokens({ issuer: 1 }))).toBe(false); + }); + + it('rejects an optional numeric field carrying a non-finite or non-number value', () => { + expect(isStoredOAuthTokens(validTokens({ expires_in: Number.NaN }))).toBe(false); + expect(isStoredOAuthTokens(validTokens({ expires_in: Number.POSITIVE_INFINITY }))).toBe(false); + expect(isStoredOAuthTokens(validTokens({ expires_in: '3600' }))).toBe(false); + expect(isStoredOAuthTokens(validTokens({ expires_at: Number.NaN }))).toBe(false); + expect(isStoredOAuthTokens(validTokens({ expiresAt: Number.NaN }))).toBe(false); + }); +}); + +describe('isStoredOAuthClientInformation', () => { + it('rejects non-record inputs', () => { + expect(isStoredOAuthClientInformation(null)).toBe(false); + expect(isStoredOAuthClientInformation('issuer')).toBe(false); + expect(isStoredOAuthClientInformation(['issuer'])).toBe(false); + }); + + it('accepts a record with no issuer or a string issuer', () => { + expect(isStoredOAuthClientInformation({})).toBe(true); + expect(isStoredOAuthClientInformation({ client_id: 'abc' })).toBe(true); + expect(isStoredOAuthClientInformation({ issuer: 'https://issuer.example' })).toBe(true); + }); + + it('rejects a record whose issuer is present but not a string', () => { + expect(isStoredOAuthClientInformation({ issuer: 42 })).toBe(false); + }); +});