diff --git a/apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckAttachForm.test.tsx b/apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckAttachForm.test.tsx new file mode 100644 index 000000000..137a2d8ab --- /dev/null +++ b/apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckAttachForm.test.tsx @@ -0,0 +1,75 @@ +import { fireEvent, render, screen } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; +import { BackgroundCheckAttachForm, type AttachFormValues } from './BackgroundCheckAttachForm'; + +function renderForm(overrides: Partial[0]> = {}) { + const values: AttachFormValues = { vendor: 'other', reportDate: '2026-06-01', file: null }; + const props = { + values, + onChange: vi.fn(), + onSubmit: vi.fn(), + submitting: false, + canSubmit: true, + ...overrides, + }; + render(); + return props; +} + +function fileInput() { + return screen.getByLabelText(/background check report or identity document/i); +} + +describe('BackgroundCheckAttachForm', () => { + it('accepts a passport photo (the manual identity fallback)', () => { + const onChange = vi.fn(); + renderForm({ onChange }); + + const passport = new File([new Uint8Array([0xff, 0xd8, 0xff])], 'passport.jpg', { + type: 'image/jpeg', + }); + fireEvent.change(fileInput(), { target: { files: [passport] } }); + + expect(screen.queryByText(/only pdf files are accepted/i)).not.toBeInTheDocument(); + expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ file: passport })); + }); + + it('lets the native picker offer images, not just PDFs', () => { + renderForm(); + + const accept = fileInput().getAttribute('accept') ?? ''; + expect(accept).toContain('application/pdf'); + expect(accept).toMatch(/image\/png/); + expect(accept).toMatch(/image\/jpeg/); + expect(accept).toMatch(/image\/heic/); + }); + + it('still accepts a PDF report', () => { + const onChange = vi.fn(); + renderForm({ onChange }); + + const pdf = new File(['%PDF-1.7'], 'report.pdf', { type: 'application/pdf' }); + fireEvent.change(fileInput(), { target: { files: [pdf] } }); + + expect(screen.queryByText(/upload a pdf or image/i)).not.toBeInTheDocument(); + expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ file: pdf })); + }); + + it('rejects unsupported types and oversized files', () => { + const onChange = vi.fn(); + renderForm({ onChange }); + + const exe = new File([new Uint8Array([0x4d, 0x5a])], 'malware.exe', { + type: 'application/x-msdownload', + }); + fireEvent.change(fileInput(), { target: { files: [exe] } }); + expect(screen.getByText(/upload a pdf or image/i)).toBeInTheDocument(); + expect(onChange).not.toHaveBeenCalled(); + + const huge = new File(['x'], 'huge.png', { type: 'image/png' }); + Object.defineProperty(huge, 'size', { value: 26 * 1024 * 1024 }); + fireEvent.change(fileInput(), { target: { files: [huge] } }); + expect(screen.getByText(/exceeds 25 mb limit/i)).toBeInTheDocument(); + expect(onChange).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckAttachForm.tsx b/apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckAttachForm.tsx index cc7a4fb3f..eb004434a 100644 --- a/apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckAttachForm.tsx +++ b/apps/app/src/app/(app)/[orgId]/people/[employeeId]/components/BackgroundCheckAttachForm.tsx @@ -43,6 +43,21 @@ interface AttachFormProps { const MAX_FILE_BYTES = 25 * 1024 * 1024; +// Reports are usually PDFs, but the manual identity fallback is a passport +// photo (JPEG/PNG/HEIC). The API accepts these same types — see +// validateFileContent in apps/api/src/utils/file-type-validation.ts. +const ACCEPTED_MIME_TYPES = [ + 'application/pdf', + 'image/png', + 'image/jpeg', + 'image/webp', + 'image/heic', + 'image/heif', +]; + +const FILE_ACCEPT_ATTR = + 'application/pdf,image/png,image/jpeg,image/webp,image/heic,image/heif,.pdf,.png,.jpg,.jpeg,.webp,.heic,.heif'; + export function BackgroundCheckAttachForm({ values, onChange, @@ -65,8 +80,8 @@ export function BackgroundCheckAttachForm({ setFileError('File exceeds 25 MB limit.'); return; } - if (file.type && file.type !== 'application/pdf') { - setFileError('Only PDF files are accepted.'); + if (file.type && !ACCEPTED_MIME_TYPES.includes(file.type)) { + setFileError('Upload a PDF or image file (PDF, PNG, JPG, HEIC).'); return; } setFileError(null); @@ -125,10 +140,10 @@ export function BackgroundCheckAttachForm({
{ @@ -151,7 +166,7 @@ export function BackgroundCheckAttachForm({ <>Selected: {values.file.name} ) : ( <> - Drop the PDF here, or{' '} + Drop the file here, or{' '}