11import { expect } from '@playwright/test'
22import type { Page } from '@playwright/test'
33
4- import type { CloudSubscriptionStatusResponse } from '@/platform/cloud/subscription/composables/useSubscription'
54import type { RemoteConfig } from '@/platform/remoteConfig/types'
5+ import {
6+ PENDING_SUBSCRIPTION_CHECKOUT_EVENT ,
7+ PENDING_SUBSCRIPTION_CHECKOUT_STORAGE_KEY
8+ } from '@/platform/cloud/subscription/utils/subscriptionCheckoutTracker'
69import type {
710 BillingBalanceResponse ,
811 BillingStatusResponse
@@ -33,21 +36,6 @@ const jsonRoute = (body: unknown) => ({
3336 body : JSON . stringify ( body )
3437} )
3538
36- // The workspace `/api/billing/status` shape mirrors the legacy subscription
37- // status; map the fields so a single test fixture drives both backends.
38- const toWorkspaceStatus = (
39- s : CloudSubscriptionStatusResponse
40- ) : BillingStatusResponse => ( {
41- is_active : s . is_active ?? false ,
42- max_seats : 1 ,
43- occupied_seats : 1 ,
44- subscription_tier : s . subscription_tier ?? undefined ,
45- subscription_duration : s . subscription_duration ?? undefined ,
46- renewal_date : s . renewal_date ?? undefined ,
47- cancel_at : s . end_date ?? undefined ,
48- has_funds : s . has_fund ?? true
49- } )
50-
5139const mockBalance : BillingBalanceResponse = {
5240 amount_micros : 6000 , // -> 12,660 credits
5341 currency : 'usd' ,
@@ -62,7 +50,7 @@ const mockWorkspaceBalance: BillingBalanceResponse = {
6250
6351async function mockCloudBoot (
6452 page : Page ,
65- subscriptionStatus : CloudSubscriptionStatusResponse ,
53+ subscriptionStatus : BillingStatusResponse ,
6654 remoteConfig : RemoteConfig = { } ,
6755 billingRail ?: BillingStatusResponse [ 'billing_rail' ]
6856) {
@@ -117,22 +105,21 @@ async function mockCloudBoot(
117105 )
118106 )
119107
120- // Legacy endpoints remain mocked for consumers that explicitly use them.
121- await page . route ( '**/customers/cloud-subscription-status' , ( r ) => {
122- billingRequests . legacyStatus ++
123- return r . fulfill ( jsonRoute ( subscriptionStatus ) )
124- } )
125108 await page . route ( '**/customers/balance' , ( r ) => {
126109 billingRequests . legacyBalance ++
127110 return r . fulfill ( jsonRoute ( mockBalance ) )
128111 } )
112+ await page . route ( '**/customers/cloud-subscription-status' , ( r ) => {
113+ billingRequests . legacyStatus ++
114+ return r . fulfill ( jsonRoute ( subscriptionStatus ) )
115+ } )
129116
130117 // Cloud personal workspaces route through `/api/billing/*`.
131118 await page . route ( '**/api/billing/status' , ( r ) => {
132119 billingRequests . workspaceStatus ++
133120 return r . fulfill (
134121 jsonRoute ( {
135- ...toWorkspaceStatus ( subscriptionStatus ) ,
122+ ...subscriptionStatus ,
136123 billing_rail : billingRail
137124 } )
138125 )
@@ -174,21 +161,42 @@ test.describe('Billing facade consumers (FE-933)', { tag: '@cloud' }, () => {
174161 subscription_tier : 'PRO' ,
175162 subscription_duration : 'MONTHLY' ,
176163 renewal_date : '2099-02-20T10:00:00Z' ,
177- end_date : null
164+ has_funds : true
178165 } ,
179166 { consolidated_billing_enabled : true } ,
180167 'legacy_stripe'
181168 )
182169 await bootApp ( page )
170+ await expect . poll ( ( ) => billingRequests . workspaceStatus ) . toBeGreaterThan ( 1 )
183171
184172 await page . getByRole ( 'button' , { name : 'Current user' } ) . click ( )
185173 const popover = page . locator ( '.current-user-popover' )
186174 await expect ( popover ) . toBeVisible ( )
175+ await expect ( popover . getByText ( '12,660' ) ) . toBeVisible ( )
176+
177+ await page . evaluate ( ( storageKey ) => {
178+ localStorage . setItem (
179+ storageKey ,
180+ JSON . stringify ( {
181+ attempt_id : 'rail-selection-regression' ,
182+ started_at_ms : Date . now ( ) ,
183+ tier : 'pro' ,
184+ cycle : 'monthly' ,
185+ checkout_type : 'change'
186+ } )
187+ )
188+ } , PENDING_SUBSCRIPTION_CHECKOUT_STORAGE_KEY )
189+ billingRequests . workspaceStatus = 0
190+ await page . evaluate (
191+ ( eventName ) => window . dispatchEvent ( new Event ( eventName ) ) ,
192+ PENDING_SUBSCRIPTION_CHECKOUT_EVENT
193+ )
187194
188195 await expect ( popover . getByText ( '12,660' ) ) . toBeVisible ( )
196+ await expect ( popover . getByText ( '0' , { exact : true } ) ) . toHaveCount ( 0 )
189197 await expect ( popover . getByTestId ( 'add-credits-button' ) ) . toBeVisible ( )
190- expect ( billingRequests . workspaceStatus ) . toBeGreaterThan ( 0 )
191- expect ( billingRequests . legacyStatus ) . toBeGreaterThan ( 0 )
198+ await expect . poll ( ( ) => billingRequests . workspaceStatus ) . toBeGreaterThan ( 0 )
199+ expect ( billingRequests . legacyStatus ) . toBe ( 0 )
192200 expect ( billingRequests . legacyBalance ) . toBeGreaterThan ( 0 )
193201 } )
194202
@@ -211,12 +219,13 @@ test.describe('Billing facade consumers (FE-933)', { tag: '@cloud' }, () => {
211219 subscription_duration : 'MONTHLY' ,
212220 // 10:00Z keeps the en-US calendar date stable across CI timezones.
213221 renewal_date : '2099-02-20T10:00:00Z' ,
214- end_date : null
222+ has_funds : false
215223 } ,
216224 {
217225 subscription_required : true ,
218226 consolidated_billing_enabled : true
219- }
227+ } ,
228+ 'stripe'
220229 )
221230 await bootApp ( page )
222231
0 commit comments