diff --git a/e2e/fixtures.cy.ts b/e2e/fixtures.cy.ts index fd75ea3..08561fa 100644 --- a/e2e/fixtures.cy.ts +++ b/e2e/fixtures.cy.ts @@ -1,9 +1,7 @@ beforeEach(() => { - cy.visit('/fixtures'); + cy.visit('/'); cy.wait('@fixtures'); cy.get('.nav-link').contains('Fixtures').click(); - - cy.get('@fixtures').should('have.property', 'state', 'Complete'); }); describe('fixtures', () => { @@ -32,8 +30,8 @@ describe('fixtures', () => { expect(loc.pathname).to.eq('/fixtures/1049002'); }); - cy.wait(['@goals', '@goals']).then((interceptions) => { - const reqQuery = JSON.parse(interceptions[1].request.query.json as string); + cy.wait(['@goals', '@goals', '@goals']).then((interceptions) => { + const reqQuery = JSON.parse(interceptions[2].request.query.json as string); cy.wrap(reqQuery).its('filter').its('fixtureId').should('equal', 1049002); }); diff --git a/e2e/goals.cy.ts b/e2e/goals.cy.ts index 49863b8..acc5e76 100644 --- a/e2e/goals.cy.ts +++ b/e2e/goals.cy.ts @@ -13,6 +13,8 @@ describe('Goals', () => { expect(loc.pathname).to.eq('/goals'); }); + cy.get('@fixtures').should('have.property', 'state', 'Complete'); + cy.get('@leagues').should('have.property', 'state', 'Complete'); cy.get('@goals').should('have.property', 'state', 'Complete'); }); diff --git a/e2e/settings.cy.ts b/e2e/settings.cy.ts index e853761..1284422 100644 --- a/e2e/settings.cy.ts +++ b/e2e/settings.cy.ts @@ -1,5 +1,5 @@ beforeEach(() => { - cy.visit('/settings'); + cy.visit('/'); cy.get('.nav-link').contains('Settings').click(); }); diff --git a/e2e/tabs.cy.ts b/e2e/tabs.cy.ts index 195d8ed..b3591fb 100644 --- a/e2e/tabs.cy.ts +++ b/e2e/tabs.cy.ts @@ -3,25 +3,16 @@ describe('tabs', () => { cy.visit('/'); cy.get('.nav-link.active').contains('Home'); - cy.location().should((loc) => { - expect(loc.pathname).to.eq('/goals'); - }); cy.get('[aria-labelledby="home-tab"]').should('be.visible'); - cy.get('[aria-labelledby="fixtures-tab"]').should('not.exist'); - cy.get('[aria-labelledby="settings-tab"]').should('not.exist'); + cy.get('[aria-labelledby="fixtures-tab"]').should('not.be.visible'); + cy.get('[aria-labelledby="settings-tab"]').should('not.be.visible'); cy.get('.nav-link').contains('Fixtures').click(); cy.get('.nav-link.active').contains('Fixtures'); - cy.location().should((loc) => { - expect(loc.pathname).to.eq('/fixtures'); - }); cy.get('[aria-labelledby="fixtures-tab"]').should('be.visible'); cy.get('.nav-link').contains('Settings').click(); cy.get('.nav-link.active').contains('Settings'); - cy.location().should((loc) => { - expect(loc.pathname).to.eq('/settings'); - }); cy.get('[aria-labelledby="settings-tab"]').should('be.visible'); }); }); diff --git a/src/App.test.tsx b/src/App.test.tsx index 5270620..9f84bf8 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -1,8 +1,23 @@ -import './mocks/matchMedia.ts'; - import {render} from '@testing-library/react'; import App from './App'; test('renders the app with no errors', () => { + // window.matchMedia is not implemented in JSDOM so need to mock it + // https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom + + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // deprecated + removeListener: vi.fn(), // deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), + }); + render(); }); diff --git a/src/App.tsx b/src/App.tsx index bdcadf7..4132959 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,58 +1,35 @@ -import Header from './components/Header'; -import {ThemeProvider} from './hooks/useTheme'; import Error from './pages/Error'; import Fixture from './pages/Fixture'; -import Fixtures from './pages/Fixtures'; import Goal from './pages/Goal'; import Goals from './pages/Goals'; -import Settings from './pages/Settings'; import {createBrowserRouter, Navigate, RouterProvider} from 'react-router-dom'; const router = createBrowserRouter([ { - element:
, - children: [ - { - path: '/', - element: , - errorElement: , - }, - { - path: '/goals', - element: , - errorElement: , - }, - { - path: '/fixtures', - element: , - errorElement: , - }, - { - path: '/settings', - element: , - errorElement: , - }, - { - path: '/goals/:goalId', - element: , - errorElement: , - }, - { - path: '/fixtures/:fixtureId', - element: , - errorElement: , - }, - ], + path: '/', + element: , + errorElement: , + }, + { + path: '/goals', + element: , + errorElement: , + }, + { + path: '/goals/:goalId', + element: , + errorElement: , + }, + { + path: '/fixtures/:fixtureId', + element: , + errorElement: , }, ]); function App() { - return ( - - - - ); + return ; } export default App; diff --git a/src/components/FixtureRow.tsx b/src/components/FixtureRow.tsx index 7171a97..2db9ce2 100644 --- a/src/components/FixtureRow.tsx +++ b/src/components/FixtureRow.tsx @@ -36,8 +36,6 @@ function FixtureRow({fixture}: FixtureRowProps) { src={fixture.teams.home.logo} alt="Home team logo" style={{maxWidth: '20px'}} - width={20} - height={20} >
{fixture.teams.home.name}
@@ -47,8 +45,6 @@ function FixtureRow({fixture}: FixtureRowProps) { src={fixture.teams.away.logo} alt="Away team logo" style={{maxWidth: '20px'}} - width={20} - height={20} >
{fixture.teams.away.name}
diff --git a/src/components/FixturesList.tsx b/src/components/FixturesList.tsx index 0349340..98946ca 100644 --- a/src/components/FixturesList.tsx +++ b/src/components/FixturesList.tsx @@ -26,7 +26,7 @@ function FixturesList({fixtures, leagues}: FixturesListProps) { {filteredLeagues.map((league) => (
- League Logo + League Logo
{league.name}
<> diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 80895c6..2a0a2a0 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,84 +1,26 @@ import {useEffect, useState} from 'react'; -import {NavLink, Outlet, useMatch} from 'react-router-dom'; import logoBlack from '../assets/top90logo-black.avif'; import logoWhite from '../assets/top90logo-white.avif'; -import {useTheme} from '../hooks/useTheme'; -const DARK = 'dark'; - -function getLogo(theme: string) { - return theme === DARK ? logoWhite : logoBlack; +interface HeaderProps { + selectedTheme: string; + onClick?: () => void; } -function Header() { - // Child components can attach a reset function to this state via the outlet context - // so that the header can reset some state that they control. - const [resetFn, setResetFn] = useState<() => void>(); - const {theme} = useTheme(); - const [logo, setLogo] = useState(getLogo(theme)); +const DARK = 'dark'; + +function Header({selectedTheme, onClick}: HeaderProps) { + const [logo, setLogo] = useState(logoBlack); useEffect(() => { - const logoToDisplay = getLogo(theme); + const logoToDisplay = selectedTheme === DARK ? logoWhite : logoBlack; setLogo(logoToDisplay); - }, [theme]); + }, [selectedTheme]); return ( -
-
-
- logo -
- -
    -
  • - { - return `nav-link ${isActive ? 'active' : ''}`; - }} - id="home-tab" - type="button" - aria-controls="home" - aria-selected={Boolean(useMatch('/goals'))} - > - Home - -
  • -
  • - { - return `nav-link ${isActive ? 'active' : ''}`; - }} - id="fixtures-tab" - type="button" - aria-controls="fixtures" - aria-selected={Boolean(useMatch('/fixtures'))} - > - Fixtures - -
  • -
  • - { - return `nav-link ${isActive ? 'active' : ''}`; - }} - id="settings-tab" - type="button" - aria-controls="settings" - aria-selected={Boolean(useMatch('/settings'))} - > - Settings - -
  • -
- -
- -
-
+
+ logo
); } diff --git a/src/components/ThemeSelect.tsx b/src/components/ThemeSelect.tsx index a95aca6..1196d2a 100644 --- a/src/components/ThemeSelect.tsx +++ b/src/components/ThemeSelect.tsx @@ -1,12 +1,13 @@ -import {Theme} from '../hooks/useTheme'; +import {getPreferredTheme} from '../lib/utils'; import Select from './Select'; interface ThemeSelectProps { - theme: Theme; onChange: (value: string) => void; } -function ThemeSelect({theme, onChange}: ThemeSelectProps) { +function ThemeSelect({onChange}: ThemeSelectProps) { + const preferredTheme = getPreferredTheme(); + return ( - - -
+
+
+
-
- -
-
- -
-
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
-
-
+
+
+
+
+ + + +
- {getGoalsResponse?.goals?.map((goal) => ( -
- -
- ))} - -
-
- -
-
- +
+ +
+
+ +
+
+ +
+
+ + {getGoalsResponse?.goals?.map((goal) => ( +
+ +
+ ))} + +
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+
+ +
+
diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx deleted file mode 100644 index 913f2e3..0000000 --- a/src/pages/Settings.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import ThemeSelect from '../components/ThemeSelect'; -import {Theme, useTheme} from '../hooks/useTheme'; - -function Settings() { - const {theme, setTheme} = useTheme(); - - return ( -
-
- setTheme(value as Theme)}> -
-
- ); -} - -export default Settings;