diff --git a/package.json b/package.json index bc3b3d9..60317ca 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "lint": "npm run lint:tests && npm run lint --workspaces", "lint:tests": "eslint . tests --ext .ts,.tsx --max-warnings 0", "build:deps": "npm run build -w @busmap/components && npm run build -w @busmap/common", - "test": "playwright test --reporter=list" + "test": "playwright test --reporter=list", + "test:local": "playwright test --project=chromium" }, "devDependencies": { "@playwright/test": "^1.40.1", diff --git a/packages/components/src/alert/mod.tsx b/packages/components/src/alert/mod.tsx index cabec68..06870bc 100644 --- a/packages/components/src/alert/mod.tsx +++ b/packages/components/src/alert/mod.tsx @@ -10,21 +10,37 @@ interface AlertProps { children: ReactNode icon?: ReactNode fullWidth?: boolean + fontSize?: string onClose?: (evt: SyntheticEvent | Event | CustomEvent) => void } type AlertRef = HTMLDivElement -const AlertBase = styled(MuiAlert)<{ $fullWidth: boolean }>` +const AlertBase = styled(MuiAlert)<{ $fullWidth: boolean; $fontSize: string }>` &.MuiAlert-root { width: ${({ $fullWidth }) => ($fullWidth ? '100%' : 'auto')}; .MuiAlert-message { width: 100%; + font-size: ${({ $fontSize }) => $fontSize}; + } + + .MuiAlert-action { + .MuiSvgIcon-root { + font-size: 20px; + } } } ` const Alert: FC = forwardRef(function Alert( - { children, icon, onClose, type = 'info', variant = 'standard', fullWidth = false }, + { + children, + icon, + onClose, + type = 'info', + variant = 'standard', + fullWidth = false, + fontSize = '14px' + }, ref ) { return ( @@ -33,6 +49,7 @@ const Alert: FC = forwardRef(function Alert( severity={type} variant={variant} icon={icon} + $fontSize={fontSize} $fullWidth={fullWidth} onClose={onClose}> {children} diff --git a/packages/components/src/alert/story.tsx b/packages/components/src/alert/story.tsx index 5093988..1a4fd00 100644 --- a/packages/components/src/alert/story.tsx +++ b/packages/components/src/alert/story.tsx @@ -61,7 +61,8 @@ export default { args: { children: 'An alert message', type: 'info', - variant: 'standard' + variant: 'standard', + fontSize: '0.875rem' }, argTypes: { type: { diff --git a/packages/components/src/toast/mod.tsx b/packages/components/src/toast/mod.tsx index 866652a..c6102d5 100644 --- a/packages/components/src/toast/mod.tsx +++ b/packages/components/src/toast/mod.tsx @@ -34,7 +34,11 @@ const EVENT_NAME = 'busmap-toaster' const toast = (props: ToasterProps) => { window.dispatchEvent(new CustomEvent(EVENT_NAME, { detail: props })) } -const Toaster: FC<{ anchor?: Positions; kind?: Variant }> = ({ anchor, kind }) => { +const Toaster: FC<{ anchor?: Positions; kind?: Variant; fontSize?: string }> = ({ + anchor, + kind, + fontSize = '14px' +}) => { const [{ open, type, variant, message, position, timeout }, setState] = useState(defaultState) const onClose = useCallback( @@ -72,6 +76,7 @@ const Toaster: FC<{ anchor?: Positions; kind?: Variant }> = ({ anchor, kind }) = {message ?? ''} diff --git a/packages/components/src/tooltip/mod.tsx b/packages/components/src/tooltip/mod.tsx index 954ecb9..990ec45 100644 --- a/packages/components/src/tooltip/mod.tsx +++ b/packages/components/src/tooltip/mod.tsx @@ -8,10 +8,14 @@ interface TooltipProps { className?: string children: ReactNode title: string + fontSize?: string placement?: 'top' | 'bottom' | 'right' | 'left' underline?: UnderlineStyle } +const Tip = styled.span<{ $fontSize: string }>` + font-size: ${({ $fontSize }) => $fontSize}; +` const Wrap = styled.div<{ underline: UnderlineStyle }>` text-decoration: ${({ underline }) => (underline ? `underline ${underline}` : 'none')}; ` @@ -20,10 +24,15 @@ const Tooltip: FC = ({ children, underline = 'dotted', placement = 'top', + fontSize = '12px', title = '' }) => { return ( - + {title}} + placement={placement} + className={className}> {children} ) diff --git a/packages/components/src/tooltip/story.tsx b/packages/components/src/tooltip/story.tsx index bae12de..befaa6b 100644 --- a/packages/components/src/tooltip/story.tsx +++ b/packages/components/src/tooltip/story.tsx @@ -25,7 +25,8 @@ export default { args: { title: 'Story title', placement: 'top', - underline: 'dashed' + underline: 'dashed', + fontSize: '12px' }, argTypes: { placement: { diff --git a/packages/ui/src/components/busmap.tsx b/packages/ui/src/components/busmap.tsx index 8d8e8b6..cedc7dc 100644 --- a/packages/ui/src/components/busmap.tsx +++ b/packages/ui/src/components/busmap.tsx @@ -1,60 +1,99 @@ +import styled from 'styled-components' + import { Page } from './page.js' +import { PageTabButton } from './pageTabButton.js' import type { FC } from 'react' +const Section = styled.section` + display: flex; + flex-direction: column; + gap: 16px; +` const BusmapPage: FC = () => { return ( - +

Busmap provides real-time arrival and departure times for vehicles servicing bus - stops along routes in San Francisco Muni CIS, Toronto Transit Commission, - OmniTrans, and other transit agencies across North and South America. -

-

- Busmap is a public, open source project{' '} - - hosted on GitHub - {' '} - and powered by the{' '} - - UMO public XML feed - {' '} - and{' '} - - restbus + stops along routes in{' '} + + San Francisco Muni CIS - .{' '} - - Pull requests + ,{' '} + + Toronto Transit Commission ,{' '} - - feedback - {' '} - and{' '} - - issues or bugs - {' '} - are welcome. -

-

- Maintained with ❤️ by{' '} - - morganney + + OmniTrans + , and other transit agencies across North and South America.

+
+

Finding Your Stop

+

+ To find your desired stop, you can start with the{' '} + Selector tab to find a transit + agency, route, direction, and stop that fits your itinerary. Alternatively, you + can use the Nearby tab where you + will be prompted to permit your device to share its geolocation with Busmap, and + a list of the nearest stops for currently running transit agencies will be + displayed. +

+

+ From either option, you can favorite the stop by clicking the star ⭐ icon, and + a bookmark will be added to the{' '} + Favorites tab. +

+
+
+

About

+

+ Busmap is a public, open source project{' '} + + hosted on GitHub + {' '} + and powered by the{' '} + + UMO public XML feed + {' '} + and{' '} + + restbus + + .{' '} + + Pull requests + + ,{' '} + + feedback + {' '} + and{' '} + + issues or bugs + {' '} + are welcome. +

+

+ Maintained with ❤️ by{' '} + + morganney + +

+
) } diff --git a/packages/ui/src/components/emptyMap.tsx b/packages/ui/src/components/emptyMap.tsx new file mode 100644 index 0000000..492f48c --- /dev/null +++ b/packages/ui/src/components/emptyMap.tsx @@ -0,0 +1,192 @@ +import styled from 'styled-components' +import { Link } from 'react-router-dom' +import { MapPin } from '@busmap/components/icons/mapPin' +import { Bus } from '@busmap/components/icons/bus' +import { + PB10T, + PB20T, + PB70T, + PB40T, + PB30T, + PB90T, + SO, + SDB +} from '@busmap/components/colors' + +import { useStorage } from '@core/contexts/storage.js' +import { useTheme } from '@module/settings/contexts/theme.js' + +import { PageTabButton } from './pageTabButton.js' + +import logoSvg from '../../assets/svg/logo.svg?raw' + +import type { FC } from 'react' +import type { Mode } from '@busmap/common/types/settings' + +const Article = styled.article<{ $mode: Mode }>` + overflow-y: auto; + max-height: 100%; + height: 100%; + width: calc(100% - 78px); + position: fixed; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 16px; + padding: 16px 8px; + margin-left: 78px; + + h2 { + font-size: 18px; + font-weight: normal; + margin: 0; + display: flex; + + span:first-child { + display: none; + } + + span:last-child { + width: 120px; + color: ${({ $mode }) => ($mode === 'light' ? SDB : SO)}; + + path.bus { + fill: ${({ $mode }) => ($mode === 'light' ? PB90T : PB20T)}; + } + } + } + + p { + font-weight: 600; + margin: 0; + font-size: 1.8rem; + + button { + text-decoration: underline; + font-size: 1.8rem; + } + } + + ul.busmap-start { + list-style: none; + margin: 0; + background: ${({ $mode }) => ($mode === 'light' ? '#ffffffcc' : `${PB10T}cc`)}; + border: 1px solid ${({ $mode }) => ($mode === 'light' ? PB70T : PB40T)}; + border-radius: 5px; + padding: 32px 48px; + display: flex; + gap: 16px; + justify-content: space-between; + + button { + padding: 16px; + border: 1px solid transparent; + border-radius: 5px; + + &:hover { + border-color: ${({ $mode }) => ($mode === 'light' ? PB70T : PB40T)}; + } + } + } + + @media (width <= 431px) { + margin-left: 48px; + width: calc(100% - 48px); + + ul.busmap-start { + flex-direction: column; + } + } +` +const ButtonContent = styled.span<{ $mode: Mode }>` + display: grid; + justify-items: center; + gap: 8px; + color: ${({ $mode }) => ($mode === 'light' ? PB30T : PB90T)}; + font-weight: normal; + + span { + color: ${({ $mode }) => ($mode === 'light' ? PB30T : PB90T)}; + } +` +const FavsList = styled.ul<{ $mode: Mode }>` + margin: 0; + padding: 0; + list-style: none; + display: flex; + flex-direction: column; + gap: 8px; + + li { + display: flex; + align-items: center; + gap: 8px; + + > span { + color: ${({ $mode }) => ($mode === 'light' ? PB30T : PB90T)}; + } + } + + a { + display: flex; + flex-direction: column; + font-size: 1.4rem; + } +` +const EmptyMap: FC = () => { + const { mode } = useTheme() + const { favorites } = useStorage() + + return ( +
+

+ Busmap + +

+

Choose one to get started.

+
    +
  • + + + + Selector + + +
  • +
  • + + + + Nearby + + +
  • +
+ {favorites.length ? ( + <> +

Or see some of your favorite stops.

+ + {favorites.slice(0, 3).map(fav => ( +
  • + + + {fav.stop.title} + {fav.direction.title} + +
  • + ))} +
    + + ) : ( +

    + Or read more about busmap. +

    + )} +
    + ) +} + +export { EmptyMap } diff --git a/packages/ui/src/components/loading.tsx b/packages/ui/src/components/loading.tsx index 6f27c5f..48e8554 100644 --- a/packages/ui/src/components/loading.tsx +++ b/packages/ui/src/components/loading.tsx @@ -19,7 +19,7 @@ const Text = styled.p` align-items: center; justify-content: center; font-family: Roboto, Arial, sans-serif; - font-size: 1rem; + font-size: 1.8rem; ` const Loading: FC = ({ text, useIcon = true }) => { return ( diff --git a/packages/ui/src/components/navigation.tsx b/packages/ui/src/components/navigation.tsx index f9bf031..d70d240 100644 --- a/packages/ui/src/components/navigation.tsx +++ b/packages/ui/src/components/navigation.tsx @@ -38,10 +38,11 @@ interface NavigationProps { } const Nav = styled.nav<{ mode: Mode; isSignedIn: boolean }>` - position: relative; + position: fixed; + left: 0; + height: 100%; z-index: 9999; background: ${({ mode }) => (mode === 'light' ? PB90T : DARK_MODE_FIELD)}; - border-right: 1px solid ${({ mode }) => (mode === 'light' ? PB80T : PB50T)}; ul { margin: 0; @@ -288,7 +289,7 @@ const Navigation: FC = ({ status }) => { data-name="busmap" aria-label="Busmap Logo" onClick={onClickNavItem} - className={page === 'busmap' ? 'active' : undefined}> + className={page === 'busmap' && !collapsed ? 'active' : undefined}> @@ -303,7 +304,7 @@ const Navigation: FC = ({ status }) => { data-name="locate" aria-label="Nearby" onClick={onClickNavItem} - className={page === 'locate' ? 'active' : undefined}> + className={page === 'locate' && !collapsed ? 'active' : undefined}> Nearby @@ -313,7 +314,7 @@ const Navigation: FC = ({ status }) => { data-name="select" aria-label="Selector" onClick={onClickNavItem} - className={page === 'select' ? 'active' : undefined}> + className={page === 'select' && !collapsed ? 'active' : undefined}> Selector @@ -323,7 +324,7 @@ const Navigation: FC = ({ status }) => { data-name="favorites" aria-label="Favorites" onClick={onClickNavItem} - className={page === 'favorites' ? 'active' : undefined}> + className={page === 'favorites' && !collapsed ? 'active' : undefined}> Favorites @@ -333,7 +334,7 @@ const Navigation: FC = ({ status }) => { data-name="settings" aria-label="Settings" onClick={onClickNavItem} - className={page === 'settings' ? 'active' : undefined}> + className={page === 'settings' && !collapsed ? 'active' : undefined}> Settings @@ -343,7 +344,7 @@ const Navigation: FC = ({ status }) => { data-name="profile" aria-label="Profile" onClick={onClickNavItem} - className={page === 'profile' ? 'active' : undefined}> + className={page === 'profile' && !collapsed ? 'active' : undefined}> Profile diff --git a/packages/ui/src/components/pageTabButton.tsx b/packages/ui/src/components/pageTabButton.tsx new file mode 100644 index 0000000..3b0d270 --- /dev/null +++ b/packages/ui/src/components/pageTabButton.tsx @@ -0,0 +1,49 @@ +import styled from 'styled-components' +import { useCallback } from 'react' +import { PB20T, PB90T } from '@busmap/components/colors' + +import { useGlobals } from '@core/globals.js' +import { isAPage } from '@module/util.js' +import { useTheme } from '@module/settings/contexts/theme.js' + +import type { ReactNode, FC, MouseEvent } from 'react' +import type { Page } from '@core/types' +import type { Mode } from '@busmap/common/types/settings' + +interface PageTabButtonProps { + children: ReactNode + page: Page +} +const Button = styled.button<{ $mode: Mode }>` + margin: 0; + padding: 0; + background: none; + border: none; + cursor: pointer; + color: ${({ $mode }) => ($mode === 'light' ? PB20T : PB90T)}; + font-weight: 700; + font-size: 1.6rem; +` +const PageTabButton: FC = ({ children, page }) => { + const { dispatch } = useGlobals() + const { mode } = useTheme() + const onClick = useCallback( + (evt: MouseEvent) => { + const tab = evt.currentTarget.dataset.tab + + if (isAPage(tab)) { + dispatch({ type: 'page', value: tab }) + dispatch({ type: 'collapsed', value: false }) + } + }, + [dispatch] + ) + + return ( + + ) +} + +export { PageTabButton } diff --git a/packages/ui/src/components/profile.tsx b/packages/ui/src/components/profile.tsx index 26ff433..0780996 100644 --- a/packages/ui/src/components/profile.tsx +++ b/packages/ui/src/components/profile.tsx @@ -20,6 +20,7 @@ const SignOutBtn = styled.button<{ $mode: Mode }>` cursor: pointer; background: none; font-weight: bold; + font-size: 16px; border: none; margin: 0 0 0 auto; padding: 0; diff --git a/packages/ui/src/components/selection.tsx b/packages/ui/src/components/selection.tsx index 72b2812..d5e8501 100644 --- a/packages/ui/src/components/selection.tsx +++ b/packages/ui/src/components/selection.tsx @@ -40,6 +40,7 @@ const Definition = styled.dl` gap: 8px; margin: 0; padding: 0; + font-size: 1.3rem; dt, dd { diff --git a/packages/ui/src/global.css b/packages/ui/src/global.css index f0424f4..4778a35 100644 --- a/packages/ui/src/global.css +++ b/packages/ui/src/global.css @@ -74,6 +74,7 @@ html { height: fill-available; display: grid; box-sizing: border-box; + font-size: 62.5%; } body { color: var(--color-light); @@ -82,14 +83,15 @@ body { font-family: Roboto, Arial, sans-serif; font-weight: 400; font-style: normal; + font-size: 1.6rem; } body.busmap-light { color: var(--color-light); - background: #e5e5e5; + background: #eee; } body.busmap-dark { color: var(--color-dark); - background: #3b3b3b; + background: #333; } body.busmap-dark .leaflet-layer, body.busmap-dark .leaflet-control-zoom-in, @@ -115,6 +117,13 @@ main { } #map { width: 100%; + visibility: hidden; +} +body.busmap-loaded #map { + visibility: visible; +} +body.busmap-loaded #busmap-empty-map { + display: none; } body.busmap-error #map { display: none; @@ -170,6 +179,9 @@ body.busmap-dark .busmap-user-circle { .busmap-vehicle-popup dd { margin: 0; } +.leaflet-popup { + font-size: 1.2rem; +} /* increased specificity necessary due to cascade from dynamic import of leaflets css file. */ .leaflet-popup.busmap-vehicle-popup.selected { transition: transform 3.75s ease; @@ -180,6 +192,7 @@ body.busmap-dark .busmap-user-circle { white-space: nowrap; border: 1px solid black; transition: transform 3.75s ease; + font-size: 1.2rem; } body.busmap-mapmove .busmap-vehicle { transition: none; diff --git a/packages/ui/src/globals.tsx b/packages/ui/src/globals.tsx index b6cfe7a..0945ced 100644 --- a/packages/ui/src/globals.tsx +++ b/packages/ui/src/globals.tsx @@ -5,12 +5,10 @@ import type { BusmapGlobals, BusmapAction } from './types.js' type BusmapState = Omit -const urlParts = window.location.pathname.split('/').filter(Boolean) -const isHomeStop = urlParts[0] === 'stop' && urlParts.length <= 5 const defaultGlobals: BusmapGlobals = { dispatch: () => {}, - page: isHomeStop ? 'select' : 'locate', - collapsed: false, + page: 'select', + collapsed: true, center: { lat: 37.7775, lon: -122.416389 }, bounds: { sw: { diff --git a/packages/ui/src/home.tsx b/packages/ui/src/home.tsx index 72926d6..c49da66 100644 --- a/packages/ui/src/home.tsx +++ b/packages/ui/src/home.tsx @@ -2,7 +2,7 @@ import { useReducer, useEffect, useCallback, useRef } from 'react' import { useQuery } from '@tanstack/react-query' import { Tabs, TabList, Tab, TabPanel } from '@busmap/components/tabs' import { toast } from '@busmap/components/toast' -import { PB50T, PB90T, PB80T, PB10T } from '@busmap/components/colors' +import { PB50T, PB90T, PB10T } from '@busmap/components/colors' import styled from 'styled-components' import { useGlobals } from './globals.js' @@ -19,9 +19,11 @@ import { BusSelector } from './components/busSelector.js' import { Loading } from './components/loading.js' import { Predictions } from './components/predictions.js' import { ErrorAgencies } from './components/error/agencies.js' +import { EmptyMap } from './components/emptyMap.js' import { getAll as getAllAgencies } from './api/rb/agency.js' import { getAll as getAllVehicles } from './api/rb/vehicles.js' import { getForStop } from './api/rb/predictions.js' +import { useHomeStop } from './hooks/useHomeStop.js' import type { FC } from 'react' import type { Mode } from '@busmap/common/types/settings' @@ -60,13 +62,12 @@ const Aside = styled.aside<{ mode: Mode; collapsed: boolean }>` width: calc(100% - 49px); max-width: 385px; background: ${({ mode }) => (mode === 'light' ? '#ffffffcc' : `${PB10T}cc`)}; - border-right: 1px solid ${({ mode }) => (mode === 'light' ? PB80T : PB50T)}; transform: ${({ collapsed }) => (!collapsed ? 'translateX(0)' : 'translateX(-100%)')}; transition: transform 0.25s ease; @media (width >= 431px) and (height >= 536px) { - left: 79px; - width: calc(33% + 79px); + left: 78px; + width: calc(33% + 78px); min-width: 325px; } ` @@ -89,6 +90,7 @@ const Wrap = styled.div` ` const Home: FC = () => { const ref = useRef(null) + const homeStop = useHomeStop() const { mode } = useTheme() const vehiclesDispatch = useVehiclesDispatch() const { dispatch: predsDispatch } = usePredictions() @@ -186,65 +188,68 @@ const Home: FC = () => { }, [vehiclesDispatch, vehicles]) return ( - + <> + + {!homeStop && } + ) } diff --git a/packages/ui/src/layout.tsx b/packages/ui/src/layout.tsx index 5e77829..c704244 100644 --- a/packages/ui/src/layout.tsx +++ b/packages/ui/src/layout.tsx @@ -63,6 +63,14 @@ const Layout: FC = ({ children }) => { document.body.classList.add(`busmap-${mode}`) }, [mode]) + useLayoutEffect(() => { + if (map) { + map.on('load', () => { + document.body.classList.add('busmap-loaded') + }) + } + }, [map]) + useRouteLayer({ routeLayer, map, popup }) useVehiclesLayer({ vehiclesLayer }) useZoomSelectedStop({ map }) diff --git a/packages/ui/src/modules/favorites/components/favorites.tsx b/packages/ui/src/modules/favorites/components/favorites.tsx index e11babc..4d1928f 100644 --- a/packages/ui/src/modules/favorites/components/favorites.tsx +++ b/packages/ui/src/modules/favorites/components/favorites.tsx @@ -14,11 +14,12 @@ import { useGlobals } from '@core/globals.js' import { useMap } from '@core/contexts/map.js' import { useStorage, useStorageDispatch } from '@core/contexts/storage.js' import { useHomeStop } from '@core/hooks/useHomeStop.js' -import { useTheme } from '@core/modules/settings/contexts/theme.js' import { Page } from '@core/components/page.js' +import { PageTabButton } from '@core/components/pageTabButton.js' import { Details } from '@core/components/details.js' import { Minutes } from '@core/components/predictionFormats/minutes.js' import { Time } from '@core/components/predictionFormats/time.js' +import { useTheme } from '@module/settings/contexts/theme.js' import { usePredictionsSettings } from '@module/settings/contexts/predictions.js' import { AgenciesWrap, @@ -27,7 +28,7 @@ import { RouteSection, StopArticle } from '@module/components.js' -import { groupBy, isAPage } from '@module/util.js' +import { groupBy } from '@module/util.js' import { getPredsKey } from '../util.js' import { MAX_FAVORITES, MAX_USER_FAVORITES } from '../common.js' @@ -66,7 +67,7 @@ const Section = styled(Page)<{ mode: Mode }>` } ` const Favorites = memo(function Favorites() { - const { user, dispatch } = useGlobals() + const { user } = useGlobals() const map = useMap() const workerRef = useRef() const homeStop = useHomeStop() @@ -119,16 +120,6 @@ const Favorites = memo(function Favorites() { }, [storageDispatch, user] ) - const onClickTab = useCallback( - (evt: MouseEvent) => { - const tab = evt.currentTarget.dataset.tab - - if (isAPage(tab)) { - dispatch({ type: 'page', value: tab }) - } - }, - [dispatch] - ) const maximum = user ? MAX_USER_FAVORITES : MAX_FAVORITES const PredFormat = format === 'minutes' ? Minutes : Time @@ -174,33 +165,19 @@ const Favorites = memo(function Favorites() {

    {user.givenName}, you can select up to {MAX_USER_FAVORITES} favorite stops across any number of transit agencies from the{' '} - {' '} - or{' '} - {' '} - tabs. + Selector or{' '} + Nearby tabs.

    ) : ( <>

    You can select up to {MAX_FAVORITES} favorite stops from the{' '} - {' '} - or{' '} - {' '} - tabs. They will be stored by this device. + Selector or{' '} + Nearby tabs.

    - {' '} - to save more favorite stops. + Sign in with Google to save + more favorite stops.

    )} diff --git a/packages/ui/src/modules/settings/components/vehicle.tsx b/packages/ui/src/modules/settings/components/vehicle.tsx index 6dd75b9..86bfe4d 100644 --- a/packages/ui/src/modules/settings/components/vehicle.tsx +++ b/packages/ui/src/modules/settings/components/vehicle.tsx @@ -93,7 +93,7 @@ const VehicleSettings: FC = () => { diff --git a/tests/favorites/addDelete.spec.ts b/tests/favorites/addDelete.spec.ts index 326da31..bc63b91 100644 --- a/tests/favorites/addDelete.spec.ts +++ b/tests/favorites/addDelete.spec.ts @@ -14,7 +14,7 @@ test('Add and then delete a favorite stop.', async ({ page, context }) => { await expect(page.getByRole('heading', { name: 'Bus Selector' })).toBeVisible() // Select first agency, click first stop - await page.getByText('Agency').click() + await page.getByText(/^Agency$/).click() await page.getByRole('option').first().click() await page.getByText('Stop', { exact: true }).click() @@ -42,7 +42,7 @@ test('Add and then delete a favorite stop.', async ({ page, context }) => { expect(favorites[0].stop.title).toEqual(stopOptionText) // Delete the favorite and restore the empty state - await page.getByLabel('Delete').getByRole('button').click() + await page.locator('footer').getByRole('button').first().click() await expect(page.getByText('You can select up to 3')).toBeVisible() storage = await context.storageState() favoritesEntry = storage.origins[0].localStorage.find( diff --git a/tests/geolocation/deny.spec.ts b/tests/geolocation/deny.spec.ts index b4a1745..86ce90f 100644 --- a/tests/geolocation/deny.spec.ts +++ b/tests/geolocation/deny.spec.ts @@ -6,12 +6,13 @@ test.beforeEach(async ({ context }) => { test('Deny geolocation use selector to find stop.', async ({ page }) => { await page.goto('/') + await page.getByRole('listitem', { name: 'Nearby' }).getByRole('button').click() await expect( page.getByText('Location permission denied. Check your OS or browser settings.') ).toBeVisible() await page.getByRole('listitem', { name: 'Selector' }).getByRole('button').click() await expect(page.getByRole('heading', { name: 'Bus Selector' })).toBeVisible() - await page.getByText('Agency').click() + await page.getByText(/^Agency$/).click() await page.getByLabel(/Agency/).fill('toronto') await page.getByRole('option', { name: 'Toronto Transit Commission' }).click() await page.getByText('Stop', { exact: true }).click() diff --git a/tests/selector/agencyStop.spec.ts b/tests/selector/agencyStop.spec.ts index 26eecce..f22d6ce 100644 --- a/tests/selector/agencyStop.spec.ts +++ b/tests/selector/agencyStop.spec.ts @@ -4,7 +4,7 @@ test('Select an agency and stop to see arrivals.', async ({ page }) => { await page.goto('/') await page.getByRole('listitem', { name: 'Selector' }).getByRole('button').click() await expect(page.getByRole('heading', { name: 'Bus Selector' })).toBeVisible() - await page.getByText('Agency').click() + await page.getByText(/^Agency$/).click() await page.getByRole('option', { name: 'Toronto Transit Commission' }).click() await page.getByText('Stop', { exact: true }).click() await page.getByRole('option', { name: 'Bathurst St At Neptune Dr' }).click()