Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/mobile/app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default function TabLayout() {
name="index"
options={{
title: "Home",
tabBarButtonTestID: "tab-home",
tabBarIcon: ({ color, size }) => (
<Ionicons name="home" size={size} color={color} />
),
Expand All @@ -36,6 +37,7 @@ export default function TabLayout() {
name="watch"
options={{
title: "Discover",
tabBarButtonTestID: "tab-discover",
headerShown: true,
headerTitle: "Discover",
headerStyle: { backgroundColor: BG_COLOR },
Expand All @@ -50,6 +52,7 @@ export default function TabLayout() {
name="library"
options={{
title: "Library",
tabBarButtonTestID: "tab-library",
tabBarIcon: ({ color, size }) => (
<Ionicons name="albums-outline" size={size} color={color} />
),
Expand All @@ -59,6 +62,7 @@ export default function TabLayout() {
name="profile"
options={{
title: "Profile",
tabBarButtonTestID: "tab-profile",
tabBarIcon: ({ color, size }) => (
<Ionicons name="person" size={size} color={color} />
),
Expand Down
6 changes: 5 additions & 1 deletion apps/mobile/app/(tabs)/library.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,10 @@ export default function LibraryScreen() {
data={experiences}
keyExtractor={(item) => item.documentId}
contentContainerStyle={styles.listContent}
renderItem={({ item }) => (
renderItem={({ item, index }) => (
<ExperienceCard
experience={item}
index={index}
isActive={item.slug === currentSlug}
onSelect={handleSelect}
/>
Expand All @@ -112,6 +113,7 @@ export default function LibraryScreen() {

function ExperienceCard({
experience,
index,
isActive,
onSelect,
}: {
Expand All @@ -122,6 +124,7 @@ function ExperienceCard({
metaDescription: string | null
ogImage: { url: string; alternativeText: string | null } | null
}
index: number
isActive: boolean
onSelect: (slug: string) => void
}) {
Expand All @@ -130,6 +133,7 @@ function ExperienceCard({

return (
<Pressable
testID={`experience-card-${index}`}
onPress={() => onSelect(experience.slug)}
style={[styles.card, isActive && styles.cardActive]}
accessibilityRole="button"
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/app/(tabs)/watch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ export default function DiscoverScreen() {
<View style={styles.container}>
<View style={styles.inputContainer}>
<TextInput
testID="search-input"
style={styles.input}
value={query}
onChangeText={handleChangeText}
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ export default function RootLayout() {
headerTitleAlign: "center",
headerLeft: () => (
<Pressable
testID="back-button"
onPress={() => router.back()}
accessibilityRole="button"
accessibilityLabel="Go back"
Expand All @@ -204,6 +205,7 @@ export default function RootLayout() {
headerTitleAlign: "center",
headerLeft: () => (
<Pressable
testID="back-button"
onPress={() => router.back()}
accessibilityRole="button"
accessibilityLabel="Go back"
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/app/collection/[sectionKey].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ function CollectionPlayerContent({

return (
<Pressable
testID={`playlist-item-${idx}`}
style={({ pressed }) => [
styles.row,
isActive && styles.rowActive,
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/app/video/[sectionKey].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ function VideoDetailContent({
headerTitle: title ?? "",
headerRight: () => (
<Pressable
testID="share-button"
onPress={() => {
const parts = [`Check out "${displayTitle}" on JesusFilm!`]
if (shareUrl != null) parts.push(shareUrl)
Expand Down Expand Up @@ -201,6 +202,7 @@ function VideoDetailContent({
/>
{!hasStarted && thumbnailUrl != null && (
<Pressable
testID="video-thumbnail"
style={StyleSheet.absoluteFill}
onPress={handlePlay}
accessibilityRole="button"
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/src/components/search/SearchResultCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function SearchResultCard({
style={[styles.cardOuter, { opacity, transform: [{ scale }] }]}
>
<Pressable
testID={`search-result-${index}`}
onPress={() => onSelect(result.slug)}
accessibilityRole="button"
accessibilityLabel={`${result.title}: ${result.snippet}`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ function QuoteCard({
return null
return (
<Pressable
testID="quote-cta"
style={({ pressed }) => [
styles.ctaButton,
pressed && styles.ctaButtonPressed,
Expand Down Expand Up @@ -231,6 +232,7 @@ export function BibleQuotesCarouselRenderer({
</Text>
)}
<Pressable
testID="share-quote"
onPress={handleShare}
style={[button.iconButton44, styles.localShareButton]}
accessibilityRole="button"
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/components/sections/ContentDispatcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function renderBlock(block: NormalizedBlock, index: number) {

switch (block.kind) {
case "video":
return <VideoCardRenderer key={key} section={block} />
return <VideoCardRenderer key={key} section={block} index={index} />
case "text":
return <TextRenderer key={key} section={block} />
case "relatedQuestions":
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/src/components/sections/CuratedHomeLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ export function CuratedHomeLayout() {
>
{muteButtonRect != null && (
<Pressable
testID="mute-button"
style={{
position: "absolute",
left: muteButtonRect.x,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export function MediaCollectionRenderer({

return (
<Pressable
testID={`media-collection-item-${index}`}
style={({ pressed }) => [
card.surface,
{ width: cardWidth },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export function NavigationCarouselRenderer({
return (
<Pressable
key={`navCarousel-${item.id}-${index}`}
testID={`nav-carousel-item-${index}`}
style={({ pressed }) => [
card.base,
styles.localCard,
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/src/components/sections/QuizButtonRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ function QuizModal({ url, onClose }: { url: string; onClose: () => void }) {
<StatusBar barStyle="light-content" />
<View style={styles.modalOverlay}>
<Pressable
testID="modal-close"
style={[
styles.closeButton,
{ top: Platform.OS === "android" ? insets.top : insets.top + 8 },
Expand Down Expand Up @@ -128,6 +129,7 @@ export function QuizButtonRenderer({ section }: QuizButtonRendererProps) {
<>
<View style={[layout.sectionOuter, styles.localContainer]}>
<Pressable
testID="quiz-button"
style={({ pressed }) => [styles.button, pressed && feedback.pressed]}
onPress={() => setModalVisible(true)}
accessibilityRole="button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ export interface RelatedQuestionsRendererProps {

function QuestionRow({
item,
index,
isExpanded,
onToggle,
}: {
item: QuestionItem
index: number
isExpanded: boolean
onToggle: () => void
}) {
Expand All @@ -42,6 +44,7 @@ function QuestionRow({
return (
<View style={styles.item}>
<Pressable
testID={`accordion-question-${index}`}
style={styles.questionRow}
onPress={onToggle}
accessibilityRole="button"
Expand Down Expand Up @@ -107,6 +110,7 @@ export function RelatedQuestionsRenderer({
)}
{ctaLink != null && (
<Pressable
testID="accordion-cta"
onPress={handleCtaPress}
style={[button.iconButton44, styles.localCtaButton]}
accessibilityRole="link"
Expand All @@ -120,10 +124,11 @@ export function RelatedQuestionsRenderer({
</Pressable>
)}
</View>
{questions.map((item) => (
{questions.map((item, index) => (
<QuestionRow
key={`rq-${item.id}`}
item={item}
index={index}
isExpanded={expandedId === item.id}
onToggle={() => handleToggle(item.id)}
/>
Expand Down
7 changes: 6 additions & 1 deletion apps/mobile/src/components/sections/VideoCardRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -53,6 +57,7 @@ export function VideoCardRenderer({ section }: VideoCardRendererProps) {

return (
<Pressable
testID={`video-card-${index}`}
style={({ pressed }) => [
styles.container,
pressed && Platform.OS === "ios" && feedback.pressed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export function VideoCarouselRenderer({ section }: VideoCarouselRendererProps) {

return (
<Pressable
testID={`video-carousel-card-${index}`}
style={({ pressed }) => [
card.surface,
{ width: cardWidth, height: cardHeight },
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/src/components/sections/VideoHeroRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ export function VideoHeroRenderer({
)}
{hasCta && (
<Pressable
testID="hero-cta"
style={({ pressed }) => [
styles.ctaButton,
pressed && feedback.pressed,
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/src/components/ui/HomeHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export function HomeHeader({ title, titleOpacity }: HomeHeaderProps) {
pointerEvents="none"
/>
<Pressable
testID="header-search"
accessibilityRole="button"
accessibilityLabel="Search"
onPress={() => router.navigate("/(tabs)/watch")}
Expand All @@ -57,6 +58,7 @@ export function HomeHeader({ title, titleOpacity }: HomeHeaderProps) {
)}

<Pressable
testID="header-profile"
accessibilityRole="button"
accessibilityLabel="Profile"
onPress={() => router.navigate("/(tabs)/profile")}
Expand Down
2 changes: 2 additions & 0 deletions apps/web/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
playwright-report/
test-results/
1 change: 1 addition & 0 deletions apps/web/src/components/SearchOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"
>
<svg
xmlns="http://www.w3.org/2000/svg"
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/SearchToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function SearchToggle() {
onClick={handleOpen}
className="rounded-lg p-3 text-stone-300 transition hover:bg-stone-800 hover:text-white"
aria-label="Search"
data-testid="search-toggle"
>
<svg
xmlns="http://www.w3.org/2000/svg"
Expand Down
6 changes: 5 additions & 1 deletion apps/web/src/components/SiteHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ export function SiteHeader() {
<div
className={`${CONTENT_WIDTH_CLASSES} flex h-full items-center justify-between`}
>
<Link href={"/" as Route} className="flex items-center">
<Link
href={"/" as Route}
className="flex items-center"
data-testid="logo"
>
<Image
src="/watch/images/jesusfilm-sign.svg"
alt="JesusFilm"
Expand Down
6 changes: 5 additions & 1 deletion apps/web/src/components/sections/AdventCountdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export function AdventCountdown({ data }: AdventCountdownProps) {
aria-expanded={expanded}
aria-controls={contentId}
id={headerId}
data-testid="advent-toggle"
>
<h4 className="text-2xl font-bold text-white/90 xl:text-3xl">
{displayTitle}
Expand Down Expand Up @@ -117,7 +118,10 @@ export function AdventCountdown({ data }: AdventCountdownProps) {
</div>
) : (
<div>
<p className="text-6xl font-extrabold tracking-tighter text-white/90">
<p
className="text-6xl font-extrabold tracking-tighter text-white/90"
data-testid="advent-days"
>
{days}
</p>
<p className="text-lg font-medium text-white/60">
Expand Down
29 changes: 16 additions & 13 deletions apps/web/src/components/sections/BibleQuotesCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function BibleQuotesCarousel({ data }: BibleQuotesCarouselProps) {
if (validQuotes.length === 0) return null

return (
<div data-testid="bible-quotes-carousel" className="pt-14 pb-6">
<div data-testid="bible-quotes" className="pt-14 pb-6">
<BibleQuotesHeader heading={heading} />
<div className={CAROUSEL_BLEED_CLASSES}>
<Carousel
Expand Down Expand Up @@ -139,18 +139,20 @@ function BibleQuoteCard({

function QuoteCard({ quote }: { quote: QuoteItem }) {
return (
<BibleQuoteCard
imageUrl={quote.imageUrl}
bgColor={quote.backgroundColor}
altText={quote.reference}
>
<span className="mb-1 block text-[10px] font-semibold tracking-[0.15em] text-amber-200/60 uppercase">
{quote.reference}
</span>
<p className="text-base leading-relaxed text-balance text-white/90">
{quote.text}
</p>
</BibleQuoteCard>
<div data-testid="quote-cta">
<BibleQuoteCard
imageUrl={quote.imageUrl}
bgColor={quote.backgroundColor}
altText={quote.reference}
>
<span className="mb-1 block text-[10px] font-semibold tracking-[0.15em] text-amber-200/60 uppercase">
{quote.reference}
</span>
<p className="text-base leading-relaxed text-balance text-white/90">
{quote.text}
</p>
</BibleQuoteCard>
</div>
)
}

Expand All @@ -169,6 +171,7 @@ function FreeResourceCard({ quote }: { quote: QuoteItem }) {
</h3>
<Button
variant="pill"
data-testid="resource-cta"
render={
quote.ctaLink ? (
<a href={quote.ctaLink} target="_blank" rel="noopener noreferrer" />
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/sections/CarouselVideo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ function ThumbnailCard({
}
}}
aria-label={`Play ${title}`}
data-testid="carousel-thumbnail"
className={`group relative m-1 flex h-[240px] w-full cursor-pointer flex-col justify-end overflow-hidden rounded-lg ${
isSelected ? "outline-4 outline-white" : ""
}`}
Expand Down
Loading
Loading