mirror of
https://github.com/saltbo/zpan.git
synced 2026-08-28 15:51:29 +08:00
310e4950b3
Replace pnpm workspace monorepo (packages/server, packages/web, packages/shared) with a flat single-package layout following Hono's pages-stack pattern. Switch from pnpm to npm and from Workers+Assets to CF Pages Functions deployment model. - Move source: packages/server/src/ → server/, packages/web/src/ → src/, packages/shared/src/ → shared/ - Add functions/api/[[route]].ts as CF Pages Functions entry (replaces entry-cloudflare.ts) - Update 22 import paths: server uses relative, web uses @shared/@server aliases - Merge three package.json into one, switch to npm - Update wrangler.toml: remove main/assets (Pages auto-detects functions/ dir) - Add per-directory tsconfig.json for VS Code type resolution - Simplify Dockerfile for flat layout - Fix react-pdf CSS import path (dist/esm/ → dist/) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
115 lines
3.8 KiB
TypeScript
115 lines
3.8 KiB
TypeScript
import { nanoid } from 'nanoid'
|
|
import { describe, expect, it } from 'vitest'
|
|
import * as authSchema from '../db/auth-schema.js'
|
|
import { createTestApp } from '../test/setup.js'
|
|
import { findPersonalOrg } from './org.js'
|
|
|
|
type TestDb = ReturnType<typeof createTestApp>['db']
|
|
|
|
async function insertUser(db: TestDb, overrides: Partial<{ id: string; name: string; email: string }> = {}) {
|
|
const id = overrides.id ?? nanoid()
|
|
await db.insert(authSchema.user).values({
|
|
id,
|
|
name: overrides.name ?? 'Test User',
|
|
email: overrides.email ?? `${id}@example.com`,
|
|
emailVerified: false,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
})
|
|
return id
|
|
}
|
|
|
|
async function insertOrg(db: TestDb, overrides: Partial<{ id: string; slug: string; metadata: string | null }> = {}) {
|
|
const id = overrides.id ?? nanoid()
|
|
await db.insert(authSchema.organization).values({
|
|
id,
|
|
name: 'Test Org',
|
|
slug: overrides.slug ?? nanoid(),
|
|
metadata: overrides.metadata !== undefined ? overrides.metadata : JSON.stringify({ type: 'personal' }),
|
|
createdAt: new Date(),
|
|
})
|
|
return id
|
|
}
|
|
|
|
async function insertMember(db: TestDb, organizationId: string, userId: string) {
|
|
await db.insert(authSchema.member).values({
|
|
id: nanoid(),
|
|
organizationId,
|
|
userId,
|
|
role: 'owner',
|
|
createdAt: new Date(),
|
|
})
|
|
}
|
|
|
|
describe('findPersonalOrg', () => {
|
|
it('returns the org id when a personal org exists for the user', async () => {
|
|
const { db } = createTestApp()
|
|
const userId = await insertUser(db)
|
|
const orgId = await insertOrg(db, { metadata: JSON.stringify({ type: 'personal' }) })
|
|
await insertMember(db, orgId, userId)
|
|
|
|
const result = await findPersonalOrg(db, userId)
|
|
expect(result).toBe(orgId)
|
|
})
|
|
|
|
it('returns null when user has no memberships', async () => {
|
|
const { db } = createTestApp()
|
|
const userId = await insertUser(db)
|
|
|
|
const result = await findPersonalOrg(db, userId)
|
|
expect(result).toBeNull()
|
|
})
|
|
|
|
it('returns null when user only belongs to a non-personal org', async () => {
|
|
const { db } = createTestApp()
|
|
const userId = await insertUser(db)
|
|
const orgId = await insertOrg(db, { metadata: JSON.stringify({ type: 'team' }) })
|
|
await insertMember(db, orgId, userId)
|
|
|
|
const result = await findPersonalOrg(db, userId)
|
|
expect(result).toBeNull()
|
|
})
|
|
|
|
it('returns null when org metadata is null', async () => {
|
|
const { db } = createTestApp()
|
|
const userId = await insertUser(db)
|
|
const orgId = await insertOrg(db, { metadata: null })
|
|
await insertMember(db, orgId, userId)
|
|
|
|
const result = await findPersonalOrg(db, userId)
|
|
expect(result).toBeNull()
|
|
})
|
|
|
|
it('returns null when org metadata is invalid JSON', async () => {
|
|
const { db } = createTestApp()
|
|
const userId = await insertUser(db)
|
|
const orgId = await insertOrg(db, { metadata: 'not-valid-json' })
|
|
await insertMember(db, orgId, userId)
|
|
|
|
const result = await findPersonalOrg(db, userId)
|
|
expect(result).toBeNull()
|
|
})
|
|
|
|
it('returns null when org metadata is valid JSON but missing type field', async () => {
|
|
const { db } = createTestApp()
|
|
const userId = await insertUser(db)
|
|
const orgId = await insertOrg(db, { metadata: JSON.stringify({ other: 'value' }) })
|
|
await insertMember(db, orgId, userId)
|
|
|
|
const result = await findPersonalOrg(db, userId)
|
|
expect(result).toBeNull()
|
|
})
|
|
|
|
it('finds the personal org among multiple memberships', async () => {
|
|
const { db } = createTestApp()
|
|
const userId = await insertUser(db)
|
|
const teamOrgId = await insertOrg(db, { metadata: JSON.stringify({ type: 'team' }) })
|
|
const personalOrgId = await insertOrg(db, { metadata: JSON.stringify({ type: 'personal' }) })
|
|
await insertMember(db, teamOrgId, userId)
|
|
await insertMember(db, personalOrgId, userId)
|
|
|
|
const result = await findPersonalOrg(db, userId)
|
|
expect(result).toBe(personalOrgId)
|
|
})
|
|
})
|