Skip to content
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

Open
wants to merge 6 commits into
base: improv/types
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions src/__tests__/components/photoInput.test.tsx
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()
})
})
5 changes: 4 additions & 1 deletion src/components/photo_input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -125,6 +125,7 @@ const PhotoInput: React.FC<PhotoInputProps> = ({
</Button>
<Button
variant="danger"
data-testid="permanently-delete-button"
Copy link
Collaborator

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?

onClick={async () => {
if (selectedPhotoAttachmentForDelete) {
onRemovePhotoAttachment &&
Expand All @@ -147,6 +148,7 @@ const PhotoInput: React.FC<PhotoInputProps> = ({
</Collapsible>
<input
ref={ref}
data-testid="photo-input"
Copy link
Collaborator

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.btn-outline-primary?

type="file"
accept={PHOTO_MIME_TYPES.join(',')}
capture={uploadable ? undefined : 'environment'}
Expand Down Expand Up @@ -193,6 +195,7 @@ const PhotoInput: React.FC<PhotoInputProps> = ({
<Button
variant="danger"
className="photo-delete-button"
data-testid="photo-delete-button"
Copy link
Collaborator

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.photo-delete-button?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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 getByTestId method. If you like this solution better, I will do this for the tests and remove the data-testid attributes.

onClick={event => {
event.stopPropagation()
event.preventDefault()
Expand Down
Loading