diff --git a/frontend/src/components/InlineEditCell.test.tsx b/frontend/src/components/InlineEditCell.test.tsx
index 3b43af3..8e7f1ec 100644
--- a/frontend/src/components/InlineEditCell.test.tsx
+++ b/frontend/src/components/InlineEditCell.test.tsx
@@ -103,4 +103,89 @@ describe('InlineEditCell', () => {
expect(onSave).toHaveBeenCalledWith(99)
})
+
+ // New tests for pencil icon and callbacks
+ it('renders a pencil icon in display mode', () => {
+ render(
+
+
+
+ )
+ // Pencil icon from lucide-react renders as an SVG — query by its test-id or aria role
+ // The Pencil icon should be present in the DOM (opacity-0, shown on hover via CSS)
+ const pencilIcon = document.querySelector('svg[data-testid="pencil-icon"]') ||
+ document.querySelector('.lucide-pencil')
+ expect(pencilIcon).not.toBeNull()
+ })
+
+ it('calls onSaveSuccess callback after successful save', async () => {
+ const user = userEvent.setup()
+ const onSave = vi.fn().mockResolvedValue(undefined)
+ const onSaveSuccess = vi.fn()
+ render(
+
+
+
+ )
+ const span = screen.getByText(/42/)
+ await user.click(span)
+
+ const input = screen.getByRole('spinbutton')
+ await user.clear(input)
+ await user.type(input, '100')
+ fireEvent.blur(input)
+
+ // Wait for async operations
+ await vi.waitFor(() => {
+ expect(onSaveSuccess).toHaveBeenCalledTimes(1)
+ })
+ })
+
+ it('calls onSaveError and reverts value when onSave rejects', async () => {
+ const user = userEvent.setup()
+ const onSave = vi.fn().mockRejectedValue(new Error('Save failed'))
+ const onSaveError = vi.fn()
+ render(
+
+
+
+ )
+ const span = screen.getByText(/42/)
+ await user.click(span)
+
+ const input = screen.getByRole('spinbutton')
+ await user.clear(input)
+ await user.type(input, '999')
+ fireEvent.blur(input)
+
+ // Wait for async operations
+ await vi.waitFor(() => {
+ expect(onSaveError).toHaveBeenCalledTimes(1)
+ })
+
+ // Value should revert back to original — display mode shows original value
+ await vi.waitFor(() => {
+ expect(screen.getByText(/42/)).toBeInTheDocument()
+ })
+ })
+
+ it('does not call onSaveSuccess when value is unchanged', async () => {
+ const user = userEvent.setup()
+ const onSave = vi.fn().mockResolvedValue(undefined)
+ const onSaveSuccess = vi.fn()
+ render(
+
+
+
+ )
+ const span = screen.getByText(/42/)
+ await user.click(span)
+
+ // Don't change the value, just blur
+ const input = screen.getByRole('spinbutton')
+ fireEvent.blur(input)
+
+ expect(onSave).not.toHaveBeenCalled()
+ expect(onSaveSuccess).not.toHaveBeenCalled()
+ })
})