33 */
44import { jest , beforeEach , afterEach } from '@jest/globals' ;
55
6+ /**
7+ * Helper to create a mock Stripe list result with autoPagingToArray
8+ */
9+ const mockListResult = ( data ) => ( {
10+ autoPagingToArray : jest . fn ( ) . mockResolvedValue ( data ) ,
11+ } ) ;
12+
613/**
714 * Unit tests for billing plans service
815 */
@@ -11,39 +18,27 @@ describe('Billing plans service unit tests:', () => {
1118 let mockConfig ;
1219 let mockStripeInstance ;
1320
14- const mockProducts = {
15- data : [
16- {
17- id : 'prod_pro' ,
18- name : 'Pro' ,
19- metadata : { planId : 'pro' } ,
20- } ,
21- {
22- id : 'prod_starter' ,
23- name : 'Starter' ,
24- metadata : { planId : 'starter' } ,
25- } ,
26- ] ,
27- } ;
28-
29- const mockAllPrices = {
30- data : [
31- { product : 'prod_starter' , recurring : { interval : 'month' } , unit_amount : 900 , id : 'price_starter_m' } ,
32- { product : 'prod_starter' , recurring : { interval : 'year' } , unit_amount : 9000 , id : 'price_starter_y' } ,
33- { product : 'prod_pro' , recurring : { interval : 'month' } , unit_amount : 2900 , id : 'price_pro_m' } ,
34- { product : 'prod_pro' , recurring : { interval : 'year' } , unit_amount : 29000 , id : 'price_pro_y' } ,
35- ] ,
36- } ;
21+ const productsData = [
22+ { id : 'prod_pro' , name : 'Pro' , metadata : { planId : 'pro' } } ,
23+ { id : 'prod_starter' , name : 'Starter' , metadata : { planId : 'starter' } } ,
24+ ] ;
25+
26+ const pricesData = [
27+ { product : 'prod_starter' , recurring : { interval : 'month' } , unit_amount : 900 , id : 'price_starter_m' } ,
28+ { product : 'prod_starter' , recurring : { interval : 'year' } , unit_amount : 9000 , id : 'price_starter_y' } ,
29+ { product : 'prod_pro' , recurring : { interval : 'month' } , unit_amount : 2900 , id : 'price_pro_m' } ,
30+ { product : 'prod_pro' , recurring : { interval : 'year' } , unit_amount : 29000 , id : 'price_pro_y' } ,
31+ ] ;
3732
3833 beforeEach ( async ( ) => {
3934 jest . resetModules ( ) ;
4035
4136 mockStripeInstance = {
4237 products : {
43- list : jest . fn ( ) . mockResolvedValue ( mockProducts ) ,
38+ list : jest . fn ( ) . mockReturnValue ( mockListResult ( productsData ) ) ,
4439 } ,
4540 prices : {
46- list : jest . fn ( ) . mockResolvedValue ( mockAllPrices ) ,
41+ list : jest . fn ( ) . mockReturnValue ( mockListResult ( pricesData ) ) ,
4742 } ,
4843 } ;
4944
@@ -122,10 +117,8 @@ describe('Billing plans service unit tests:', () => {
122117 } ) ;
123118
124119 test ( 'should fall back to product id when metadata planId is missing' , async ( ) => {
125- mockStripeInstance . products . list . mockResolvedValue ( {
126- data : [ { id : 'prod_basic' , name : 'Basic' , metadata : { } } ] ,
127- } ) ;
128- mockStripeInstance . prices . list . mockResolvedValue ( { data : [ ] } ) ;
120+ mockStripeInstance . products . list . mockReturnValue ( mockListResult ( [ { id : 'prod_basic' , name : 'Basic' , metadata : { } } ] ) ) ;
121+ mockStripeInstance . prices . list . mockReturnValue ( mockListResult ( [ ] ) ) ;
129122
130123 const mod = await import ( '../services/billing.plans.service.js' ) ;
131124 BillingPlansService = mod . default ;
@@ -145,12 +138,12 @@ describe('Billing plans service unit tests:', () => {
145138 } ) ;
146139
147140 test ( 'should handle prices without recurring interval' , async ( ) => {
148- mockStripeInstance . products . list . mockResolvedValue ( {
149- data : [ { id : 'prod_one' , name : 'OneTime' , metadata : { planId : 'one' } } ] ,
150- } ) ;
151- mockStripeInstance . prices . list . mockResolvedValue ( {
152- data : [ { product : 'prod_one' , unit_amount : 500 , id : 'price_one' } ] ,
153- } ) ;
141+ mockStripeInstance . products . list . mockReturnValue (
142+ mockListResult ( [ { id : 'prod_one' , name : 'OneTime' , metadata : { planId : 'one' } } ] ) ,
143+ ) ;
144+ mockStripeInstance . prices . list . mockReturnValue (
145+ mockListResult ( [ { product : 'prod_one' , unit_amount : 500 , id : 'price_one' } ] ) ,
146+ ) ;
154147
155148 const mod = await import ( '../services/billing.plans.service.js' ) ;
156149 BillingPlansService = mod . default ;
@@ -163,12 +156,12 @@ describe('Billing plans service unit tests:', () => {
163156 } ) ;
164157
165158 test ( 'should handle null unit_amount gracefully' , async ( ) => {
166- mockStripeInstance . products . list . mockResolvedValue ( {
167- data : [ { id : 'prod_metered' , name : 'Metered' , metadata : { planId : 'metered' } } ] ,
168- } ) ;
169- mockStripeInstance . prices . list . mockResolvedValue ( {
170- data : [ { product : 'prod_metered' , recurring : { interval : 'month' } , unit_amount : null , id : 'price_metered' } ] ,
171- } ) ;
159+ mockStripeInstance . products . list . mockReturnValue (
160+ mockListResult ( [ { id : 'prod_metered' , name : 'Metered' , metadata : { planId : 'metered' } } ] ) ,
161+ ) ;
162+ mockStripeInstance . prices . list . mockReturnValue (
163+ mockListResult ( [ { product : 'prod_metered' , recurring : { interval : 'month' } , unit_amount : null , id : 'price_metered' } ] ) ,
164+ ) ;
172165
173166 const mod = await import ( '../services/billing.plans.service.js' ) ;
174167 BillingPlansService = mod . default ;
@@ -178,14 +171,14 @@ describe('Billing plans service unit tests:', () => {
178171 expect ( plans [ 0 ] . stripePriceMonthly ) . toBe ( 'price_metered' ) ;
179172 } ) ;
180173
181- test ( 'should fetch products and prices with limit 100 ' , async ( ) => {
174+ test ( 'should use autoPagingToArray for products and prices' , async ( ) => {
182175 const mod = await import ( '../services/billing.plans.service.js' ) ;
183176 BillingPlansService = mod . default ;
184177
185178 await BillingPlansService . getPlans ( ) ;
186179
187- expect ( mockStripeInstance . products . list ) . toHaveBeenCalledWith ( { active : true , limit : 100 } ) ;
188- expect ( mockStripeInstance . prices . list ) . toHaveBeenCalledWith ( { active : true , limit : 100 } ) ;
180+ expect ( mockStripeInstance . products . list ) . toHaveBeenCalledWith ( { active : true } ) ;
181+ expect ( mockStripeInstance . prices . list ) . toHaveBeenCalledWith ( { active : true } ) ;
189182 } ) ;
190183
191184 test ( 'should only make one prices.list call regardless of product count' , async ( ) => {
@@ -196,4 +189,21 @@ describe('Billing plans service unit tests:', () => {
196189
197190 expect ( mockStripeInstance . prices . list ) . toHaveBeenCalledTimes ( 1 ) ;
198191 } ) ;
192+
193+ test ( 'should refresh cache after TTL expires' , async ( ) => {
194+ const mod = await import ( '../services/billing.plans.service.js' ) ;
195+ BillingPlansService = mod . default ;
196+
197+ await BillingPlansService . getPlans ( ) ;
198+
199+ // Advance time past TTL (1 hour)
200+ const originalDateNow = Date . now ;
201+ Date . now = jest . fn ( ) . mockReturnValue ( originalDateNow ( ) + 61 * 60 * 1000 ) ;
202+
203+ await BillingPlansService . getPlans ( ) ;
204+
205+ expect ( mockStripeInstance . products . list ) . toHaveBeenCalledTimes ( 2 ) ;
206+
207+ Date . now = originalDateNow ;
208+ } ) ;
199209} ) ;
0 commit comments