docs(17): create phase plan for Jest unit tests
Phase 17: Unit Tests (Jest) - 1 plan in 1 wave - 1 parallel, 0 sequential - Covers UNIT-01, UNIT-02, UNIT-03 requirements - Ready for execution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c5600e9315
commit
44cc57ad85
|
|
@ -0,0 +1,325 @@
|
|||
---
|
||||
phase: 17-unit-tests-jest
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- jam-ui/src/components/client/__tests__/JKSessionSettingsModal.test.js
|
||||
autonomous: true
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Test file exists and runs without errors"
|
||||
- "UNIT-01: Test verifies modal renders with currentSession props (privacy, description displayed)"
|
||||
- "UNIT-02: Test verifies save button calls onSave with correctly transformed payload"
|
||||
- "UNIT-03: Test verifies loading state disables form interactions"
|
||||
- "All tests pass with npm run test:unit"
|
||||
artifacts:
|
||||
- path: "jam-ui/src/components/client/__tests__/JKSessionSettingsModal.test.js"
|
||||
provides: "Jest unit tests for JKSessionSettingsModal component"
|
||||
min_lines: 80
|
||||
contains: "describe('JKSessionSettingsModal'"
|
||||
key_links:
|
||||
- from: "JKSessionSettingsModal.test.js"
|
||||
to: "JKSessionSettingsModal.js"
|
||||
via: "import"
|
||||
pattern: "import JKSessionSettingsModal from"
|
||||
- from: "JKSessionSettingsModal.test.js"
|
||||
to: "globals.js"
|
||||
via: "import SESSION_PRIVACY_MAP"
|
||||
pattern: "SESSION_PRIVACY_MAP"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Create Jest unit tests for JKSessionSettingsModal component covering all three requirements: rendering with props, save payload transformation, and loading state behavior.
|
||||
|
||||
Purpose: Enable confident changes to Session Settings modal by having automated test coverage for critical paths
|
||||
Output: Test file with passing tests for UNIT-01, UNIT-02, UNIT-03
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@/Users/nuwan/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@/Users/nuwan/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
|
||||
# Component under test
|
||||
@jam-ui/src/components/client/JKSessionSettingsModal.js
|
||||
|
||||
# Existing test pattern to follow
|
||||
@jam-ui/src/components/client/chat/__tests__/JKChatMessageList.test.js
|
||||
|
||||
# Globals with SESSION_PRIVACY_MAP
|
||||
@jam-ui/src/helpers/globals.js
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create test file with setup and mocks</name>
|
||||
<files>jam-ui/src/components/client/__tests__/JKSessionSettingsModal.test.js</files>
|
||||
<action>
|
||||
Create the __tests__ directory if needed and test file with proper setup:
|
||||
|
||||
1. Create directory structure:
|
||||
- `jam-ui/src/components/client/__tests__/` (may already exist)
|
||||
|
||||
2. Set up test file with required imports:
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import JKSessionSettingsModal from '../JKSessionSettingsModal';
|
||||
import { SESSION_PRIVACY_MAP } from '../../../helpers/globals.js';
|
||||
```
|
||||
|
||||
3. Mock react-i18next (required because component uses useTranslation):
|
||||
```javascript
|
||||
jest.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key) => {
|
||||
const translations = {
|
||||
'new.privacy_opt_public': 'Public',
|
||||
'new.privacy_opt_private_invite': 'Private (Invite Only)',
|
||||
'new.privacy_opt_private_approve': 'Private (Approval Required)'
|
||||
};
|
||||
return translations[key] || key;
|
||||
}
|
||||
})
|
||||
}));
|
||||
```
|
||||
|
||||
4. Create helper function for rendering component:
|
||||
```javascript
|
||||
const renderModal = (props = {}) => {
|
||||
const defaultProps = {
|
||||
isOpen: true,
|
||||
toggle: jest.fn(),
|
||||
currentSession: {
|
||||
privacy: SESSION_PRIVACY_MAP.private_approve,
|
||||
description: 'Test session description'
|
||||
},
|
||||
onSave: jest.fn(),
|
||||
loading: false
|
||||
};
|
||||
return render(<JKSessionSettingsModal {...defaultProps} {...props} />);
|
||||
};
|
||||
```
|
||||
|
||||
5. Add describe block shell:
|
||||
```javascript
|
||||
describe('JKSessionSettingsModal', () => {
|
||||
// Tests will be added in next task
|
||||
});
|
||||
```
|
||||
</action>
|
||||
<verify>
|
||||
File exists at jam-ui/src/components/client/__tests__/JKSessionSettingsModal.test.js
|
||||
File compiles without syntax errors: `cd jam-ui && npm run test:unit -- --testPathPattern=JKSessionSettingsModal --passWithNoTests`
|
||||
</verify>
|
||||
<done>Test file created with all setup code, mocks, and helper functions in place</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Write tests for all three requirements</name>
|
||||
<files>jam-ui/src/components/client/__tests__/JKSessionSettingsModal.test.js</files>
|
||||
<action>
|
||||
Add test cases inside the describe block for each requirement:
|
||||
|
||||
**UNIT-01: Modal renders with currentSession props**
|
||||
```javascript
|
||||
describe('rendering with currentSession props (UNIT-01)', () => {
|
||||
test('displays privacy value from currentSession', () => {
|
||||
renderModal({
|
||||
currentSession: {
|
||||
privacy: SESSION_PRIVACY_MAP.public,
|
||||
description: ''
|
||||
}
|
||||
});
|
||||
|
||||
const privacySelect = screen.getByTestId('session-privacy');
|
||||
expect(privacySelect.value).toBe(String(SESSION_PRIVACY_MAP.public));
|
||||
});
|
||||
|
||||
test('displays description value from currentSession', () => {
|
||||
const testDescription = 'My test session description';
|
||||
renderModal({
|
||||
currentSession: {
|
||||
privacy: SESSION_PRIVACY_MAP.private_approve,
|
||||
description: testDescription
|
||||
}
|
||||
});
|
||||
|
||||
const descriptionInput = screen.getByRole('textbox');
|
||||
expect(descriptionInput.value).toBe(testDescription);
|
||||
});
|
||||
|
||||
test('renders modal title', () => {
|
||||
renderModal();
|
||||
expect(screen.getByText('Session Settings')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**UNIT-02: Save button calls onSave with correct payload**
|
||||
```javascript
|
||||
describe('save functionality (UNIT-02)', () => {
|
||||
test('calls onSave with privacy and description when save clicked', () => {
|
||||
const mockOnSave = jest.fn();
|
||||
renderModal({
|
||||
currentSession: {
|
||||
privacy: SESSION_PRIVACY_MAP.public,
|
||||
description: 'Original description'
|
||||
},
|
||||
onSave: mockOnSave
|
||||
});
|
||||
|
||||
const saveButton = screen.getByRole('button', { name: /save/i });
|
||||
fireEvent.click(saveButton);
|
||||
|
||||
expect(mockOnSave).toHaveBeenCalledTimes(1);
|
||||
expect(mockOnSave).toHaveBeenCalledWith({
|
||||
privacy: String(SESSION_PRIVACY_MAP.public),
|
||||
description: 'Original description'
|
||||
});
|
||||
});
|
||||
|
||||
test('calls onSave with updated values after user changes', () => {
|
||||
const mockOnSave = jest.fn();
|
||||
renderModal({
|
||||
currentSession: {
|
||||
privacy: SESSION_PRIVACY_MAP.private_approve,
|
||||
description: ''
|
||||
},
|
||||
onSave: mockOnSave
|
||||
});
|
||||
|
||||
// Change privacy
|
||||
const privacySelect = screen.getByTestId('session-privacy');
|
||||
fireEvent.change(privacySelect, { target: { value: SESSION_PRIVACY_MAP.public } });
|
||||
|
||||
// Change description
|
||||
const descriptionInput = screen.getByRole('textbox');
|
||||
fireEvent.change(descriptionInput, { target: { value: 'New description' } });
|
||||
|
||||
// Click save
|
||||
const saveButton = screen.getByRole('button', { name: /save/i });
|
||||
fireEvent.click(saveButton);
|
||||
|
||||
expect(mockOnSave).toHaveBeenCalledWith({
|
||||
privacy: String(SESSION_PRIVACY_MAP.public),
|
||||
description: 'New description'
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**UNIT-03: Loading state disables form interactions**
|
||||
```javascript
|
||||
describe('loading state (UNIT-03)', () => {
|
||||
test('disables save button when loading', () => {
|
||||
renderModal({ loading: true });
|
||||
|
||||
const saveButton = screen.getByRole('button', { name: /saving/i });
|
||||
expect(saveButton).toBeDisabled();
|
||||
});
|
||||
|
||||
test('disables cancel button when loading', () => {
|
||||
renderModal({ loading: true });
|
||||
|
||||
const cancelButton = screen.getByRole('button', { name: /cancel/i });
|
||||
expect(cancelButton).toBeDisabled();
|
||||
});
|
||||
|
||||
test('disables description textarea when loading', () => {
|
||||
renderModal({ loading: true });
|
||||
|
||||
const descriptionInput = screen.getByRole('textbox');
|
||||
expect(descriptionInput).toBeDisabled();
|
||||
});
|
||||
|
||||
test('shows "Saving..." text on save button when loading', () => {
|
||||
renderModal({ loading: true });
|
||||
|
||||
expect(screen.getByRole('button', { name: /saving/i })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Note: The privacy select dropdown is NOT disabled when loading (based on component code review - only description textarea has `disabled={loading}`). The tests reflect actual component behavior.
|
||||
</action>
|
||||
<verify>
|
||||
Run tests: `cd jam-ui && npm run test:unit -- --testPathPattern=JKSessionSettingsModal`
|
||||
All tests pass (exit code 0)
|
||||
</verify>
|
||||
<done>
|
||||
All three requirements covered with passing tests:
|
||||
- UNIT-01: 3 tests for rendering (privacy, description, title)
|
||||
- UNIT-02: 2 tests for save functionality (initial values, updated values)
|
||||
- UNIT-03: 4 tests for loading state (save disabled, cancel disabled, textarea disabled, button text)
|
||||
</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Verify full test suite and clean up</name>
|
||||
<files>jam-ui/src/components/client/__tests__/JKSessionSettingsModal.test.js</files>
|
||||
<action>
|
||||
1. Run full unit test suite to ensure no regressions:
|
||||
```bash
|
||||
cd jam-ui && npm run test:unit
|
||||
```
|
||||
|
||||
2. Verify test count matches expectations (9 tests total: 3 + 2 + 4)
|
||||
|
||||
3. Check test output shows all test names correctly grouped:
|
||||
- JKSessionSettingsModal
|
||||
- rendering with currentSession props (UNIT-01)
|
||||
- save functionality (UNIT-02)
|
||||
- loading state (UNIT-03)
|
||||
|
||||
4. If any tests fail, debug and fix:
|
||||
- Check if component behavior differs from expectations
|
||||
- Adjust test assertions to match actual component behavior
|
||||
- Do NOT modify the component - only fix test expectations
|
||||
|
||||
5. Add any missing edge case tests if time permits:
|
||||
- Empty description handling
|
||||
- Default privacy value when currentSession.privacy is undefined
|
||||
</action>
|
||||
<verify>
|
||||
`cd jam-ui && npm run test:unit` passes with 0 failures
|
||||
Test file has proper structure with requirement labels in describe blocks
|
||||
</verify>
|
||||
<done>
|
||||
All unit tests pass, test file is complete and properly structured with requirement traceability (UNIT-01, UNIT-02, UNIT-03)
|
||||
</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
1. Test file exists: `ls jam-ui/src/components/client/__tests__/JKSessionSettingsModal.test.js`
|
||||
2. All tests pass: `cd jam-ui && npm run test:unit -- --testPathPattern=JKSessionSettingsModal`
|
||||
3. Full unit test suite passes: `cd jam-ui && npm run test:unit`
|
||||
4. Requirement coverage:
|
||||
- UNIT-01: Tests in "rendering with currentSession props" describe block
|
||||
- UNIT-02: Tests in "save functionality" describe block
|
||||
- UNIT-03: Tests in "loading state" describe block
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
1. Test file exists at `jam-ui/src/components/client/__tests__/JKSessionSettingsModal.test.js`
|
||||
2. UNIT-01 covered: Tests verify privacy and description from currentSession are displayed
|
||||
3. UNIT-02 covered: Tests verify onSave called with correct payload on save click
|
||||
4. UNIT-03 covered: Tests verify loading state disables save button, cancel button, and description input
|
||||
5. All tests pass with `npm run test:unit`
|
||||
6. No regressions in existing test suite
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/17-unit-tests-jest/17-01-SUMMARY.md`
|
||||
</output>
|
||||
Loading…
Reference in New Issue