diff --git a/apps/mobile/app/(tabs)/_layout.tsx b/apps/mobile/app/(tabs)/_layout.tsx index d96fb0e88..3efcc6a51 100644 --- a/apps/mobile/app/(tabs)/_layout.tsx +++ b/apps/mobile/app/(tabs)/_layout.tsx @@ -27,6 +27,7 @@ export default function TabLayout() { name="index" options={{ title: "Home", + tabBarButtonTestID: "tab-home", tabBarIcon: ({ color, size }) => ( ), @@ -36,6 +37,7 @@ export default function TabLayout() { name="watch" options={{ title: "Discover", + tabBarButtonTestID: "tab-discover", headerShown: true, headerTitle: "Discover", headerStyle: { backgroundColor: BG_COLOR }, @@ -50,6 +52,7 @@ export default function TabLayout() { name="library" options={{ title: "Library", + tabBarButtonTestID: "tab-library", tabBarIcon: ({ color, size }) => ( ), @@ -59,6 +62,7 @@ export default function TabLayout() { name="profile" options={{ title: "Profile", + tabBarButtonTestID: "tab-profile", tabBarIcon: ({ color, size }) => ( ), diff --git a/apps/mobile/app/(tabs)/library.tsx b/apps/mobile/app/(tabs)/library.tsx index aaed47bc6..8a8c21a36 100644 --- a/apps/mobile/app/(tabs)/library.tsx +++ b/apps/mobile/app/(tabs)/library.tsx @@ -96,9 +96,10 @@ export default function LibraryScreen() { data={experiences} keyExtractor={(item) => item.documentId} contentContainerStyle={styles.listContent} - renderItem={({ item }) => ( + renderItem={({ item, index }) => ( @@ -112,6 +113,7 @@ export default function LibraryScreen() { function ExperienceCard({ experience, + index, isActive, onSelect, }: { @@ -122,6 +124,7 @@ function ExperienceCard({ metaDescription: string | null ogImage: { url: string; alternativeText: string | null } | null } + index: number isActive: boolean onSelect: (slug: string) => void }) { @@ -130,6 +133,7 @@ function ExperienceCard({ return ( onSelect(experience.slug)} style={[styles.card, isActive && styles.cardActive]} accessibilityRole="button" diff --git a/apps/mobile/app/(tabs)/watch.tsx b/apps/mobile/app/(tabs)/watch.tsx index e4cde556d..f719ba228 100644 --- a/apps/mobile/app/(tabs)/watch.tsx +++ b/apps/mobile/app/(tabs)/watch.tsx @@ -257,6 +257,7 @@ export default function DiscoverScreen() { ( router.back()} accessibilityRole="button" accessibilityLabel="Go back" @@ -204,6 +205,7 @@ export default function RootLayout() { headerTitleAlign: "center", headerLeft: () => ( router.back()} accessibilityRole="button" accessibilityLabel="Go back" diff --git a/apps/mobile/app/collection/[sectionKey].tsx b/apps/mobile/app/collection/[sectionKey].tsx index e4a6229c3..d7aaf3806 100644 --- a/apps/mobile/app/collection/[sectionKey].tsx +++ b/apps/mobile/app/collection/[sectionKey].tsx @@ -247,6 +247,7 @@ function CollectionPlayerContent({ return ( [ styles.row, isActive && styles.rowActive, diff --git a/apps/mobile/app/video/[sectionKey].tsx b/apps/mobile/app/video/[sectionKey].tsx index 54009bd99..b54189139 100644 --- a/apps/mobile/app/video/[sectionKey].tsx +++ b/apps/mobile/app/video/[sectionKey].tsx @@ -97,6 +97,7 @@ function VideoDetailContent({ headerTitle: title ?? "", headerRight: () => ( { const parts = [`Check out "${displayTitle}" on JesusFilm!`] if (shareUrl != null) parts.push(shareUrl) @@ -201,6 +202,7 @@ function VideoDetailContent({ /> {!hasStarted && thumbnailUrl != null && ( onSelect(result.slug)} accessibilityRole="button" accessibilityLabel={`${result.title}: ${result.snippet}`} diff --git a/apps/mobile/src/components/sections/BibleQuotesCarouselRenderer.tsx b/apps/mobile/src/components/sections/BibleQuotesCarouselRenderer.tsx index 6c2d58158..29d343667 100644 --- a/apps/mobile/src/components/sections/BibleQuotesCarouselRenderer.tsx +++ b/apps/mobile/src/components/sections/BibleQuotesCarouselRenderer.tsx @@ -106,6 +106,7 @@ function QuoteCard({ return null return ( [ styles.ctaButton, pressed && styles.ctaButtonPressed, @@ -231,6 +232,7 @@ export function BibleQuotesCarouselRenderer({ )} + return case "text": return case "relatedQuestions": diff --git a/apps/mobile/src/components/sections/CuratedHomeLayout.tsx b/apps/mobile/src/components/sections/CuratedHomeLayout.tsx index b0782d94b..48e00f743 100644 --- a/apps/mobile/src/components/sections/CuratedHomeLayout.tsx +++ b/apps/mobile/src/components/sections/CuratedHomeLayout.tsx @@ -201,6 +201,7 @@ export function CuratedHomeLayout() { > {muteButtonRect != null && ( [ card.surface, { width: cardWidth }, diff --git a/apps/mobile/src/components/sections/NavigationCarouselRenderer.tsx b/apps/mobile/src/components/sections/NavigationCarouselRenderer.tsx index 60f76a74d..7472dff78 100644 --- a/apps/mobile/src/components/sections/NavigationCarouselRenderer.tsx +++ b/apps/mobile/src/components/sections/NavigationCarouselRenderer.tsx @@ -62,6 +62,7 @@ export function NavigationCarouselRenderer({ return ( [ card.base, styles.localCard, diff --git a/apps/mobile/src/components/sections/QuizButtonRenderer.tsx b/apps/mobile/src/components/sections/QuizButtonRenderer.tsx index ba347dcc0..a664049c8 100644 --- a/apps/mobile/src/components/sections/QuizButtonRenderer.tsx +++ b/apps/mobile/src/components/sections/QuizButtonRenderer.tsx @@ -68,6 +68,7 @@ function QuizModal({ url, onClose }: { url: string; onClose: () => void }) { [styles.button, pressed && feedback.pressed]} onPress={() => setModalVisible(true)} accessibilityRole="button" diff --git a/apps/mobile/src/components/sections/RelatedQuestionsRenderer.tsx b/apps/mobile/src/components/sections/RelatedQuestionsRenderer.tsx index aa1651882..b15836fcc 100644 --- a/apps/mobile/src/components/sections/RelatedQuestionsRenderer.tsx +++ b/apps/mobile/src/components/sections/RelatedQuestionsRenderer.tsx @@ -30,10 +30,12 @@ export interface RelatedQuestionsRendererProps { function QuestionRow({ item, + index, isExpanded, onToggle, }: { item: QuestionItem + index: number isExpanded: boolean onToggle: () => void }) { @@ -42,6 +44,7 @@ function QuestionRow({ return ( )} - {questions.map((item) => ( + {questions.map((item, index) => ( handleToggle(item.id)} /> diff --git a/apps/mobile/src/components/sections/VideoCardRenderer.tsx b/apps/mobile/src/components/sections/VideoCardRenderer.tsx index 23e9d13dc..7078df941 100644 --- a/apps/mobile/src/components/sections/VideoCardRenderer.tsx +++ b/apps/mobile/src/components/sections/VideoCardRenderer.tsx @@ -22,11 +22,15 @@ import type { VideoRef } from "../../lib/types" export interface VideoCardRendererProps { section: NormalizedBlock + index?: number } // ── Component ─────────────────────────────────────────────────────────────── -export function VideoCardRenderer({ section }: VideoCardRendererProps) { +export function VideoCardRenderer({ + section, + index = 0, +}: VideoCardRendererProps) { const router = useRouter() const typography = useTypography() @@ -53,6 +57,7 @@ export function VideoCardRenderer({ section }: VideoCardRendererProps) { return ( [ styles.container, pressed && Platform.OS === "ios" && feedback.pressed, diff --git a/apps/mobile/src/components/sections/VideoCarouselRenderer.tsx b/apps/mobile/src/components/sections/VideoCarouselRenderer.tsx index 298a9e8bc..61b4f2d81 100644 --- a/apps/mobile/src/components/sections/VideoCarouselRenderer.tsx +++ b/apps/mobile/src/components/sections/VideoCarouselRenderer.tsx @@ -88,6 +88,7 @@ export function VideoCarouselRenderer({ section }: VideoCarouselRendererProps) { return ( [ card.surface, { width: cardWidth, height: cardHeight }, diff --git a/apps/mobile/src/components/sections/VideoHeroRenderer.tsx b/apps/mobile/src/components/sections/VideoHeroRenderer.tsx index 4bdd88a05..91414aaa1 100644 --- a/apps/mobile/src/components/sections/VideoHeroRenderer.tsx +++ b/apps/mobile/src/components/sections/VideoHeroRenderer.tsx @@ -276,6 +276,7 @@ export function VideoHeroRenderer({ )} {hasCta && ( [ styles.ctaButton, pressed && feedback.pressed, diff --git a/apps/mobile/src/components/ui/HomeHeader.tsx b/apps/mobile/src/components/ui/HomeHeader.tsx index a926762e6..3001f0aa0 100644 --- a/apps/mobile/src/components/ui/HomeHeader.tsx +++ b/apps/mobile/src/components/ui/HomeHeader.tsx @@ -31,6 +31,7 @@ export function HomeHeader({ title, titleOpacity }: HomeHeaderProps) { pointerEvents="none" /> router.navigate("/(tabs)/watch")} @@ -57,6 +58,7 @@ export function HomeHeader({ title, titleOpacity }: HomeHeaderProps) { )} router.navigate("/(tabs)/profile")} diff --git a/apps/web/.gitignore b/apps/web/.gitignore new file mode 100644 index 000000000..5c4ffa21f --- /dev/null +++ b/apps/web/.gitignore @@ -0,0 +1,2 @@ +playwright-report/ +test-results/ diff --git a/apps/web/src/components/SearchOverlay.tsx b/apps/web/src/components/SearchOverlay.tsx index bc38bf561..c243a0246 100644 --- a/apps/web/src/components/SearchOverlay.tsx +++ b/apps/web/src/components/SearchOverlay.tsx @@ -243,6 +243,7 @@ export function SearchOverlay({ open, onClose, closing }: SearchOverlayProps) { onClick={onClose} className="rounded-full p-3 text-stone-400 transition hover:text-white" aria-label="Close search" + data-testid="search-close" > - +

{displayTitle} @@ -117,7 +118,10 @@ export function AdventCountdown({ data }: AdventCountdownProps) { ) : (
-

+

{days}

diff --git a/apps/web/src/components/sections/BibleQuotesCarousel.tsx b/apps/web/src/components/sections/BibleQuotesCarousel.tsx index 2d76ef8c4..b06079039 100644 --- a/apps/web/src/components/sections/BibleQuotesCarousel.tsx +++ b/apps/web/src/components/sections/BibleQuotesCarousel.tsx @@ -35,7 +35,7 @@ export function BibleQuotesCarousel({ data }: BibleQuotesCarouselProps) { if (validQuotes.length === 0) return null return ( -

+
- - {quote.reference} - -

- {quote.text} -

- +
+ + + {quote.reference} + +

+ {quote.text} +

+
+
) } @@ -169,6 +171,7 @@ function FreeResourceCard({ quote }: { quote: QuoteItem }) {