test: add auth, social login, email verification, and validation tests
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import ErrorBoundary from '../ErrorBoundary.vue'
|
||||
|
||||
// Stub UIcon and UButton since they come from Nuxt UI
|
||||
const stubs = {
|
||||
UIcon: { template: '<span />' },
|
||||
UButton: { template: '<button><slot /></button>' },
|
||||
}
|
||||
|
||||
describe('errorBoundary', () => {
|
||||
it('renders slot content when no error', () => {
|
||||
const wrapper = mount(ErrorBoundary, {
|
||||
slots: {
|
||||
default: '<div>Hello World</div>',
|
||||
},
|
||||
global: { stubs },
|
||||
})
|
||||
|
||||
expect(wrapper.text()).toContain('Hello World')
|
||||
})
|
||||
|
||||
it('does not show error UI by default', () => {
|
||||
const wrapper = mount(ErrorBoundary, {
|
||||
slots: {
|
||||
default: '<div>Content</div>',
|
||||
},
|
||||
global: { stubs },
|
||||
})
|
||||
|
||||
expect(wrapper.text()).not.toContain('Something went wrong')
|
||||
expect(wrapper.text()).toContain('Content')
|
||||
})
|
||||
})
|
||||
85
resources/js/composables/__tests__/useAuth.test.ts
Normal file
85
resources/js/composables/__tests__/useAuth.test.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const mockPageProps = {
|
||||
auth: { user: null as any },
|
||||
flash: { success: null, error: null, message: null, status: null },
|
||||
authConfig: {
|
||||
appName: 'TestApp',
|
||||
features: {
|
||||
registration: true,
|
||||
password_reset: true,
|
||||
remember_me: true,
|
||||
email_verification: false,
|
||||
},
|
||||
login: { title: 'Login', description: '', icon: '', submit_label: 'Sign in' },
|
||||
register: { title: 'Register', description: '', icon: '', submit_label: 'Sign up' },
|
||||
forgotPassword: { title: 'Forgot', description: '', icon: '', submit_label: 'Send' },
|
||||
resetPassword: { title: 'Reset', description: '', icon: '', submit_label: 'Reset' },
|
||||
providers: [],
|
||||
legal: { terms_url: null, privacy_url: null, show_in_register: false },
|
||||
},
|
||||
}
|
||||
|
||||
vi.mock('@inertiajs/vue3', () => ({
|
||||
usePage: () => ({ props: mockPageProps }),
|
||||
}))
|
||||
|
||||
const { useAuth } = await import('../useAuth')
|
||||
|
||||
describe('useAuth', () => {
|
||||
it('returns null user when not authenticated', () => {
|
||||
mockPageProps.auth.user = null
|
||||
|
||||
const { user, isAuthenticated } = useAuth()
|
||||
|
||||
expect(user.value).toBeNull()
|
||||
expect(isAuthenticated.value).toBe(false)
|
||||
})
|
||||
|
||||
it('returns user when authenticated', () => {
|
||||
mockPageProps.auth.user = {
|
||||
id: 1,
|
||||
username: 'testuser',
|
||||
first_name: 'Test',
|
||||
last_name: 'User',
|
||||
full_name: 'Test User',
|
||||
email: 'test@example.com',
|
||||
email_verified_at: '2026-01-01',
|
||||
created_at: '2026-01-01',
|
||||
updated_at: '2026-01-01',
|
||||
}
|
||||
|
||||
const { user, isAuthenticated } = useAuth()
|
||||
|
||||
expect(user.value).not.toBeNull()
|
||||
expect(user.value!.username).toBe('testuser')
|
||||
expect(isAuthenticated.value).toBe(true)
|
||||
})
|
||||
|
||||
it('returns flash messages', () => {
|
||||
mockPageProps.flash.success = 'It worked!'
|
||||
|
||||
const { flash } = useAuth()
|
||||
|
||||
expect(flash.value.success).toBe('It worked!')
|
||||
})
|
||||
|
||||
it('returns auth config', () => {
|
||||
const { config } = useAuth()
|
||||
|
||||
expect(config.value.appName).toBe('TestApp')
|
||||
expect(config.value.features.registration).toBe(true)
|
||||
expect(config.value.features.email_verification).toBe(false)
|
||||
})
|
||||
|
||||
it('returns providers from config', () => {
|
||||
mockPageProps.authConfig.providers = [
|
||||
{ key: 'github', label: 'GitHub', icon: 'i-simple-icons-github' },
|
||||
]
|
||||
|
||||
const { config } = useAuth()
|
||||
|
||||
expect(config.value.providers).toHaveLength(1)
|
||||
expect(config.value.providers[0].key).toBe('github')
|
||||
})
|
||||
})
|
||||
169
resources/js/validation/__tests__/auth.test.ts
Normal file
169
resources/js/validation/__tests__/auth.test.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import * as v from 'valibot'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
completeProfileSchema,
|
||||
forgotPasswordSchema,
|
||||
loginSchema,
|
||||
registerSchema,
|
||||
resetPasswordSchema,
|
||||
} from '../auth'
|
||||
|
||||
function validate<T extends v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>>(schema: T, data: unknown) {
|
||||
return v.safeParse(schema, data)
|
||||
}
|
||||
|
||||
describe('loginSchema', () => {
|
||||
it('accepts valid login data', () => {
|
||||
const result = validate(loginSchema, { login: 'user@test.com', password: 'secret' })
|
||||
expect(result.success).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects empty login', () => {
|
||||
const result = validate(loginSchema, { login: '', password: 'secret' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects empty password', () => {
|
||||
const result = validate(loginSchema, { login: 'user', password: '' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('accepts optional remember field', () => {
|
||||
const result = validate(loginSchema, { login: 'user', password: 'secret', remember: true })
|
||||
expect(result.success).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('registerSchema', () => {
|
||||
const validData = {
|
||||
username: 'testuser',
|
||||
first_name: 'Test',
|
||||
last_name: 'User',
|
||||
email: 'test@example.com',
|
||||
password: 'password123',
|
||||
password_confirmation: 'password123',
|
||||
}
|
||||
|
||||
it('accepts valid registration data', () => {
|
||||
const result = validate(registerSchema, validData)
|
||||
expect(result.success).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects username shorter than 3 characters', () => {
|
||||
const result = validate(registerSchema, { ...validData, username: 'ab' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects username with spaces', () => {
|
||||
const result = validate(registerSchema, { ...validData, username: 'test user' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('accepts username with dashes and underscores', () => {
|
||||
const result = validate(registerSchema, { ...validData, username: 'test-user_123' })
|
||||
expect(result.success).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects invalid email', () => {
|
||||
const result = validate(registerSchema, { ...validData, email: 'not-an-email' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects password shorter than 8 characters', () => {
|
||||
const result = validate(registerSchema, { ...validData, password: 'short', password_confirmation: 'short' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects mismatched passwords', () => {
|
||||
const result = validate(registerSchema, { ...validData, password_confirmation: 'different123' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects empty first name', () => {
|
||||
const result = validate(registerSchema, { ...validData, first_name: '' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects empty last name', () => {
|
||||
const result = validate(registerSchema, { ...validData, last_name: '' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('forgotPasswordSchema', () => {
|
||||
it('accepts valid email', () => {
|
||||
const result = validate(forgotPasswordSchema, { email: 'test@example.com' })
|
||||
expect(result.success).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects empty email', () => {
|
||||
const result = validate(forgotPasswordSchema, { email: '' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects invalid email', () => {
|
||||
const result = validate(forgotPasswordSchema, { email: 'not-email' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('resetPasswordSchema', () => {
|
||||
const validData = {
|
||||
email: 'test@example.com',
|
||||
password: 'newpassword123',
|
||||
password_confirmation: 'newpassword123',
|
||||
}
|
||||
|
||||
it('accepts valid reset data', () => {
|
||||
const result = validate(resetPasswordSchema, validData)
|
||||
expect(result.success).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects mismatched passwords', () => {
|
||||
const result = validate(resetPasswordSchema, { ...validData, password_confirmation: 'different' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects password shorter than 8 characters', () => {
|
||||
const result = validate(resetPasswordSchema, { ...validData, password: 'short', password_confirmation: 'short' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects invalid email', () => {
|
||||
const result = validate(resetPasswordSchema, { ...validData, email: 'bad' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('completeProfileSchema', () => {
|
||||
const validData = {
|
||||
username: 'newuser',
|
||||
first_name: 'New',
|
||||
last_name: 'User',
|
||||
}
|
||||
|
||||
it('accepts valid profile data', () => {
|
||||
const result = validate(completeProfileSchema, validData)
|
||||
expect(result.success).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects username shorter than 3 characters', () => {
|
||||
const result = validate(completeProfileSchema, { ...validData, username: 'ab' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects username with special characters', () => {
|
||||
const result = validate(completeProfileSchema, { ...validData, username: 'user@name' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects empty first name', () => {
|
||||
const result = validate(completeProfileSchema, { ...validData, first_name: '' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects empty last name', () => {
|
||||
const result = validate(completeProfileSchema, { ...validData, last_name: '' })
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user