Download packages/core/src/billing/billing.test.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 8.37 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/core/src/billing/billing.test.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/core/src/billing/billing.test.ts
-
curl -L -o billing.test.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/core/src/billing/billing.test.ts
8.37 kB
| /** | |
| * @license | |
| * Copyright 2026 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { describe, it, expect } from 'vitest'; | |
| import type { GeminiUserTier } from '../code_assist/types.js'; | |
| import { | |
| buildG1Url, | |
| getG1CreditBalance, | |
| G1_CREDIT_TYPE, | |
| G1_UTM_CAMPAIGNS, | |
| isOverageEligibleModel, | |
| shouldAutoUseCredits, | |
| shouldShowEmptyWalletMenu, | |
| shouldShowOverageMenu, | |
| wrapInAccountChooser, | |
| } from './billing.js'; | |
| describe('billing', () => { | |
| describe('wrapInAccountChooser', () => { | |
| it('should wrap URL with AccountChooser redirect', () => { | |
| const result = wrapInAccountChooser( | |
| 'user@gmail.com', | |
| 'https://one.google.com/ai/activity', | |
| ); | |
| expect(result).toBe( | |
| 'https://accounts.google.com/AccountChooser?Email=user%40gmail.com&continue=https%3A%2F%2Fone.google.com%2Fai%2Factivity', | |
| ); | |
| }); | |
| it('should handle special characters in email', () => { | |
| const result = wrapInAccountChooser( | |
| 'user+test@example.com', | |
| 'https://example.com', | |
| ); | |
| expect(result).toContain('Email=user%2Btest%40example.com'); | |
| }); | |
| }); | |
| describe('buildG1Url', () => { | |
| it('should build activity URL with UTM params wrapped in AccountChooser', () => { | |
| const result = buildG1Url( | |
| 'activity', | |
| 'user@gmail.com', | |
| G1_UTM_CAMPAIGNS.MANAGE_ACTIVITY, | |
| ); | |
| // Should contain AccountChooser prefix | |
| expect(result).toContain('https://accounts.google.com/AccountChooser'); | |
| expect(result).toContain('Email=user%40gmail.com'); | |
| // The continue URL should contain the G1 activity path and UTM params | |
| expect(result).toContain('one.google.com%2Fai%2Factivity'); | |
| expect(result).toContain('utm_source%3Dgemini_cli'); | |
| expect(result).toContain( | |
| 'utm_campaign%3Dhydrogen_cli_settings_ai_credits_activity_page', | |
| ); | |
| }); | |
| it('should build credits URL with UTM params wrapped in AccountChooser', () => { | |
| const result = buildG1Url( | |
| 'credits', | |
| 'test@example.com', | |
| G1_UTM_CAMPAIGNS.EMPTY_WALLET_ADD_CREDITS, | |
| ); | |
| expect(result).toContain('https://accounts.google.com/AccountChooser'); | |
| expect(result).toContain('one.google.com%2Fai%2Fcredits'); | |
| expect(result).toContain( | |
| 'utm_campaign%3Dhydrogen_cli_insufficient_credits_add_credits', | |
| ); | |
| }); | |
| }); | |
| describe('getG1CreditBalance', () => { | |
| it('should return null for null tier', () => { | |
| expect(getG1CreditBalance(null)).toBeNull(); | |
| }); | |
| it('should return null for undefined tier', () => { | |
| expect(getG1CreditBalance(undefined)).toBeNull(); | |
| }); | |
| it('should return null for tier without availableCredits', () => { | |
| const tier: GeminiUserTier = { id: 'PERSONAL' }; | |
| expect(getG1CreditBalance(tier)).toBeNull(); | |
| }); | |
| it('should return null for empty availableCredits array', () => { | |
| const tier: GeminiUserTier = { id: 'PERSONAL', availableCredits: [] }; | |
| expect(getG1CreditBalance(tier)).toBeNull(); | |
| }); | |
| it('should return null when no G1 credit type found', () => { | |
| const tier: GeminiUserTier = { | |
| id: 'PERSONAL', | |
| availableCredits: [ | |
| { creditType: 'CREDIT_TYPE_UNSPECIFIED', creditAmount: '100' }, | |
| ], | |
| }; | |
| expect(getG1CreditBalance(tier)).toBeNull(); | |
| }); | |
| it('should return G1 credit balance when present', () => { | |
| const tier: GeminiUserTier = { | |
| id: 'PERSONAL', | |
| availableCredits: [{ creditType: G1_CREDIT_TYPE, creditAmount: '500' }], | |
| }; | |
| expect(getG1CreditBalance(tier)).toBe(500); | |
| }); | |
| it('should return G1 credit balance when multiple credit types present', () => { | |
| const tier: GeminiUserTier = { | |
| id: 'PERSONAL', | |
| availableCredits: [ | |
| { creditType: 'CREDIT_TYPE_UNSPECIFIED', creditAmount: '100' }, | |
| { creditType: G1_CREDIT_TYPE, creditAmount: '750' }, | |
| ], | |
| }; | |
| expect(getG1CreditBalance(tier)).toBe(750); | |
| }); | |
| it('should return 0 for invalid credit amount', () => { | |
| const tier: GeminiUserTier = { | |
| id: 'PERSONAL', | |
| availableCredits: [ | |
| { creditType: G1_CREDIT_TYPE, creditAmount: 'invalid' }, | |
| ], | |
| }; | |
| expect(getG1CreditBalance(tier)).toBe(0); | |
| }); | |
| it('should handle large credit amounts (int64 as string)', () => { | |
| const tier: GeminiUserTier = { | |
| id: 'PERSONAL', | |
| availableCredits: [ | |
| { creditType: G1_CREDIT_TYPE, creditAmount: '9999999999' }, | |
| ], | |
| }; | |
| expect(getG1CreditBalance(tier)).toBe(9999999999); | |
| }); | |
| it('should sum multiple credits of the same G1 type', () => { | |
| const tier: GeminiUserTier = { | |
| id: 'PERSONAL', | |
| availableCredits: [ | |
| { creditType: G1_CREDIT_TYPE, creditAmount: '1000' }, | |
| { creditType: G1_CREDIT_TYPE, creditAmount: '8' }, | |
| ], | |
| }; | |
| expect(getG1CreditBalance(tier)).toBe(1008); | |
| }); | |
| }); | |
| describe('shouldAutoUseCredits', () => { | |
| it('should return true when strategy is always and balance > 0', () => { | |
| expect(shouldAutoUseCredits('always', 100)).toBe(true); | |
| }); | |
| it('should return false when strategy is always but balance is 0', () => { | |
| expect(shouldAutoUseCredits('always', 0)).toBe(false); | |
| }); | |
| it('should return false when strategy is ask', () => { | |
| expect(shouldAutoUseCredits('ask', 100)).toBe(false); | |
| }); | |
| it('should return false when strategy is never', () => { | |
| expect(shouldAutoUseCredits('never', 100)).toBe(false); | |
| }); | |
| it('should return false when creditBalance is null (ineligible)', () => { | |
| expect(shouldAutoUseCredits('always', null)).toBe(false); | |
| }); | |
| }); | |
| describe('shouldShowOverageMenu', () => { | |
| it('should return true when strategy is ask and balance > 0', () => { | |
| expect(shouldShowOverageMenu('ask', 100)).toBe(true); | |
| }); | |
| it('should return false when strategy is ask but balance is 0', () => { | |
| expect(shouldShowOverageMenu('ask', 0)).toBe(false); | |
| }); | |
| it('should return false when strategy is always', () => { | |
| expect(shouldShowOverageMenu('always', 100)).toBe(false); | |
| }); | |
| it('should return false when strategy is never', () => { | |
| expect(shouldShowOverageMenu('never', 100)).toBe(false); | |
| }); | |
| it('should return false when creditBalance is null (ineligible)', () => { | |
| expect(shouldShowOverageMenu('ask', null)).toBe(false); | |
| }); | |
| }); | |
| describe('shouldShowEmptyWalletMenu', () => { | |
| it('should return true when strategy is ask and balance is 0', () => { | |
| expect(shouldShowEmptyWalletMenu('ask', 0)).toBe(true); | |
| }); | |
| it('should return true when strategy is always and balance is 0', () => { | |
| expect(shouldShowEmptyWalletMenu('always', 0)).toBe(true); | |
| }); | |
| it('should return false when strategy is never', () => { | |
| expect(shouldShowEmptyWalletMenu('never', 0)).toBe(false); | |
| }); | |
| it('should return false when balance > 0', () => { | |
| expect(shouldShowEmptyWalletMenu('ask', 100)).toBe(false); | |
| }); | |
| it('should return false when creditBalance is null (ineligible)', () => { | |
| expect(shouldShowEmptyWalletMenu('ask', null)).toBe(false); | |
| }); | |
| }); | |
| describe('isOverageEligibleModel', () => { | |
| it('should return true for gemini-3-pro-preview', () => { | |
| expect(isOverageEligibleModel('gemini-3-pro-preview')).toBe(true); | |
| }); | |
| it('should return true for gemini-3.1-pro-preview', () => { | |
| expect(isOverageEligibleModel('gemini-3.1-pro-preview')).toBe(true); | |
| }); | |
| it('should return false for gemini-3.1-pro-preview-customtools', () => { | |
| expect(isOverageEligibleModel('gemini-3.1-pro-preview-customtools')).toBe( | |
| false, | |
| ); | |
| }); | |
| it('should return true for gemini-3-flash-preview', () => { | |
| expect(isOverageEligibleModel('gemini-3-flash-preview')).toBe(true); | |
| }); | |
| it('should return false for gemini-2.5-pro', () => { | |
| expect(isOverageEligibleModel('gemini-2.5-pro')).toBe(false); | |
| }); | |
| it('should return false for gemini-2.5-flash', () => { | |
| expect(isOverageEligibleModel('gemini-2.5-flash')).toBe(false); | |
| }); | |
| it('should return false for custom model names', () => { | |
| expect(isOverageEligibleModel('my-custom-model')).toBe(false); | |
| }); | |
| }); | |
| }); | |