-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
115 photo input testing #271
base: improv/types
Are you sure you want to change the base?
Changes from all commits
b1b4e08
eecf00e
7e7d13d
67fa8a4
2657d76
c1d8185
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
//Command to run this test: yarn test src/__tests__/components/photoInput.test.tsx | ||
|
||
// Test suite for PhotoInput component | ||
import { render, screen, fireEvent } from '@testing-library/react' | ||
import { StoreContext } from '../../providers/store_provider' | ||
import PhotoInput, { PhotoInputProps } from '../../components/photo_input' | ||
import { type PhotoAttachment } from '../../utilities/photo_attachment_utils' | ||
|
||
// Mock URL.createObjectURL | ||
global.URL.createObjectURL = jest.fn() | ||
|
||
const mockStoreContext = { | ||
docId: 'TestDocID123', | ||
attachments: {}, | ||
metadata: {}, | ||
} | ||
|
||
const generateMockPhotoAttachment = (): PhotoAttachment => ({ | ||
attachmentId: 'photoAttachment1', | ||
attachment: { | ||
data: new Blob(['testImage'], { type: 'image/jpeg' }), | ||
content_type: 'image/jpeg', | ||
} as PouchDB.Core.FullAttachment, | ||
metadata: { | ||
timestamp: new Date().toISOString(), | ||
geolocation: { | ||
latitude: 47.6062, | ||
longitude: -122.3321, | ||
}, | ||
}, | ||
}) | ||
|
||
describe('PhotoInput Component', () => { | ||
const renderWithProps = (props: Partial<PhotoInputProps> = {}) => { | ||
const defaultProps: PhotoInputProps = { | ||
label: 'Test Label', | ||
uploadable: true, | ||
loading: false, | ||
error: undefined, | ||
count: 5, | ||
id: 'photo-input-id', | ||
notes: true, | ||
photoAttachments: [], | ||
onPutPhotoAttachment: jest.fn(), | ||
onRemovePhotoAttachment: jest.fn(), | ||
children: <div>Test Children</div>, | ||
} | ||
|
||
return render( | ||
<StoreContext.Provider value={mockStoreContext as any}> | ||
<PhotoInput {...defaultProps} {...props} /> | ||
</StoreContext.Provider>, | ||
) | ||
} | ||
|
||
test('renders label and children', () => { | ||
renderWithProps() | ||
expect(screen.getByText(/test label/i)).toBeInTheDocument() | ||
expect(screen.getByText(/test children/i)).toBeInTheDocument() | ||
}) | ||
|
||
test('can add a photo', async () => { | ||
const onPutPhotoAttachment = jest.fn() | ||
renderWithProps({ onPutPhotoAttachment }) | ||
const addPhotoButton = screen.getByText(/add photo/i) | ||
fireEvent.click(addPhotoButton) | ||
|
||
const input = screen.getByTestId('photo-input') | ||
const file = new File(['dummy'], 'photo.jpg', { type: 'image/jpeg' }) | ||
|
||
fireEvent.change(input, { target: { files: [file] } }) | ||
|
||
expect(onPutPhotoAttachment).toHaveBeenCalled() | ||
}) | ||
|
||
test('can delete a photo', async () => { | ||
const mockAttachment = generateMockPhotoAttachment() | ||
const onRemovePhotoAttachment = jest.fn() | ||
renderWithProps({ | ||
photoAttachments: [mockAttachment], | ||
onRemovePhotoAttachment, | ||
}) | ||
// const deleteButton = screen.getByTestId('photo-delete-button') | ||
const deleteButton = document.querySelector('.photo-delete-button') | ||
if (deleteButton) { | ||
fireEvent.click(deleteButton) | ||
|
||
await screen.findAllByText(/permanently delete/i) // Wait for modal to appear | ||
|
||
const confirmDeleteButton = screen.getByTestId( | ||
'permanently-delete-button', | ||
) | ||
fireEvent.click(confirmDeleteButton) | ||
|
||
expect(onRemovePhotoAttachment).toHaveBeenCalledTimes(1) | ||
} else { | ||
throw new Error('Delete button not found') | ||
} | ||
}) | ||
|
||
test('renders loading indicator', () => { | ||
renderWithProps({ loading: true }) | ||
expect(document.querySelector('.loader')).toBeInTheDocument() | ||
}) | ||
|
||
test('renders error message', () => { | ||
renderWithProps({ error: 'Image loading failed.' }) | ||
expect(screen.getByText(/image loading failed/i)).toBeInTheDocument() | ||
}) | ||
|
||
test('renders notes input if notes prop is true', () => { | ||
renderWithProps({ notes: true }) | ||
expect( | ||
screen.getByLabelText(/optional note about photo\(s\)/i), | ||
).toBeInTheDocument() | ||
}) | ||
|
||
test('does not render notes input if notes prop is false', () => { | ||
renderWithProps({ notes: false }) | ||
expect( | ||
screen.queryByLabelText(/optional note about photo\(s\)/i), | ||
).toBeNull() | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,7 @@ import TextInputWrapper from './text_input_wrapper' | |
import { type PhotoAttachment } from '../utilities/photo_attachment_utils' | ||
import { PHOTO_MIME_TYPES } from '../utilities/photo_utils' | ||
|
||
interface PhotoInputProps { | ||
export interface PhotoInputProps { | ||
label: string | ||
uploadable: boolean | ||
loading: boolean | ||
|
@@ -125,6 +125,7 @@ const PhotoInput: React.FC<PhotoInputProps> = ({ | |
</Button> | ||
<Button | ||
variant="danger" | ||
data-testid="permanently-delete-button" | ||
onClick={async () => { | ||
if (selectedPhotoAttachmentForDelete) { | ||
onRemovePhotoAttachment && | ||
|
@@ -147,6 +148,7 @@ const PhotoInput: React.FC<PhotoInputProps> = ({ | |
</Collapsible> | ||
<input | ||
ref={ref} | ||
data-testid="photo-input" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of adding the |
||
type="file" | ||
accept={PHOTO_MIME_TYPES.join(',')} | ||
capture={uploadable ? undefined : 'environment'} | ||
|
@@ -193,6 +195,7 @@ const PhotoInput: React.FC<PhotoInputProps> = ({ | |
<Button | ||
variant="danger" | ||
className="photo-delete-button" | ||
data-testid="photo-delete-button" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of adding the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @markborkum I just pushed a change that accomplishes this. I'm not a pro at Jest, but it seems like using querySelector forces the test to be a little more lengthy. ChatGPT is telling me that error handling is baked into the |
||
onClick={event => { | ||
event.stopPropagation() | ||
event.preventDefault() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of adding the
data-testid
prop, could you find this element with a CSS selector, e.g.,button.btn-danger
?