mirror of
https://github.com/saltbo/zpan.git
synced 2026-08-28 15:51:29 +08:00
b92df828ab
* ci: parallelize and isolate test suites * ci: avoid unavailable Playwright video runtime * ci: shard coverage and cache docker smoke * ci: balance Playwright shards by test * ci: smoke test the CLI container * ci: enforce merged coverage thresholds * ci: ratchet canonical coverage baseline * ci: make coverage ratchet lossless * ci: organize parallel gates by responsibility * perf(ci): reduce total runner time * perf(ci): balance runner cost and latency * perf(ci): suppress passing test logs * fix(test): make coverage sorting proof deterministic * perf(docker): exclude test-only build inputs * perf(ci): scope Docker smokes to packaging changes * refactor(test): enforce fast test boundaries * test: isolate coverage ownership * perf(test): run backend projects concurrently * perf(ci): separate test layers by runtime * perf(test): separate integration boundaries * perf(ci): prioritize test runners * docs(ci): clarify package scheduling * test: restore shared Cloudflare mocks * fix(preview): isolate Cloudflare E2E build config * fix(auth): bind preview sessions to request origin * revert: remove ineffective preview auth workaround * fix(auth): stop signing JWTs on session reads
61 lines
2.6 KiB
TypeScript
61 lines
2.6 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
|
import {
|
|
getJson,
|
|
pairAndApprove,
|
|
postJson,
|
|
signInAsAdmin,
|
|
signUpAndGoToFiles,
|
|
unbindCurrentCloudBinding,
|
|
} from './helpers'
|
|
|
|
const PLAN_NAME = 'E2E Storage Plan'
|
|
const GIFT_CARD_CODE = 'E2E-GIFT-200'
|
|
|
|
test.describe('ZPan Cloud store protocol integration', () => {
|
|
test.afterEach(async () => {
|
|
await unbindCurrentCloudBinding()
|
|
})
|
|
|
|
test('@desktop @critical pairs, browses a plan, redeems credit, and creates checkout', async ({ page }) => {
|
|
await signInAsAdmin(page)
|
|
await pairAndApprove(page)
|
|
await page.context().clearCookies()
|
|
await signUpAndGoToFiles(page)
|
|
|
|
await page.goto('/storage')
|
|
await expect(page.getByRole('heading', { name: 'Storage', exact: true })).toBeVisible()
|
|
const packages = await getJson<{ items: Array<{ id: string; name: string; prices: Array<{ id: string }> }> }>(
|
|
page,
|
|
'/api/store/packages',
|
|
)
|
|
expect(packages.items.map((item) => item.name)).toContain(PLAN_NAME)
|
|
|
|
const targets = await getJson<{ items: Array<{ orgId: string; role: string }> }>(page, '/api/store/targets')
|
|
const target = targets.items.find((item) => item.role === 'owner') ?? targets.items[0]
|
|
if (!target) throw new Error('Cloud store target is unavailable')
|
|
|
|
await page.goto(`/teams/${encodeURIComponent(target.orgId)}/billing`)
|
|
await page.getByRole('button', { name: 'Redeem gift card' }).click()
|
|
const redeemDialog = page.getByRole('dialog', { name: 'Redeem gift card' })
|
|
await redeemDialog.getByLabel('Gift card code').fill(GIFT_CARD_CODE)
|
|
const redeemResponse = page.waitForResponse(
|
|
(response) => response.url().includes('/api/store/credits/redemptions') && response.request().method() === 'POST',
|
|
)
|
|
await redeemDialog.getByRole('button', { name: 'Redeem' }).click()
|
|
expect((await redeemResponse).status()).toBe(200)
|
|
await expect(page.getByText(/Redeemed successfully/)).toBeVisible()
|
|
await expect.poll(async () => (await getJson<{ balance: number }>(page, '/api/store/credits')).balance).toBe(200)
|
|
|
|
const plan = packages.items.find((item) => item.name === PLAN_NAME)
|
|
if (!plan?.prices[0]) throw new Error('E2E plan is missing its price')
|
|
const checkout = await postJson<{ orderId: string; url: string }>(page, '/api/store/checkouts', {
|
|
packageId: plan.id,
|
|
priceId: plan.prices[0].id,
|
|
})
|
|
expect(checkout.orderId).toBe('e2e-order')
|
|
|
|
const orders = await getJson<{ items: Array<{ id: string; paymentStatus: string }> }>(page, '/api/store/orders')
|
|
expect(orders.items).toContainEqual(expect.objectContaining({ id: 'e2e-order', paymentStatus: 'pending' }))
|
|
})
|
|
})
|