Skip to content

Commit

Permalink
Merge pull request #2 from fumeapp/pen-tests
Browse files Browse the repository at this point in the history
💚 created a pen
  • Loading branch information
acidjazz authored Aug 21, 2024
2 parents a861fd8 + a0700db commit f377518
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 51 deletions.
8 changes: 7 additions & 1 deletion app/types/models.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Token as PrismaToken, User as PrismaUser } from '@prisma/client'
import type { Cartridge as PrismaCartridge, Pen as PrismaPen, Shot as PrismaShot } from '@prisma/client'
import type { UserInfo } from '~/types/oauth'

export interface Token extends PrismaToken {
client: import('ua-parser-js').IResult
Expand All @@ -25,6 +26,11 @@ export interface User extends PrismaUser {
hash: string
}

export interface UserSession extends UserInfo {
session: User
cookie?: string
}

export interface Shot extends PrismaShot {
cartridge?: Cartridge
}
Expand All @@ -35,5 +41,5 @@ export interface Cartridge extends PrismaCartridge {
}

export interface Pen extends PrismaPen {
cartridge?: Cartridge
cartridge: Cartridge | null
}
2 changes: 1 addition & 1 deletion app/types/oauth.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export interface UserInfo {
email: string
name: string
avatar: string
email: string
payload?: UserPayload
}

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"test": "vitest run",
"test:dev": "DEVRUN=true vitest run",
"test:reset": "pnpm run db:test:reset; vitest run",
"test:dev:reset": "pnpm run db:test:reset; DEVRUN=true vitest run",
"db:test:reset": "dotenv -e .env.test -- npx prisma migrate reset --force",
"test:coverage": "vitest run --coverage.enabled true",
"lint": "eslint .",
Expand Down
41 changes: 26 additions & 15 deletions server/controllers/pen.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
import { z } from 'zod'
import { penColors } from '~/utils/shared'

const inc = {
cartridge: {
include: {
shots: {
orderBy: {
date: 'asc',
},
},
},
},
}

const index = defineEventHandler(async (event) => {
const { user } = await requireUserSession(event)
return metapi().render(
await prisma.pen.findMany({
where: {
userId: BigInt(user.id),
},
include: {
cartridge: {
include: {
shots: {
orderBy: {
date: 'asc',
},
},
},
},
include: inc,
orderBy: {
updatedAt: 'desc',
},
}),
)
})

const create = defineEventHandler(async (event) => {
const { user } = await requireUserSession(event)
const schema = z.object({ color: z.enum(penColors as [string, ...string[]]) })
const create = authedHandler(async ({ user, event }) => {
const schema = z.object({
color: z.enum(penColors as [string, ...string[]]),
})
const parsed = schema.safeParse(await readBody(event))
if (!parsed.success) return metapi().error(event, parsed.error.issues, 400)
const pen = await prisma.pen.create({
Expand All @@ -34,20 +40,22 @@ const create = defineEventHandler(async (event) => {
userId: user.id,
cartridgeId: null,
},
include: inc,
})

return metapi().success('pen created', pen)
})

const update = defineEventHandler(async (event) => {
const { user } = await requireUserSession(event)
const update = authedHandler(async ({ user, event }) => {
const schema = z.object({
id: z.number(),
color: z.enum(penColors as [string, ...string[]]),
cartridgeId: z.number().optional(),
})
const parsed = schema.safeParse({
id: Number.parseInt(event.context.params?.id as string),
cartridgeId: Number.parseInt((await readBody(event))?.cartridgeId) || undefined,
color: (await readBody(event))?.color || penColors[0],
})
if (!parsed.success) return metapi().error(event, parsed.error.issues, 400)
const pen = await prisma.pen.update({
Expand All @@ -57,7 +65,9 @@ const update = defineEventHandler(async (event) => {
},
data: {
cartridgeId: parsed.data.cartridgeId ? BigInt(parsed.data.cartridgeId) : null,
color: parsed.data.color,
},
include: inc,
})

return metapi().success('pen updated', pen)
Expand All @@ -74,6 +84,7 @@ const get = defineEventHandler(async (event) => {
id: parsed.data.id,
userId: user.id,
},
include: inc,
}))
})

Expand Down
1 change: 1 addition & 0 deletions server/utils/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const createUser = async (info: UserInfo, provider: string, oauthPayload:
},
},
}) as unknown as User

else
await prisma.provider.upsert({
where: {
Expand Down
26 changes: 15 additions & 11 deletions test/auth.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { $fetch } from '@nuxt/test-utils/e2e'
import type { User } from '~/types/models'
import type { User, UserSession } from '~/types/models'
import { createUser } from '~~/server/utils/user'

const users = [
{
session: {} as User,
cookie: '',
cookie: undefined,
email: '[email protected]',
name: 'Test User',
avatar: 'https://avatars.githubusercontent.com/u/31337?v=4',
Expand All @@ -27,25 +27,29 @@ const users = [
},
},
},
]
] as UserSession[]

async function setupUsers() {
await Promise.all(users.map(async (userData) => {
userData.session = await createUser(userData, 'github', {})
}))
async function userFromEmail(email: string): Promise<UserSession> {
const index = users.findIndex(user => user.email === email)
if (index === undefined) throw new Error(`User not found: ${email} - ${index}`)
if (!users[index]) throw new Error('User not found')
if (!users[index].session?.id)
users[index].session = await createUser(users[index], 'github', {})
return users[index]
}

async function actingAs(email: string) {
const user = users.find(user => user.email === email)
if (!user) throw new Error('User not found')
const user = await userFromEmail(email)
const { data } = await $fetch('/api/test/session', { method: 'POST', body: { id: user?.session?.id.toString(), hash: user?.session?.hash } })
user.cookie = data.cookie[1].split(';')[0] as string
const get = (url: string) => $fetch(url, { headers: { cookie: user.cookie as string } })
return { get }
const post = (url: string, params: object) => $fetch(url, { method: 'POST', body: params, headers: { cookie: user.cookie as string } })
const put = (url: string, params: object) => $fetch(url, { method: 'PUT', body: params, headers: { cookie: user.cookie as string } })
return { get, post, put }
}

export {
users,
setupUsers,
actingAs,
userFromEmail,
}
10 changes: 10 additions & 0 deletions test/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function setupConfig() {
if (process.env.DEVRUN === 'true' && !process.env.CI)
return { host: 'http://localhost:3000' }
else
return {}
}

export {
setupConfig,
}
39 changes: 39 additions & 0 deletions test/pen.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { describe, expect, it } from 'vitest'
import { setup } from '@nuxt/test-utils'
import { actingAs, userFromEmail } from './auth'
import { setupConfig } from './config'
import { penColors } from '~/utils/shared'
import type { MetapiResponse } from '~/types/metapi'
import type { Pen } from '~/types/models'

describe('/api/pen', async () => {
await setup(setupConfig())

const pens: Pen[] = []

it('post /api/pen - create a pen', async () => {
const { post } = await actingAs('[email protected]')
const { data: pen } = await post('/api/pen', { color: penColors[0] }) as MetapiResponse<Pen>
expect(pen.color).toBe(penColors[0])
pens.push(pen)
expect(pen.userId).toBe((await userFromEmail('[email protected]')).session.id.toString())
})

it(' get /api/pen - list all pens', async () => {
const { get } = await actingAs('[email protected]')
const response = await get('/api/pen') as MetapiResponse<Pen[]>
expect(response.data[0]).toStrictEqual(pens[0])
})

it ('get /api/pen/:id - get a pen', async () => {
const { get } = await actingAs('[email protected]')
const response = await get(`/api/pen/${pens[0]?.id}`) as MetapiResponse<Pen>
expect(response.data).toStrictEqual(pens[0])
})

it ('put /api/pen/:id - update a pen', async () => {
const { put } = await actingAs('[email protected]')
const { data: pen } = await put(`/api/pen/${pens[0]?.id}`, { color: penColors[1] }) as MetapiResponse<Pen>
expect(pen.color).toBe(penColors[1])
})
})
27 changes: 12 additions & 15 deletions test/user.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
import { beforeAll, describe, expect, it } from 'vitest'
import { describe, expect, it } from 'vitest'
import { $fetch, setup } from '@nuxt/test-utils/e2e'
import { actingAs, setupUsers, users } from './auth'
import { actingAs, users } from './auth'
import { setupConfig } from './config'
import type { MetapiResponse } from '~/types/metapi'
import type { User } from '~/types/models'

beforeAll(setupUsers)

function setupConfig() {
if (process.env.DEVRUN === 'true' && !process.env.CI)
return { host: 'http://localhost:3000' }
else
return {}
}

describe('/api/me', async () => {
describe('/api/me and /api/user', async () => {
await setup(setupConfig())
it('/api/me should 401', async () => {
try { await $fetch('/api/me') }
Expand All @@ -22,13 +14,13 @@ describe('/api/me', async () => {
}
})

it('/api/me returns the currently logged in user', async () => {
it('get /api/me - current user session', async () => {
const { get } = await actingAs('[email protected]')
const response = await get('/api/me') as MetapiResponse<User>
expect(response.data.email).toEqual(users[0]?.session.email)
})

it ('/api/user should 404 if a non-admin accesses it', async () => {
it ('get /api/user isAdmin: false - 404', async () => {
try {
await (await actingAs('[email protected]')).get('/api/user')
}
Expand All @@ -37,8 +29,13 @@ describe('/api/me', async () => {
}
})

it ('/api/use should return a list of all users if an admin accesses it', async () => {
it ('get /api/user GET', async () => {
const response = await (await actingAs('[email protected]')).get('/api/user') as MetapiResponse<User[]>
expect(response.data.length).toBe(2)
})

it ('get /api/user/:id', async () => {
const response = await (await actingAs('[email protected]')).get(`/api/user/${users[0]?.session.id}`) as MetapiResponse<User>
expect(response.data.id).toBe(users[0]?.session.id.toString())
})
})
8 changes: 0 additions & 8 deletions vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,6 @@ export default defineVitestConfig({
coverage: {
reporter: ['text', 'json-summary', 'json'],
reportOnFailure: true,
/*
thresholds: {
lines: 60,
branches: 60,
functions: 60,
statements: 60,
},
*/
},
},
})

0 comments on commit f377518

Please sign in to comment.