feat: enhance child edit and view components with improved form handling and validation
All checks were successful
Chore App Build and Push Docker Images / build-and-push (push) Successful in 1m4s
All checks were successful
Chore App Build and Push Docker Images / build-and-push (push) Successful in 1m4s
- Added `requireDirty` prop to `EntityEditForm` for dirty state management. - Updated `ChildEditView` to handle initial data loading and image selection more robustly. - Refactored `ChildView` to remove unused reward dialog logic and prevent API calls in child mode. - Improved type definitions for form fields and initial data in `ChildEditView`. - Enhanced error handling in form submissions across components. - Implemented cross-tab logout synchronization on password reset in the auth store. - Added tests for login and entity edit form functionalities to ensure proper behavior. - Introduced global fetch interceptor for handling unauthorized responses. - Documented password reset flow and its implications on session management.
This commit is contained in:
81
frontend/vue-app/src/components/auth/__tests__/Login.spec.ts
Normal file
81
frontend/vue-app/src/components/auth/__tests__/Login.spec.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Login from '../Login.vue'
|
||||
|
||||
const { pushMock, loginUserMock, checkAuthMock } = vi.hoisted(() => ({
|
||||
pushMock: vi.fn(),
|
||||
loginUserMock: vi.fn(),
|
||||
checkAuthMock: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('vue-router', () => ({
|
||||
useRouter: vi.fn(() => ({ push: pushMock })),
|
||||
}))
|
||||
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
loginUser: loginUserMock,
|
||||
checkAuth: checkAuthMock,
|
||||
}))
|
||||
|
||||
vi.mock('@/common/api', async () => {
|
||||
const actual = await vi.importActual<typeof import('@/common/api')>('@/common/api')
|
||||
return {
|
||||
...actual,
|
||||
parseErrorResponse: vi.fn(async () => ({
|
||||
msg: 'bad credentials',
|
||||
code: 'INVALID_CREDENTIALS',
|
||||
})),
|
||||
}
|
||||
})
|
||||
|
||||
describe('Login.vue', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
checkAuthMock.mockResolvedValue(undefined)
|
||||
vi.stubGlobal('fetch', vi.fn())
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
it('hydrates auth state after successful login', async () => {
|
||||
const fetchMock = vi.mocked(fetch)
|
||||
fetchMock.mockResolvedValue({ ok: true } as Response)
|
||||
|
||||
const wrapper = mount(Login)
|
||||
|
||||
await wrapper.get('#email').setValue('test@example.com')
|
||||
await wrapper.get('#password').setValue('secret123')
|
||||
await wrapper.get('form').trigger('submit')
|
||||
|
||||
await Promise.resolve()
|
||||
|
||||
expect(loginUserMock).toHaveBeenCalledTimes(1)
|
||||
expect(checkAuthMock).toHaveBeenCalledTimes(1)
|
||||
expect(pushMock).toHaveBeenCalledWith({ path: '/' })
|
||||
|
||||
const checkAuthOrder = checkAuthMock.mock.invocationCallOrder[0]
|
||||
const pushOrder = pushMock.mock.invocationCallOrder[0]
|
||||
expect(checkAuthOrder).toBeDefined()
|
||||
expect(pushOrder).toBeDefined()
|
||||
expect((checkAuthOrder ?? 0) < (pushOrder ?? 0)).toBe(true)
|
||||
})
|
||||
|
||||
it('does not hydrate auth state when login fails', async () => {
|
||||
const fetchMock = vi.mocked(fetch)
|
||||
fetchMock.mockResolvedValue({ ok: false, status: 401 } as Response)
|
||||
|
||||
const wrapper = mount(Login)
|
||||
|
||||
await wrapper.get('#email').setValue('test@example.com')
|
||||
await wrapper.get('#password').setValue('badpassword')
|
||||
await wrapper.get('form').trigger('submit')
|
||||
|
||||
await Promise.resolve()
|
||||
|
||||
expect(loginUserMock).not.toHaveBeenCalled()
|
||||
expect(checkAuthMock).not.toHaveBeenCalled()
|
||||
expect(pushMock).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user