@@ -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,219 @@ 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+ await waitFor ( ( ) => {
1755+ expect ( screen . getByText ( 'Recur:' ) ) . toBeInTheDocument ( ) ;
1756+ } ) ;
1757+
1758+ const recurLabel = screen . getByText ( 'Recur:' ) ;
1759+ const recurRow = recurLabel . closest ( 'tr' ) as HTMLElement ;
1760+ const editButton = within ( recurRow ) . getByLabelText ( 'edit' ) ;
1761+
1762+ fireEvent . click ( editButton ) ;
1763+
1764+ const select = within ( recurRow ) . getByTestId ( 'recur-select' ) ;
1765+ fireEvent . change ( select , { target : { value : 'none' } } ) ;
1766+
1767+ const saveButton = screen . getByLabelText ( 'save' ) ;
1768+ fireEvent . click ( saveButton ) ;
1769+
1770+ const hooks = require ( '../hooks' ) ;
1771+ expect ( hooks . editTaskOnBackend ) . not . toHaveBeenCalled ( ) ;
1772+ } ) ;
1773+
1774+ test ( 'saves recur when a valid value is selected' , async ( ) => {
1775+ render ( < Tasks { ...mockProps } /> ) ;
1776+
1777+ await screen . findByText ( 'Task 12' ) ;
1778+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1779+
1780+ await waitFor ( ( ) => {
1781+ expect ( screen . getByText ( 'Recur:' ) ) . toBeInTheDocument ( ) ;
1782+ } ) ;
1783+
1784+ const recurLabel = screen . getByText ( 'Recur:' ) ;
1785+ const recurRow = recurLabel . closest ( 'tr' ) as HTMLElement ;
1786+ const editButton = within ( recurRow ) . getByLabelText ( 'edit' ) ;
1787+
1788+ fireEvent . click ( editButton ) ;
1789+
1790+ const select = within ( recurRow ) . getByTestId ( 'recur-select' ) ;
1791+ fireEvent . change ( select , { target : { value : 'daily' } } ) ;
1792+
1793+ const saveButton = screen . getByLabelText ( 'save' ) ;
1794+ fireEvent . click ( saveButton ) ;
1795+
1796+ const hooks = require ( '../hooks' ) ;
1797+ expect ( hooks . editTaskOnBackend ) . toHaveBeenCalled ( ) ;
1798+ } ) ;
1799+
1800+ test ( 'does not save when recur is empty string' , async ( ) => {
1801+ render ( < Tasks { ...mockProps } /> ) ;
1802+
1803+ await screen . findByText ( 'Task 12' ) ;
1804+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1805+
1806+ await waitFor ( ( ) => {
1807+ expect ( screen . getByText ( 'Recur:' ) ) . toBeInTheDocument ( ) ;
1808+ } ) ;
1809+
1810+ const recurLabel = screen . getByText ( 'Recur:' ) ;
1811+ const recurRow = recurLabel . closest ( 'tr' ) as HTMLElement ;
1812+ const editButton = within ( recurRow ) . getByLabelText ( 'edit' ) ;
1813+ fireEvent . click ( editButton ) ;
1814+
1815+ const select = within ( recurRow ) . getByTestId ( 'recur-select' ) ;
1816+ fireEvent . change ( select , { target : { value : '' } } ) ;
1817+ const saveButton = within ( recurRow ) . getByLabelText ( 'save' ) ;
1818+ fireEvent . click ( saveButton ) ;
1819+
1820+ const hooks = require ( '../hooks' ) ;
1821+ expect ( hooks . editTaskOnBackend ) . not . toHaveBeenCalled ( ) ;
1822+ } ) ;
1823+ } ) ;
1824+
1825+ describe ( 'Priority Editing' , ( ) => {
1826+ test ( 'saving priority calls modifyTaskOnBackend with correct value' , async ( ) => {
1827+ render ( < Tasks { ...mockProps } /> ) ;
1828+
1829+ await screen . findByText ( 'Task 12' ) ;
1830+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1831+
1832+ await waitFor ( ( ) => {
1833+ expect ( screen . getByText ( 'Priority:' ) ) . toBeInTheDocument ( ) ;
1834+ } ) ;
1835+
1836+ const priorityLabel = screen . getByText ( 'Priority:' ) ;
1837+ const priorityRow = priorityLabel . closest ( 'tr' ) as HTMLElement ;
1838+ const editButton = within ( priorityRow ) . getByLabelText ( 'edit' ) ;
1839+ fireEvent . click ( editButton ) ;
1840+
1841+ const select = within ( priorityRow ) . getByTestId ( 'priority-select' ) ;
1842+ fireEvent . change ( select , { target : { value : 'H' } } ) ;
1843+
1844+ const saveButton = screen . getByLabelText ( 'save' ) ;
1845+ fireEvent . click ( saveButton ) ;
1846+
1847+ await waitFor ( ( ) => {
1848+ const hooks = require ( '../hooks' ) ;
1849+ expect ( hooks . modifyTaskOnBackend ) . toHaveBeenCalledWith (
1850+ expect . objectContaining ( { priority : 'H' } )
1851+ ) ;
1852+ } ) ;
1853+ } ) ;
1854+
1855+ test ( 'saving "NONE" priority sends empty string to backend' , async ( ) => {
1856+ render ( < Tasks { ...mockProps } /> ) ;
1857+
1858+ await screen . findByText ( 'Task 12' ) ;
1859+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1860+
1861+ await waitFor ( ( ) => {
1862+ expect ( screen . getByText ( 'Priority:' ) ) . toBeInTheDocument ( ) ;
1863+ } ) ;
1864+
1865+ const priorityLabel = screen . getByText ( 'Priority:' ) ;
1866+ const priorityRow = priorityLabel . closest ( 'tr' ) as HTMLElement ;
1867+ const editButton = within ( priorityRow ) . getByLabelText ( 'edit' ) ;
1868+ fireEvent . click ( editButton ) ;
1869+
1870+ const select = within ( priorityRow ) . getByTestId ( 'priority-select' ) ;
1871+ fireEvent . change ( select , { target : { value : 'NONE' } } ) ;
1872+
1873+ const saveButton = screen . getByLabelText ( 'save' ) ;
1874+ fireEvent . click ( saveButton ) ;
1875+
1876+ await waitFor ( ( ) => {
1877+ const hooks = require ( '../hooks' ) ;
1878+ expect ( hooks . modifyTaskOnBackend ) . toHaveBeenCalledWith (
1879+ expect . objectContaining ( {
1880+ priority : '' ,
1881+ } )
1882+ ) ;
1883+ } ) ;
1884+ } ) ;
1885+
1886+ test ( 'shows error toast when priority save fails' , async ( ) => {
1887+ const { toast } = require ( 'react-toastify' ) ;
1888+ const hooks = require ( '../hooks' ) ;
1889+
1890+ hooks . modifyTaskOnBackend . mockRejectedValueOnce (
1891+ new Error ( 'Network error' )
1892+ ) ;
1893+
1894+ render ( < Tasks { ...mockProps } /> ) ;
1895+ await screen . findByText ( 'Task 12' ) ;
1896+
1897+ fireEvent . click ( screen . getByText ( 'Task 12' ) ) ;
1898+
1899+ await waitFor ( ( ) => {
1900+ expect ( screen . getByText ( 'Priority:' ) ) . toBeInTheDocument ( ) ;
1901+ } ) ;
1902+
1903+ const priorityLabel = screen . getByText ( 'Priority:' ) ;
1904+ const priorityRow = priorityLabel . closest ( 'tr' ) as HTMLElement ;
1905+
1906+ const editButton = within ( priorityRow ) . getByLabelText ( 'edit' ) ;
1907+ fireEvent . click ( editButton ) ;
1908+
1909+ const select = within ( priorityRow ) . getByTestId ( 'priority-select' ) ;
1910+ fireEvent . change ( select , { target : { value : 'H' } } ) ;
1911+
1912+ const saveButton = within ( priorityRow ) . getByLabelText ( 'save' ) ;
1913+ fireEvent . click ( saveButton ) ;
1914+
1915+ await waitFor ( ( ) => {
1916+ expect ( toast . error ) . toHaveBeenCalledWith (
1917+ expect . stringContaining ( 'Failed to update priority' )
1918+ ) ;
1919+ } ) ;
1920+ } ) ;
1921+ } ) ;
1922+
1923+ describe ( 'Reports Toggle' , ( ) => {
1924+ test ( 'clicking "Show Reports" button switches view from tasks to reports' , async ( ) => {
1925+ render ( < Tasks { ...mockProps } /> ) ;
1926+
1927+ await screen . findByText ( 'Task 1' ) ;
1928+
1929+ expect ( screen . getByText ( 'Here are' ) ) . toBeInTheDocument ( ) ;
1930+
1931+ const toggleBtn = screen . getByRole ( 'button' , { name : / s h o w r e p o r t s / i } ) ;
1932+ fireEvent . click ( toggleBtn ) ;
1933+
1934+ expect (
1935+ screen . getByRole ( 'button' , { name : / s h o w t a s k s / i } )
1936+ ) . toBeInTheDocument ( ) ;
1937+ } ) ;
1938+
1939+ test ( 'clicking "Show Tasks" returns to task list view' , async ( ) => {
1940+ render ( < Tasks { ...mockProps } /> ) ;
1941+ await screen . findByText ( 'Task 1' ) ;
1942+
1943+ fireEvent . click ( screen . getByRole ( 'button' , { name : / s h o w r e p o r t s / i } ) ) ;
1944+ fireEvent . click ( screen . getByRole ( 'button' , { name : / s h o w t a s k s / i } ) ) ;
1945+
1946+ expect ( screen . getByText ( 'Task 1' ) ) . toBeInTheDocument ( ) ;
1947+ } ) ;
1948+
1949+ test ( 'hotkeys are disabled when reports view is shown' , async ( ) => {
1950+ render ( < Tasks { ...mockProps } /> ) ;
1951+ await screen . findByText ( 'Task 1' ) ;
1952+
1953+ fireEvent . click ( screen . getByRole ( 'button' , { name : / s h o w r e p o r t s / i } ) ) ;
1954+ fireEvent . keyDown ( window , { key : 'a' } ) ;
1955+
1956+ expect (
1957+ screen . queryByText ( / f i l l i n t h e d e t a i l s b e l o w / i)
1958+ ) . not . toBeInTheDocument ( ) ;
1959+ } ) ;
1960+ } ) ;
17401961} ) ;
0 commit comments