Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions packages/worker/src/app/document-head.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@ import {
resolveDocumentTitle,
} from './document-head.ts'

test('resolveDocumentTitle returns static titles for known routes', () => {
test('resolveDocumentHead covers static titles, dynamic OG, fallbacks, and absolutized URLs', () => {
expect(resolveDocumentTitle('/')).toBe(DEFAULT_DOCUMENT_TITLE)
expect(resolveDocumentTitle('/account')).toBe('Account')
expect(resolveDocumentTitle('/account/secrets')).toBe('Secrets')
expect(resolveDocumentTitle('/account/secrets/new')).toBe('Secrets')
expect(resolveDocumentTitle('/account/billing')).toBe('Billing')
expect(
resolveDocumentTitle('/account/package-invocation-tokens/token-1'),
).toBe('Package invocation tokens')
expect(resolveDocumentTitle('/blog')).toBe('Blog')
expect(resolveDocumentTitle('/community')).toBe('Community packages')
expect(resolveDocumentTitle('/timeline')).toBe('Timeline')
expect(resolveDocumentTitle('/admin/users')).toBe('Admin users')
expect(resolveDocumentTitle('/privacy')).toBe('Privacy')
})

test('resolveDocumentHead attaches OG metadata for public registry pages', () => {
const home = resolveDocumentHead('/')
expect(home.og?.title).toBe("Kody — your assistant's home")
expect(home.og?.imagePath).toBe('/og/home.png')
Expand All @@ -36,9 +40,7 @@ test('resolveDocumentHead attaches OG metadata for public registry pages', () =>
hrefPath: '/blog/rss.xml',
},
])
})

