@@ -58,10 +58,10 @@ jest.mock('@/components/ui/multi-select', () => ({
5858
5959jest . mock ( '@/components/ui/select' , ( ) => {
6060 return {
61- Select : ( { children, onValueChange, value } : any ) => {
61+ Select : ( { children, onValueChange, value, ... props } : any ) => {
6262 return (
6363 < select
64- data-testid = "project-select"
64+ { ... props }
6565 value = { value }
6666 onChange = { ( e ) => onValueChange ?.( e . target . value ) }
6767 >
@@ -182,6 +182,12 @@ jest.mock('../TaskSkeleton', () => {
182182
183183global . fetch = jest . fn ( ) . mockResolvedValue ( { ok : true } ) ;
184184
185+ global . ResizeObserver = class ResizeObserver {
186+ observe ( ) { }
187+ unobserve ( ) { }
188+ disconnect ( ) { }
189+ } ;
190+
185191describe ( 'Tasks Component' , ( ) => {
186192 const localStorageMock = ( ( ) => {
187193 let store : { [ key : string ] : string } = { } ;
@@ -1229,7 +1235,7 @@ describe('Tasks Component', () => {
12291235 const editButton = within ( priorityRow ) . getByLabelText ( 'edit' ) ;
12301236 fireEvent . click ( editButton ) ;
12311237
1232- const select = within ( priorityRow ) . getByTestId ( 'project -select' ) ;
1238+ const select = within ( priorityRow ) . getByTestId ( 'priority -select' ) ;
12331239 fireEvent . change ( select , { target : { value : 'H' } } ) ;
12341240
12351241 const saveButton = screen . getByLabelText ( 'save' ) ;
@@ -1339,7 +1345,7 @@ describe('Tasks Component', () => {
13391345 const editButton = within ( recurRow ) . getByLabelText ( 'edit' ) ;
13401346 fireEvent . click ( editButton ) ;
13411347
1342- const select = within ( recurRow ) . getByTestId ( 'project -select' ) ;
1348+ const select = within ( recurRow ) . getByTestId ( 'recur -select' ) ;
13431349 fireEvent . change ( select , { target : { value : 'weekly' } } ) ;
13441350
13451351 const saveButton = screen . getByLabelText ( 'save' ) ;
@@ -1737,4 +1743,211 @@ describe('Tasks Component', () => {
17371743 expect ( task1Row ) . toBeInTheDocument ( ) ;
17381744 } ) ;
17391745 } ) ;
1746+
1747+ describe ( 'Recur Editing' , ( ) => {
1748+ test ( 'does not save when recur is set to "none"' , async ( ) => {
1749+ render ( < Tasks { ...mockProps } /> ) ;
1750+
1751+ await screen . findByText ( 'Task 12' ) ;
1752+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1753+
1754+ expect ( await screen . findByText ( 'Recur:' ) ) . toBeInTheDocument ( ) ;
1755+
1756+ const recurLabel = screen . getByText ( 'Recur:' ) ;
1757+ const recurRow = recurLabel . closest ( 'tr' ) as HTMLElement ;
1758+ const editButton = within ( recurRow ) . getByLabelText ( 'edit' ) ;
1759+
1760+ fireEvent . click ( editButton ) ;
1761+
1762+ const select = within ( recurRow ) . getByTestId ( 'recur-select' ) ;
1763+ fireEvent . change ( select , { target : { value : 'none' } } ) ;
1764+
1765+ const saveButton = screen . getByLabelText ( 'save' ) ;
1766+ fireEvent . click ( saveButton ) ;
1767+
1768+ const hooks = require ( '../hooks' ) ;
1769+ expect ( hooks . editTaskOnBackend ) . not . toHaveBeenCalled ( ) ;
1770+ } ) ;
1771+
1772+ test ( 'saves recur when a valid value is selected' , async ( ) => {
1773+ render ( < Tasks { ...mockProps } /> ) ;
1774+
1775+ await screen . findByText ( 'Task 12' ) ;
1776+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1777+
1778+ expect ( await screen . findByText ( 'Recur:' ) ) . toBeInTheDocument ( ) ;
1779+
1780+ const recurLabel = screen . getByText ( 'Recur:' ) ;
1781+ const recurRow = recurLabel . closest ( 'tr' ) as HTMLElement ;
1782+ const editButton = within ( recurRow ) . getByLabelText ( 'edit' ) ;
1783+
1784+ fireEvent . click ( editButton ) ;
1785+
1786+ const select = within ( recurRow ) . getByTestId ( 'recur-select' ) ;
1787+ fireEvent . change ( select , { target : { value : 'daily' } } ) ;
1788+
1789+ const saveButton = screen . getByLabelText ( 'save' ) ;
1790+ fireEvent . click ( saveButton ) ;
1791+
1792+ const hooks = require ( '../hooks' ) ;
1793+ expect ( hooks . editTaskOnBackend ) . toHaveBeenCalledWith (
1794+ expect . objectContaining ( { recur : 'daily' } )
1795+ ) ;
1796+ } ) ;
1797+
1798+ test ( 'does not save when recur is empty string' , async ( ) => {
1799+ render ( < Tasks { ...mockProps } /> ) ;
1800+
1801+ await screen . findByText ( 'Task 12' ) ;
1802+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1803+
1804+ expect ( await screen . findByText ( 'Recur:' ) ) . toBeInTheDocument ( ) ;
1805+
1806+ const recurLabel = screen . getByText ( 'Recur:' ) ;
1807+ const recurRow = recurLabel . closest ( 'tr' ) as HTMLElement ;
1808+ const editButton = within ( recurRow ) . getByLabelText ( 'edit' ) ;
1809+ fireEvent . click ( editButton ) ;
1810+
1811+ const select = within ( recurRow ) . getByTestId ( 'recur-select' ) ;
1812+ fireEvent . change ( select , { target : { value : '' } } ) ;
1813+ const saveButton = within ( recurRow ) . getByLabelText ( 'save' ) ;
1814+ fireEvent . click ( saveButton ) ;
1815+
1816+ const hooks = require ( '../hooks' ) ;
1817+ expect ( hooks . editTaskOnBackend ) . not . toHaveBeenCalled ( ) ;
1818+ } ) ;
1819+ } ) ;
1820+
1821+ describe ( 'Priority Editing' , ( ) => {
1822+ test ( 'saving priority calls modifyTaskOnBackend with correct value' , async ( ) => {
1823+ render ( < Tasks { ...mockProps } /> ) ;
1824+
1825+ await screen . findByText ( 'Task 12' ) ;
1826+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1827+
1828+ expect ( await screen . findByText ( 'Priority:' ) ) . toBeInTheDocument ( ) ;
1829+
1830+ const priorityLabel = screen . getByText ( 'Priority:' ) ;
1831+ const priorityRow = priorityLabel . closest ( 'tr' ) as HTMLElement ;
1832+ const editButton = within ( priorityRow ) . getByLabelText ( 'edit' ) ;
1833+ fireEvent . click ( editButton ) ;
1834+
1835+ const select = within ( priorityRow ) . getByTestId ( 'priority-select' ) ;
1836+ fireEvent . change ( select , { target : { value : 'H' } } ) ;
1837+
1838+ const saveButton = screen . getByLabelText ( 'save' ) ;
1839+ fireEvent . click ( saveButton ) ;
1840+
1841+ await waitFor ( ( ) => {
1842+ const hooks = require ( '../hooks' ) ;
1843+ expect ( hooks . modifyTaskOnBackend ) . toHaveBeenCalledWith (
1844+ expect . objectContaining ( { priority : 'H' } )
1845+ ) ;
1846+ } ) ;
1847+ } ) ;
1848+
1849+ test ( 'saving "NONE" priority sends empty string to backend' , async ( ) => {
1850+ render ( < Tasks { ...mockProps } /> ) ;
1851+
1852+ await screen . findByText ( 'Task 12' ) ;
1853+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1854+
1855+ expect ( await screen . findByText ( 'Priority:' ) ) . toBeInTheDocument ( ) ;
1856+
1857+ const priorityLabel = screen . getByText ( 'Priority:' ) ;
1858+ const priorityRow = priorityLabel . closest ( 'tr' ) as HTMLElement ;
1859+ const editButton = within ( priorityRow ) . getByLabelText ( 'edit' ) ;
1860+ fireEvent . click ( editButton ) ;
1861+
1862+ const select = within ( priorityRow ) . getByTestId ( 'priority-select' ) ;
1863+ fireEvent . change ( select , { target : { value : 'NONE' } } ) ;
1864+
1865+ const saveButton = screen . getByLabelText ( 'save' ) ;
1866+ fireEvent . click ( saveButton ) ;
1867+
1868+ await waitFor ( ( ) => {
1869+ const hooks = require ( '../hooks' ) ;
1870+ expect ( hooks . modifyTaskOnBackend ) . toHaveBeenCalledWith (
1871+ expect . objectContaining ( {
1872+ priority : '' ,
1873+ } )
1874+ ) ;
1875+ } ) ;
1876+ } ) ;
1877+
1878+ test ( 'shows error toast when priority save fails' , async ( ) => {
1879+ const { toast } = require ( 'react-toastify' ) ;
1880+ const hooks = require ( '../hooks' ) ;
1881+
1882+ hooks . modifyTaskOnBackend . mockRejectedValueOnce (
1883+ new Error ( 'Network error' )
1884+ ) ;
1885+
1886+ render ( < Tasks { ...mockProps } /> ) ;
1887+ await screen . findByText ( 'Task 12' ) ;
1888+
1889+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1890+
1891+ await waitFor ( ( ) => {
1892+ expect ( screen . getByText ( 'Priority:' ) ) . toBeInTheDocument ( ) ;
1893+ } ) ;
1894+
1895+ const priorityLabel = screen . getByText ( 'Priority:' ) ;
1896+ const priorityRow = priorityLabel . closest ( 'tr' ) as HTMLElement ;
1897+
1898+ const editButton = within ( priorityRow ) . getByLabelText ( 'edit' ) ;
1899+ fireEvent . click ( editButton ) ;
1900+
1901+ const select = within ( priorityRow ) . getByTestId ( 'priority-select' ) ;
1902+ fireEvent . change ( select , { target : { value : 'H' } } ) ;
1903+
1904+ const saveButton = within ( priorityRow ) . getByLabelText ( 'save' ) ;
1905+ fireEvent . click ( saveButton ) ;
1906+
1907+ await waitFor ( ( ) => {
1908+ expect ( toast . error ) . toHaveBeenCalledWith (
1909+ expect . stringContaining ( 'Failed to update priority' )
1910+ ) ;
1911+ } ) ;
1912+ } ) ;
1913+ } ) ;
1914+
1915+ describe ( 'Reports Toggle' , ( ) => {
1916+ test ( 'clicking "Show Reports" button switches view from tasks to reports' , async ( ) => {
1917+ render ( < Tasks { ...mockProps } /> ) ;
1918+
1919+ await screen . findByText ( 'Task 1' ) ;
1920+
1921+ expect ( screen . getByText ( 'Here are' ) ) . toBeInTheDocument ( ) ;
1922+
1923+ const toggleBtn = screen . getByRole ( 'button' , { name : / s h o w r e p o r t s / i } ) ;
1924+ fireEvent . click ( toggleBtn ) ;
1925+
1926+ expect (
1927+ screen . getByRole ( 'button' , { name : / s h o w t a s k s / i } )
1928+ ) . toBeInTheDocument ( ) ;
1929+ } ) ;
1930+
1931+ test ( 'clicking "Show Tasks" returns to task list view' , async ( ) => {
1932+ render ( < Tasks { ...mockProps } /> ) ;
1933+ await screen . findByText ( 'Task 1' ) ;
1934+
1935+ fireEvent . click ( screen . getByRole ( 'button' , { name : / s h o w r e p o r t s / i } ) ) ;
1936+ fireEvent . click ( screen . getByRole ( 'button' , { name : / s h o w t a s k s / i } ) ) ;
1937+
1938+ expect ( screen . getByText ( 'Task 1' ) ) . toBeInTheDocument ( ) ;
1939+ } ) ;
1940+
1941+ test ( 'hotkeys are disabled when reports view is shown' , async ( ) => {
1942+ render ( < Tasks { ...mockProps } /> ) ;
1943+ await screen . findByText ( 'Task 1' ) ;
1944+
1945+ fireEvent . click ( screen . getByRole ( 'button' , { name : / s h o w r e p o r t s / i } ) ) ;
1946+ fireEvent . keyDown ( window , { key : 'a' } ) ;
1947+
1948+ expect (
1949+ screen . queryByText ( / f i l l i n t h e d e t a i l s b e l o w / i)
1950+ ) . not . toBeInTheDocument ( ) ;
1951+ } ) ;
1952+ } ) ;
17401953} ) ;
0 commit comments