chore: Jest to vitestga!
This commit is contained in:
@ -1,3 +0,0 @@
|
||||
{
|
||||
"presets": ["babel-preset-vite"]
|
||||
}
|
@ -1,299 +0,0 @@
|
||||
// Test runner
|
||||
import {expect, test, beforeAll, afterEach, afterAll} from '@jest/globals';
|
||||
|
||||
// Render mocking, DOM querying
|
||||
import {act, render, within} from '@testing-library/react'
|
||||
import '@testing-library/jest-dom' // Required for .toHaveStyle
|
||||
|
||||
// Request mocking
|
||||
import {http, HttpResponse} from 'msw'
|
||||
import {setupServer} from 'msw/node'
|
||||
|
||||
// React and XState code to test
|
||||
import { Models } from '@kittycad/lib'
|
||||
import { createActor } from 'xstate'
|
||||
import {
|
||||
BillingRemaining,
|
||||
BillingRemainingMode,
|
||||
} from '@src/components/BillingRemaining'
|
||||
import { BillingDialog, } from '@src/components/BillingDialog'
|
||||
import { BILLING_CONTEXT_DEFAULTS, billingMachine, BillingTransition } from '@src/machines/billingMachine'
|
||||
|
||||
// Setup basic request mocking
|
||||
const server = setupServer()
|
||||
beforeAll(() => server.listen())
|
||||
afterEach(() => server.resetHandlers())
|
||||
afterAll(() => server.close())
|
||||
|
||||
// Data ripped from docs.zoo.dev
|
||||
const createUserPaymentBalanceResponse = (opts: {
|
||||
monthlyApiCreditsRemaining,
|
||||
stableApiCreditsRemaining,
|
||||
}): Models['CustomerBalance_type'] => ({
|
||||
"created_at": "2025-05-05T16:05:47.317Z",
|
||||
"id": "de607b7e-90ba-4977-8561-16e8a9ea0e50",
|
||||
"map_id": "d7f7de34-9bc3-4b8b-9951-cdee03fc792d",
|
||||
"modeling_app_enterprise_price": {
|
||||
"type": "enterprise"
|
||||
},
|
||||
"monthly_api_credits_remaining": opts.monthlyApiCreditsRemaining,
|
||||
"monthly_api_credits_remaining_monetary_value": "22.47",
|
||||
"stable_api_credits_remaining": opts.stableApiCreditsRemaining,
|
||||
"stable_api_credits_remaining_monetary_value": "18.91",
|
||||
"subscription_details": undefined,
|
||||
"subscription_id": "Hnd3jalJkHA3lb1YexOTStZtPYHTM",
|
||||
"total_due": "100.08",
|
||||
"updated_at": "2025-05-05T16:05:47.317Z"
|
||||
})
|
||||
|
||||
const createOrgResponse = (opts: {
|
||||
}): Models['Org_type'] => ({
|
||||
"allow_users_in_domain_to_auto_join": true,
|
||||
"billing_email": "m@dN9MCH.com",
|
||||
"billing_email_verified": "2025-05-05T18:52:02.021Z",
|
||||
"block": "payment_method_failed",
|
||||
"can_train_on_data": true,
|
||||
"created_at": "2025-05-05T18:52:02.021Z",
|
||||
"domain": "Ctxde1hpG8xTvvlef5SEPm7",
|
||||
"id": "78432284-8660-46bf-ac65-d00bf9b18c3e",
|
||||
"image": "https://Rt0.yK.com/R2SoRtl/tpUdckyDJ",
|
||||
"name": "AevRR4w42KdkA487dh",
|
||||
"phone": "+1-696-641-2790",
|
||||
"stripe_id": "sCfjVscpLyOBYUWO7Vlx",
|
||||
"updated_at": "2025-05-05T18:52:02.021Z"
|
||||
})
|
||||
|
||||
const createUserPaymentSubscriptionsResponse = (opts: {
|
||||
monthlyPayAsYouGoApiCreditsTotal,
|
||||
name,
|
||||
}): Models['ZooProductSubscriptions_type'] => ({
|
||||
"modeling_app": {
|
||||
"annual_discount": 10,
|
||||
"description": "1ztERftrU3L3yOnv5epTLcM",
|
||||
"endpoints_included": [
|
||||
"modeling"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"info": "zZcZKHejXabT5HMZDkSkDGD2bfzkAt"
|
||||
}
|
||||
],
|
||||
"monthly_pay_as_you_go_api_credits": opts.monthlyPayAsYouGoApiCreditsTotal,
|
||||
"monthly_pay_as_you_go_api_credits_monetary_value": "55.85",
|
||||
"name": opts.name,
|
||||
"pay_as_you_go_api_credit_price": "18.49",
|
||||
"price": {
|
||||
"interval": "year",
|
||||
"price": "50.04",
|
||||
"type": "per_user"
|
||||
},
|
||||
"share_links": [
|
||||
"password_protected"
|
||||
],
|
||||
"support_tier": "community",
|
||||
"training_data_behavior": "default_on",
|
||||
"type": {
|
||||
"saml_sso": true,
|
||||
"type": "organization"
|
||||
},
|
||||
"zoo_tools_included": [
|
||||
"text_to_cad"
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
test('Shows a loading spinner when uninitialized credit count', async () => {
|
||||
server.use(
|
||||
http.get('*/user/payment/balance', (req, res, ctx) => {
|
||||
return HttpResponse.json({})
|
||||
}),
|
||||
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
|
||||
return HttpResponse.json({})
|
||||
}),
|
||||
http.get('*/org', (req, res, ctx) => {
|
||||
return new HttpResponse(403)
|
||||
}),
|
||||
)
|
||||
|
||||
const billingActor = createActor(billingMachine, { input: BILLING_CONTEXT_DEFAULTS }).start()
|
||||
|
||||
const { queryByTestId } = render(<BillingRemaining
|
||||
mode={BillingRemainingMode.ProgressBarFixed}
|
||||
billingActor={billingActor}
|
||||
/>)
|
||||
|
||||
await expect(queryByTestId('spinner')).toBeVisible()
|
||||
})
|
||||
|
||||
test('Shows the total credits for Unknown subscription', async () => {
|
||||
const data = {
|
||||
balance: {
|
||||
monthlyApiCreditsRemaining: 10,
|
||||
stableApiCreditsRemaining: 25,
|
||||
},
|
||||
subscriptions: {
|
||||
monthlyPayAsYouGoApiCreditsTotal: 20,
|
||||
name: "unknown",
|
||||
}
|
||||
}
|
||||
|
||||
server.use(
|
||||
http.get('*/user/payment/balance', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
|
||||
}),
|
||||
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentSubscriptionsResponse(data.subscriptions))
|
||||
}),
|
||||
http.get('*/org', (req, res, ctx) => {
|
||||
return new HttpResponse(403)
|
||||
}),
|
||||
)
|
||||
|
||||
const billingActor = createActor(billingMachine, { input: BILLING_CONTEXT_DEFAULTS }).start()
|
||||
|
||||
const { queryByTestId } = render(<BillingRemaining
|
||||
mode={BillingRemainingMode.ProgressBarFixed}
|
||||
billingActor={billingActor}
|
||||
/>)
|
||||
|
||||
await act(() => {
|
||||
billingActor.send({ type: BillingTransition.Update, apiToken: "it doesn't matter wtf this is :)" })
|
||||
})
|
||||
|
||||
const totalCredits = data.balance.monthlyApiCreditsRemaining + data.balance.stableApiCreditsRemaining
|
||||
await expect(billingActor.getSnapshot().context.credits).toBe(totalCredits)
|
||||
await within(queryByTestId('billing-credits')).getByText(totalCredits)
|
||||
})
|
||||
|
||||
test('Progress bar reflects ratio left of Free subscription', async () => {
|
||||
const data = {
|
||||
balance: {
|
||||
monthlyApiCreditsRemaining: 10,
|
||||
stableApiCreditsRemaining: 0,
|
||||
},
|
||||
subscriptions: {
|
||||
monthlyPayAsYouGoApiCreditsTotal: 20,
|
||||
name: "free",
|
||||
}
|
||||
}
|
||||
|
||||
server.use(
|
||||
http.get('*/user/payment/balance', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
|
||||
}),
|
||||
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentSubscriptionsResponse(data.subscriptions))
|
||||
}),
|
||||
http.get('*/org', (req, res, ctx) => {
|
||||
return new HttpResponse(403)
|
||||
}),
|
||||
)
|
||||
|
||||
const billingActor = createActor(billingMachine, { input: BILLING_CONTEXT_DEFAULTS }).start()
|
||||
|
||||
const { queryByTestId } = render(<BillingRemaining
|
||||
mode={BillingRemainingMode.ProgressBarFixed}
|
||||
billingActor={billingActor}
|
||||
/>)
|
||||
|
||||
await act(() => {
|
||||
billingActor.send({ type: BillingTransition.Update, apiToken: "it doesn't matter wtf this is :)" })
|
||||
})
|
||||
|
||||
const totalCredits = data.balance.monthlyApiCreditsRemaining + data.balance.stableApiCreditsRemaining
|
||||
const monthlyCredits = data.subscriptions.monthlyPayAsYouGoApiCreditsTotal
|
||||
const context = billingActor.getSnapshot().context
|
||||
await expect(context.credits).toBe(totalCredits)
|
||||
await expect(context.allowance).toBe(monthlyCredits)
|
||||
|
||||
await within(queryByTestId('billing-credits')).getByText(totalCredits)
|
||||
await expect(queryByTestId('billing-remaining-progress-bar-inner')).toHaveStyle({
|
||||
width: "50.00%"
|
||||
})
|
||||
})
|
||||
test('Shows infinite credits for Pro subscription', async () => {
|
||||
const data = {
|
||||
// These are all ignored
|
||||
balance: {
|
||||
monthlyApiCreditsRemaining: 10,
|
||||
stableApiCreditsRemaining: 0,
|
||||
},
|
||||
subscriptions: {
|
||||
// This should be ignored because it's Pro tier.
|
||||
monthlyPayAsYouGoApiCreditsTotal: 20,
|
||||
name: "pro",
|
||||
}
|
||||
}
|
||||
|
||||
server.use(
|
||||
http.get('*/user/payment/balance', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
|
||||
}),
|
||||
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentSubscriptionsResponse(data.subscriptions))
|
||||
}),
|
||||
http.get('*/org', (req, res, ctx) => {
|
||||
return new HttpResponse(403)
|
||||
}),
|
||||
)
|
||||
|
||||
const billingActor = createActor(billingMachine, { input: BILLING_CONTEXT_DEFAULTS }).start()
|
||||
|
||||
const { queryByTestId } = render(<BillingRemaining
|
||||
mode={BillingRemainingMode.ProgressBarFixed}
|
||||
billingActor={billingActor}
|
||||
/>)
|
||||
|
||||
await act(() => {
|
||||
billingActor.send({ type: BillingTransition.Update, apiToken: "aosetuhsatuh" })
|
||||
})
|
||||
|
||||
await expect(queryByTestId('infinity')).toBeVisible()
|
||||
// You can't do `.not.toBeVisible` folks. When the query fails it's because
|
||||
// no element could be found. toBeVisible should be used on an element
|
||||
// that's found but may not be visible due to `display` or others.
|
||||
await expect(queryByTestId('billing-remaining-progress-bar-inline')).toBe(null)
|
||||
})
|
||||
test('Shows infinite credits for Enterprise subscription', async () => {
|
||||
const data = {
|
||||
// These are all ignored, user is part of an org.
|
||||
balance: {
|
||||
monthlyApiCreditsRemaining: 10,
|
||||
stableApiCreditsRemaining: 0,
|
||||
},
|
||||
subscriptions: {
|
||||
// This should be ignored because it's Pro tier.
|
||||
monthlyPayAsYouGoApiCreditsTotal: 20,
|
||||
// This should be ignored because the user is part of an Org.
|
||||
name: "free",
|
||||
}
|
||||
}
|
||||
|
||||
server.use(
|
||||
http.get('*/user/payment/balance', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
|
||||
}),
|
||||
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentSubscriptionsResponse(data.subscriptions))
|
||||
}),
|
||||
// Ok finally the first use of an org lol
|
||||
http.get('*/org', (req, res, ctx) => {
|
||||
return HttpResponse.json(createOrgResponse())
|
||||
}),
|
||||
)
|
||||
|
||||
const billingActor = createActor(billingMachine, { input: BILLING_CONTEXT_DEFAULTS }).start()
|
||||
|
||||
const { queryByTestId } = render(<BillingRemaining
|
||||
mode={BillingRemainingMode.ProgressBarFixed}
|
||||
billingActor={billingActor}
|
||||
/>)
|
||||
|
||||
await act(() => {
|
||||
billingActor.send({ type: BillingTransition.Update, apiToken: "aosetuhsatuh" })
|
||||
})
|
||||
|
||||
// The result should be the same as Pro users.
|
||||
await expect(queryByTestId('infinity')).toBeVisible()
|
||||
await expect(queryByTestId('billing-remaining-progress-bar-inline')).toBe(null)
|
||||
})
|
@ -1,25 +0,0 @@
|
||||
import { pathsToModuleNameMapper } from 'ts-jest'
|
||||
// In the following statement, replace `./tsconfig` with the path to your `tsconfig` file
|
||||
// which contains the path mapping (ie the `compilerOptions.paths` option):
|
||||
import { compilerOptions } from './tsconfig.json'
|
||||
import type { Config } from 'jest'
|
||||
|
||||
const jestConfig: Config = {
|
||||
// [...]
|
||||
preset: "ts-jest",
|
||||
transform: {
|
||||
"^.+\.tsx?$": ["ts-jest",{ babelConfig: true }],
|
||||
},
|
||||
testEnvironment: "jest-fixed-jsdom",
|
||||
// Include both standard test patterns and our custom .jesttest. pattern
|
||||
testMatch: [
|
||||
"**/__tests__/**/*.[jt]s?(x)",
|
||||
"**/?(*.)+(spec|test).[tj]s?(x)",
|
||||
"**/?(*.)+(jesttest).[tj]s?(x)"
|
||||
],
|
||||
// TAG: paths, path, baseUrl, alias
|
||||
// This is necessary to use tsconfig path aliases.
|
||||
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/../' }),
|
||||
}
|
||||
|
||||
export default jestConfig
|
@ -1,35 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noErrorTruncation": true,
|
||||
"baseUrl": "../../",
|
||||
"paths": {
|
||||
"@kittycad/codemirror-lsp-client": [
|
||||
"./packages/codemirror-lsp-client/src/index.ts"
|
||||
],
|
||||
"@kittycad/codemirror-lang-kcl": [
|
||||
"./packages/codemirror-lang-kcl/src/index.ts"
|
||||
],
|
||||
"@rust/*": ["./rust/*"],
|
||||
"@e2e/*": ["./e2e/*"],
|
||||
"@src/*": ["./src/*"],
|
||||
"@public/*": ["./public/*"],
|
||||
"@root/*": ["./*"]
|
||||
},
|
||||
"target": "esnext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"composite": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
}
|
||||
}
|
@ -131,8 +131,7 @@
|
||||
"test": "vitest --mode development",
|
||||
"test:rust": "(cd rust && just test && just lint)",
|
||||
"test:snapshots": "cross-env TARGET=web NODE_ENV=development playwright test --config=playwright.config.ts --grep=@snapshot --trace=on",
|
||||
"test:unit": "vitest run --mode development --exclude **/jest-component-unit-tests/*",
|
||||
"test:unit:components": "jest -c jest-component-unit-tests/jest.config.ts --rootDir jest-component-unit-tests/",
|
||||
"test:unit": "vitest run --mode development",
|
||||
"test:e2e:web": "cross-env TARGET=web NODE_ENV=development playwright test --config=playwright.config.ts --project=\"Google Chrome\" --grep=@web",
|
||||
"test:e2e:desktop": "cross-env TARGET=desktop playwright test --config=playwright.electron.config.ts --grep-invert=\"@snapshot|@web\"",
|
||||
"test:e2e:desktop:local": "cross-env TARGET=desktop npm run tronb:vite:dev && playwright test --config=playwright.electron.config.ts --grep-invert=\"@snapshot|@web\" --grep-invert=\"$(curl --silent https://test-analysis-bot.hawk-dinosaur.ts.net/projects/KittyCAD/modeling-app/tests/disabled/regex)\"",
|
||||
|
347
src/components/billing.test.tsx
Normal file
347
src/components/billing.test.tsx
Normal file
@ -0,0 +1,347 @@
|
||||
// @ts-nocheck
|
||||
// This was moved out of the Jest workflow. Needs proper TS TLC.
|
||||
|
||||
// Test runner
|
||||
|
||||
// Render mocking, DOM querying
|
||||
import { act, render, within } from '@testing-library/react'
|
||||
import '@testing-library/jest-dom' // Required for .toHaveStyle
|
||||
|
||||
// Request mocking
|
||||
import { http, HttpResponse } from 'msw'
|
||||
import { setupServer } from 'msw/node'
|
||||
|
||||
// React and XState code to test
|
||||
import type { Models } from '@kittycad/lib'
|
||||
import { createActor } from 'xstate'
|
||||
import {
|
||||
BillingRemaining,
|
||||
BillingRemainingMode,
|
||||
} from '@src/components/BillingRemaining'
|
||||
import {
|
||||
BILLING_CONTEXT_DEFAULTS,
|
||||
billingMachine,
|
||||
BillingTransition,
|
||||
} from '@src/machines/billingMachine'
|
||||
|
||||
// Setup basic request mocking
|
||||
const server = setupServer()
|
||||
beforeAll(() => server.listen())
|
||||
afterEach(() => server.resetHandlers())
|
||||
afterAll(() => server.close())
|
||||
|
||||
// Data ripped from docs.zoo.dev
|
||||
const createUserPaymentBalanceResponse = (opts: {
|
||||
monthlyApiCreditsRemaining
|
||||
stableApiCreditsRemaining
|
||||
}): Models['CustomerBalance_type'] => ({
|
||||
created_at: '2025-05-05T16:05:47.317Z',
|
||||
id: 'de607b7e-90ba-4977-8561-16e8a9ea0e50',
|
||||
map_id: 'd7f7de34-9bc3-4b8b-9951-cdee03fc792d',
|
||||
modeling_app_enterprise_price: {
|
||||
type: 'enterprise',
|
||||
},
|
||||
monthly_api_credits_remaining: opts.monthlyApiCreditsRemaining,
|
||||
monthly_api_credits_remaining_monetary_value: '22.47',
|
||||
stable_api_credits_remaining: opts.stableApiCreditsRemaining,
|
||||
stable_api_credits_remaining_monetary_value: '18.91',
|
||||
subscription_details: undefined,
|
||||
subscription_id: 'Hnd3jalJkHA3lb1YexOTStZtPYHTM',
|
||||
total_due: '100.08',
|
||||
updated_at: '2025-05-05T16:05:47.317Z',
|
||||
})
|
||||
|
||||
const createOrgResponse = (): Models['Org_type'] => ({
|
||||
allow_users_in_domain_to_auto_join: true,
|
||||
billing_email: 'm@dN9MCH.com',
|
||||
billing_email_verified: '2025-05-05T18:52:02.021Z',
|
||||
block: 'payment_method_failed',
|
||||
can_train_on_data: true,
|
||||
created_at: '2025-05-05T18:52:02.021Z',
|
||||
domain: 'Ctxde1hpG8xTvvlef5SEPm7',
|
||||
id: '78432284-8660-46bf-ac65-d00bf9b18c3e',
|
||||
image: 'https://Rt0.yK.com/R2SoRtl/tpUdckyDJ',
|
||||
name: 'AevRR4w42KdkA487dh',
|
||||
phone: '+1-696-641-2790',
|
||||
stripe_id: 'sCfjVscpLyOBYUWO7Vlx',
|
||||
updated_at: '2025-05-05T18:52:02.021Z',
|
||||
})
|
||||
|
||||
const createUserPaymentSubscriptionsResponse = (opts: {
|
||||
monthlyPayAsYouGoApiCreditsTotal
|
||||
name
|
||||
}): Models['ZooProductSubscriptions_type'] => ({
|
||||
modeling_app: {
|
||||
annual_discount: 10,
|
||||
description: '1ztERftrU3L3yOnv5epTLcM',
|
||||
endpoints_included: ['modeling'],
|
||||
features: [
|
||||
{
|
||||
info: 'zZcZKHejXabT5HMZDkSkDGD2bfzkAt',
|
||||
},
|
||||
],
|
||||
monthly_pay_as_you_go_api_credits: opts.monthlyPayAsYouGoApiCreditsTotal,
|
||||
monthly_pay_as_you_go_api_credits_monetary_value: '55.85',
|
||||
name: opts.name,
|
||||
pay_as_you_go_api_credit_price: '18.49',
|
||||
price: {
|
||||
interval: 'year',
|
||||
price: '50.04',
|
||||
type: 'per_user',
|
||||
},
|
||||
share_links: ['password_protected'],
|
||||
support_tier: 'community',
|
||||
training_data_behavior: 'default_on',
|
||||
type: {
|
||||
saml_sso: true,
|
||||
type: 'organization',
|
||||
},
|
||||
zoo_tools_included: ['text_to_cad'],
|
||||
},
|
||||
})
|
||||
|
||||
test('Shows a loading spinner when uninitialized credit count', async () => {
|
||||
server.use(
|
||||
http.get('*/user/payment/balance', (req, res, ctx) => {
|
||||
return HttpResponse.json({})
|
||||
}),
|
||||
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
|
||||
return HttpResponse.json({})
|
||||
}),
|
||||
http.get('*/org', (req, res, ctx) => {
|
||||
return new HttpResponse(403)
|
||||
})
|
||||
)
|
||||
|
||||
const billingActor = createActor(billingMachine, {
|
||||
input: BILLING_CONTEXT_DEFAULTS,
|
||||
}).start()
|
||||
|
||||
const { queryByTestId } = render(
|
||||
<BillingRemaining
|
||||
mode={BillingRemainingMode.ProgressBarFixed}
|
||||
billingActor={billingActor}
|
||||
/>
|
||||
)
|
||||
|
||||
await expect(queryByTestId('spinner')).toBeVisible()
|
||||
})
|
||||
|
||||
test('Shows the total credits for Unknown subscription', async () => {
|
||||
const data = {
|
||||
balance: {
|
||||
monthlyApiCreditsRemaining: 10,
|
||||
stableApiCreditsRemaining: 25,
|
||||
},
|
||||
subscriptions: {
|
||||
monthlyPayAsYouGoApiCreditsTotal: 20,
|
||||
name: 'unknown',
|
||||
},
|
||||
}
|
||||
|
||||
server.use(
|
||||
http.get('*/user/payment/balance', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
|
||||
}),
|
||||
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
|
||||
return HttpResponse.json(
|
||||
createUserPaymentSubscriptionsResponse(data.subscriptions)
|
||||
)
|
||||
}),
|
||||
http.get('*/org', (req, res, ctx) => {
|
||||
return new HttpResponse(403)
|
||||
})
|
||||
)
|
||||
|
||||
const billingActor = createActor(billingMachine, {
|
||||
input: BILLING_CONTEXT_DEFAULTS,
|
||||
}).start()
|
||||
|
||||
const { queryByTestId } = render(
|
||||
<BillingRemaining
|
||||
mode={BillingRemainingMode.ProgressBarFixed}
|
||||
billingActor={billingActor}
|
||||
/>
|
||||
)
|
||||
|
||||
await act(() => {
|
||||
billingActor.send({
|
||||
type: BillingTransition.Update,
|
||||
apiToken: "it doesn't matter wtf this is :)",
|
||||
})
|
||||
})
|
||||
|
||||
const totalCredits =
|
||||
data.balance.monthlyApiCreditsRemaining +
|
||||
data.balance.stableApiCreditsRemaining
|
||||
await expect(billingActor.getSnapshot().context.credits).toBe(totalCredits)
|
||||
await within(queryByTestId('billing-credits')).getByText(totalCredits)
|
||||
})
|
||||
|
||||
test('Progress bar reflects ratio left of Free subscription', async () => {
|
||||
const data = {
|
||||
balance: {
|
||||
monthlyApiCreditsRemaining: 10,
|
||||
stableApiCreditsRemaining: 0,
|
||||
},
|
||||
subscriptions: {
|
||||
monthlyPayAsYouGoApiCreditsTotal: 20,
|
||||
name: 'free',
|
||||
},
|
||||
}
|
||||
|
||||
server.use(
|
||||
http.get('*/user/payment/balance', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
|
||||
}),
|
||||
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
|
||||
return HttpResponse.json(
|
||||
createUserPaymentSubscriptionsResponse(data.subscriptions)
|
||||
)
|
||||
}),
|
||||
http.get('*/org', (req, res, ctx) => {
|
||||
return new HttpResponse(403)
|
||||
})
|
||||
)
|
||||
|
||||
const billingActor = createActor(billingMachine, {
|
||||
input: BILLING_CONTEXT_DEFAULTS,
|
||||
}).start()
|
||||
|
||||
const { queryByTestId } = render(
|
||||
<BillingRemaining
|
||||
mode={BillingRemainingMode.ProgressBarFixed}
|
||||
billingActor={billingActor}
|
||||
/>
|
||||
)
|
||||
|
||||
await act(() => {
|
||||
billingActor.send({
|
||||
type: BillingTransition.Update,
|
||||
apiToken: "it doesn't matter wtf this is :)",
|
||||
})
|
||||
})
|
||||
|
||||
const totalCredits =
|
||||
data.balance.monthlyApiCreditsRemaining +
|
||||
data.balance.stableApiCreditsRemaining
|
||||
const monthlyCredits = data.subscriptions.monthlyPayAsYouGoApiCreditsTotal
|
||||
const context = billingActor.getSnapshot().context
|
||||
await expect(context.credits).toBe(totalCredits)
|
||||
await expect(context.allowance).toBe(monthlyCredits)
|
||||
|
||||
await within(queryByTestId('billing-credits')).getByText(totalCredits)
|
||||
await expect(
|
||||
queryByTestId('billing-remaining-progress-bar-inner')
|
||||
).toHaveStyle({
|
||||
width: '50.00%',
|
||||
})
|
||||
})
|
||||
test('Shows infinite credits for Pro subscription', async () => {
|
||||
const data = {
|
||||
// These are all ignored
|
||||
balance: {
|
||||
monthlyApiCreditsRemaining: 10,
|
||||
stableApiCreditsRemaining: 0,
|
||||
},
|
||||
subscriptions: {
|
||||
// This should be ignored because it's Pro tier.
|
||||
monthlyPayAsYouGoApiCreditsTotal: 20,
|
||||
name: 'pro',
|
||||
},
|
||||
}
|
||||
|
||||
server.use(
|
||||
http.get('*/user/payment/balance', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
|
||||
}),
|
||||
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
|
||||
return HttpResponse.json(
|
||||
createUserPaymentSubscriptionsResponse(data.subscriptions)
|
||||
)
|
||||
}),
|
||||
http.get('*/org', (req, res, ctx) => {
|
||||
return new HttpResponse(403)
|
||||
})
|
||||
)
|
||||
|
||||
const billingActor = createActor(billingMachine, {
|
||||
input: BILLING_CONTEXT_DEFAULTS,
|
||||
}).start()
|
||||
|
||||
const { queryByTestId } = render(
|
||||
<BillingRemaining
|
||||
mode={BillingRemainingMode.ProgressBarFixed}
|
||||
billingActor={billingActor}
|
||||
/>
|
||||
)
|
||||
|
||||
await act(() => {
|
||||
billingActor.send({
|
||||
type: BillingTransition.Update,
|
||||
apiToken: 'aosetuhsatuh',
|
||||
})
|
||||
})
|
||||
|
||||
await expect(queryByTestId('infinity')).toBeVisible()
|
||||
// You can't do `.not.toBeVisible` folks. When the query fails it's because
|
||||
// no element could be found. toBeVisible should be used on an element
|
||||
// that's found but may not be visible due to `display` or others.
|
||||
await expect(queryByTestId('billing-remaining-progress-bar-inline')).toBe(
|
||||
null
|
||||
)
|
||||
})
|
||||
test('Shows infinite credits for Enterprise subscription', async () => {
|
||||
const data = {
|
||||
// These are all ignored, user is part of an org.
|
||||
balance: {
|
||||
monthlyApiCreditsRemaining: 10,
|
||||
stableApiCreditsRemaining: 0,
|
||||
},
|
||||
subscriptions: {
|
||||
// This should be ignored because it's Pro tier.
|
||||
monthlyPayAsYouGoApiCreditsTotal: 20,
|
||||
// This should be ignored because the user is part of an Org.
|
||||
name: 'free',
|
||||
},
|
||||
}
|
||||
|
||||
server.use(
|
||||
http.get('*/user/payment/balance', (req, res, ctx) => {
|
||||
return HttpResponse.json(createUserPaymentBalanceResponse(data.balance))
|
||||
}),
|
||||
http.get('*/user/payment/subscriptions', (req, res, ctx) => {
|
||||
return HttpResponse.json(
|
||||
createUserPaymentSubscriptionsResponse(data.subscriptions)
|
||||
)
|
||||
}),
|
||||
// Ok finally the first use of an org lol
|
||||
http.get('*/org', (req, res, ctx) => {
|
||||
return HttpResponse.json(createOrgResponse())
|
||||
})
|
||||
)
|
||||
|
||||
const billingActor = createActor(billingMachine, {
|
||||
input: BILLING_CONTEXT_DEFAULTS,
|
||||
}).start()
|
||||
|
||||
const { queryByTestId } = render(
|
||||
<BillingRemaining
|
||||
mode={BillingRemainingMode.ProgressBarFixed}
|
||||
billingActor={billingActor}
|
||||
/>
|
||||
)
|
||||
|
||||
await act(() => {
|
||||
billingActor.send({
|
||||
type: BillingTransition.Update,
|
||||
apiToken: 'aosetuhsatuh',
|
||||
})
|
||||
})
|
||||
|
||||
// The result should be the same as Pro users.
|
||||
await expect(queryByTestId('infinity')).toBeVisible()
|
||||
await expect(queryByTestId('billing-remaining-progress-bar-inline')).toBe(
|
||||
null
|
||||
)
|
||||
})
|
Reference in New Issue
Block a user