test('resolveDocumentHead derives dynamic OG from loader data', () => {
const blogPost = resolveDocumentHead('/blog/hello-world', {
blogPost: {
ok: true,
Expand Down Expand Up @@ -106,9 +108,13 @@ test('resolveDocumentHead derives dynamic OG from loader data', () => {
})
expect(privateProfile.title).toBe('Kent C. Dodds')
expect(privateProfile.og).toBeUndefined()
})

test('resolveDocumentHead falls back when dynamic loader data is missing', () => {
expect(
resolveDocumentTitle('/@missing', {
profileShell: { ok: false, unavailable: true },
}),
).toBe('Profile unavailable')

expect(resolveDocumentHead('/blog/hello-world')).toEqual({ title: 'Blog' })
expect(resolveDocumentHead('/community/listing-1')).toEqual({
title: 'Community packages',
Expand All @@ -117,9 +123,7 @@ test('resolveDocumentHead falls back when dynamic loader data is missing', () =>
expect(resolveDocumentHead('/this-route-does-not-exist').title).toBe(
NOT_FOUND_DOCUMENT_TITLE,
)
})

test('absolutizeDocumentHead expands origin-relative paths', () => {
const resolved = absolutizeDocumentHead(
resolveDocumentHead('/blog', undefined),
'https://heykody.dev',
Expand Down
17 changes: 3 additions & 14 deletions packages/worker/src/app/onboarding-data.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,6 @@ import {
loadPublicOnboardingData,
} from '#app/onboarding-data.ts'

test('onboarding setup prompt steers agents to fork trusted community packages before creating', () => {
const prompt = buildOnboardingSetupPrompt()
expect(prompt).toContain('community_search')
expect(prompt).toContain('trusted community package')
expect(prompt).toContain('community_fork')
expect(prompt).toContain(
'only create a new package if nothing suitable exists',
)
expect(prompt).not.toContain('then package things up once they work')
})

test('onboarding data builds the MCP URL and derives incomplete setup from verification plus grants', async () => {
expect(
buildMcpServerUrl({
Expand All @@ -26,14 +15,14 @@ test('onboarding data builds the MCP URL and derives incomplete setup from verif
}),
).toBe('https://preview.example/mcp')

// Discovery prompt must identify the deployment origin so agents know
// which Kody instance the user is evaluating.
expect(
buildDiscoveryPrompt({
env: {},
requestUrl: 'https://heykody.dev/onboarding',
}),
).toContain(
"I'm deciding whether Kody (https://heykody.dev) would be useful for me.",
)
).toContain('https://heykody.dev')

expect(
loadPublicOnboardingData({
Expand Down
166 changes: 80 additions & 86 deletions packages/worker/src/billing/stripe-client.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,79 +51,6 @@ test('stripe client request contracts for checkout, subscriptions, and portal',
vi.unstubAllGlobals()
}

const listFetch = vi.fn(async () =>
jsonResponse({
data: [
{
id: 'sub_1',
status: 'active',
cancel_at: null,
items: { data: [{ price: { id: 'price_1' } }] },
},
],
}),
)
vi.stubGlobal('fetch', listFetch)
try {
const subscriptions = await listSubscriptions(
{
STRIPE_SECRET_KEY: 'sk_test_secret',
STRIPE_API_BASE_URL: 'https://stripe.mock/',
},
'cus_abc',
)
expect(subscriptions).toHaveLength(1)
expect(subscriptions[0]?.id).toBe('sub_1')

const [listUrl, listInit] = listFetch.mock.calls[0]!
const parsed = new URL(String(listUrl))
expect(parsed.origin).toBe('https://stripe.mock')
expect(parsed.pathname).toBe('/v1/subscriptions')
expect(parsed.searchParams.get('customer')).toBe('cus_abc')
expect(parsed.searchParams.get('status')).toBe('all')
expect(parsed.searchParams.get('limit')).toBe('100')
expect(listInit).toMatchObject({
method: 'GET',
headers: expect.objectContaining({
authorization: 'Bearer sk_test_secret',
}),
})
} finally {
vi.unstubAllGlobals()
}

const portalFetch = vi.fn(async () =>
jsonResponse({ url: 'https://billing.stripe.com/session/test' }),
)
vi.stubGlobal('fetch', portalFetch)
try {
const result = await createBillingPortalSession(
{ STRIPE_SECRET_KEY: 'sk_test_secret' },
{
customerId: 'cus_portal',
returnUrl: 'https://app.example.com/account',
},
)
expect(result).toEqual({
url: 'https://billing.stripe.com/session/test',
})

const [portalUrl, portalInit] = portalFetch.mock.calls[0]!
expect(portalUrl).toBe('https://api.stripe.com/v1/billing_portal/sessions')
expect(portalInit?.method).toBe('POST')
expect(portalInit?.headers).toMatchObject({
authorization: 'Bearer sk_test_secret',
'content-type': 'application/x-www-form-urlencoded',
})
const body = new URLSearchParams(String(portalInit?.body))
expect(body.get('customer')).toBe('cus_portal')
expect(body.get('return_url')).toBe('https://app.example.com/account')
} finally {
vi.unstubAllGlobals()
}
})

test('createCheckoutSession posts subscription form fields and auth header', async () => {
const createFetch = vi.fn(async () =>
jsonResponse({
id: 'cs_new_1',
Expand Down Expand Up @@ -173,16 +100,15 @@ test('createCheckoutSession posts subscription form fields and auth header', asy
} finally {
vi.unstubAllGlobals()
}
})

test('createCheckoutSession uses customer when customerId is set, not customer_email', async () => {
const createFetch = vi.fn(async () =>
// Existing Stripe customers must send customer, never customer_email.
const customerIdFetch = vi.fn(async () =>
jsonResponse({
id: 'cs_new_2',
url: 'https://checkout.stripe.com/c/pay/cs_new_2',
}),
)
vi.stubGlobal('fetch', createFetch)
vi.stubGlobal('fetch', customerIdFetch)
try {
await createCheckoutSession(
{ STRIPE_SECRET_KEY: 'sk_test_secret' },
Expand All @@ -197,16 +123,91 @@ test('createCheckoutSession uses customer when customerId is set, not customer_e
},
)
const body = new URLSearchParams(
String(createFetch.mock.calls[0]?.[1]?.body),
String(customerIdFetch.mock.calls[0]?.[1]?.body),
)
expect(body.get('customer')).toBe('cus_existing')
expect(body.get('customer_email')).toBeNull()
} finally {
vi.unstubAllGlobals()
}

const listFetch = vi.fn(async () =>
jsonResponse({
data: [
{
id: 'sub_1',
status: 'active',
cancel_at: null,
items: { data: [{ price: { id: 'price_1' } }] },
},
],
}),
)
vi.stubGlobal('fetch', listFetch)
try {
const subscriptions = await listSubscriptions(
{
STRIPE_SECRET_KEY: 'sk_test_secret',
STRIPE_API_BASE_URL: 'https://stripe.mock/',
},
'cus_abc',
)
expect(subscriptions).toHaveLength(1)
expect(subscriptions[0]?.id).toBe('sub_1')

const [listUrl, listInit] = listFetch.mock.calls[0]!
const parsed = new URL(String(listUrl))
expect(parsed.origin).toBe('https://stripe.mock')
expect(parsed.pathname).toBe('/v1/subscriptions')
expect(parsed.searchParams.get('customer')).toBe('cus_abc')
expect(parsed.searchParams.get('status')).toBe('all')
expect(parsed.searchParams.get('limit')).toBe('100')
expect(listInit).toMatchObject({
method: 'GET',
headers: expect.objectContaining({
authorization: 'Bearer sk_test_secret',
}),
})
} finally {
vi.unstubAllGlobals()
}

const portalFetch = vi.fn(async () =>
jsonResponse({ url: 'https://billing.stripe.com/session/test' }),
)
vi.stubGlobal('fetch', portalFetch)
try {
const result = await createBillingPortalSession(
{ STRIPE_SECRET_KEY: 'sk_test_secret' },
{
customerId: 'cus_portal',
returnUrl: 'https://app.example.com/account',
},
)
expect(result).toEqual({
url: 'https://billing.stripe.com/session/test',
})

const [portalUrl, portalInit] = portalFetch.mock.calls[0]!
expect(portalUrl).toBe('https://api.stripe.com/v1/billing_portal/sessions')
expect(portalInit?.method).toBe('POST')
expect(portalInit?.headers).toMatchObject({
authorization: 'Bearer sk_test_secret',
'content-type': 'application/x-www-form-urlencoded',
})
const body = new URLSearchParams(String(portalInit?.body))
expect(body.get('customer')).toBe('cus_portal')
expect(body.get('return_url')).toBe('https://app.example.com/account')
} finally {
vi.unstubAllGlobals()
}
})

test('createCheckoutSession rejects null url and non-OK Stripe responses', async () => {
test('stripe client rejects missing config and maps API failure shapes', async () => {
await expect(getCheckoutSession({}, 'cs_test')).rejects.toBeInstanceOf(
BillingNotConfiguredError,
)

silenceExpectedConsoleErrors(['stripe_api_error'])

vi.stubGlobal(
Expand Down Expand Up @@ -262,14 +263,7 @@ test('createCheckoutSession rejects null url and non-OK Stripe responses', async
} finally {
vi.unstubAllGlobals()
}
})

test('stripe client rejects missing config and maps API failure shapes', async () => {
await expect(getCheckoutSession({}, 'cs_test')).rejects.toBeInstanceOf(
BillingNotConfiguredError,
)

silenceExpectedConsoleErrors(['stripe_api_error'])
vi.stubGlobal(
'fetch',
vi.fn(async () => jsonResponse({ error: { message: 'nope' } }, 404)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const owner: PackageOwnerContext = {
delegated: false,
}

test('createStubSavedPackage rejects invalid kody ids and registers valid stubs through the pipeline', async () => {
test('createStubSavedPackage rejects invalid kody ids and registers stubs for owner and delegated scopes', async () => {
resetMocks()
await expect(
createStubSavedPackage({
Expand Down Expand Up @@ -121,9 +121,8 @@ test('createStubSavedPackage rejects invalid kody ids and registers valid stubs
)
expect(mockModule.upsertSavedPackageVector).toHaveBeenCalled()
expect(mockModule.refreshSavedPackageProjection).toHaveBeenCalled()
})

test('createStubSavedPackage stores under the owner account when acting under a grant', async () => {
// Delegated grants must persist under the platform owner, not the actor.
resetMocks()
const delegatedOwner: PackageOwnerContext = {
ownerUserId: 'platform-owner',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ test('get_git_remote returns scoped artifact remotes and rejects invalid input',
).rejects.toThrow()
})

test('get_git_remote create mode registers a stub package when missing', async () => {
test('get_git_remote create mode registers stubs for owner and delegated scopes', async () => {
resetMocks()
await expect(
getGitRemoteCapability.handler(
Expand Down Expand Up @@ -305,9 +305,7 @@ test('get_git_remote create mode registers a stub package when missing', async (
)
expect(trimmedResult.created).toBe(true)
expect(trimmedResult.kody_id).toBe('unleashed-wifi')
})

test('get_git_remote uses the delegated package owner for storage lookups', async () => {
resetMocks()
const delegatedOwner = {
ownerUserId: 'platform-owner',
Expand All @@ -326,7 +324,7 @@ test('get_git_remote uses the delegated package owner for storage lookups', asyn
name: '@kody/unleashed-wifi',
}
})
const result = await getGitRemoteCapability.handler(
const delegatedResult = await getGitRemoteCapability.handler(
{
kody_id: 'unleashed-wifi',
create: true,
Expand Down Expand Up @@ -361,6 +359,6 @@ test('get_git_remote uses the delegated package owner for storage lookups', asyn
kodyId: 'unleashed-wifi',
}),
)
expect(result.created).toBe(true)
expect(result.package_id).toBe('package-1')
expect(delegatedResult.created).toBe(true)
expect(delegatedResult.package_id).toBe('package-1')
})
Loading
Loading