Skip to content

Commit

Permalink
fix: fixes from review
Browse files Browse the repository at this point in the history
  • Loading branch information
mmeissonnier-pass committed Jan 27, 2025
1 parent e49078e commit e391fc7
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 107 deletions.
Original file line number Diff line number Diff line change
@@ -1,33 +1,91 @@
import React from 'react'

import { ChronicleCardListProps } from 'features/chronicle/components/ChronicleCardList/ChronicleCardListBase'
import { chroniclesSnap } from 'features/chronicle/fixtures/chroniclesSnap'
import { fireEvent, render, screen, waitFor } from 'tests/utils/web'

import { ChronicleCardList } from './ChronicleCardList'

describe('ChronicleCardList', () => {
it('should render the ChronicleCardList correctly', () => {
render(<ChronicleCardList data={chroniclesSnap} />)
let mockCallback: (
entries: {
target: HTMLElement
contentRect: Partial<DOMRectReadOnly>
}[]
) => void

beforeAll(() => {
const mockResizeObserver = jest.fn().mockImplementation((callback) => {
mockCallback = callback
return {
observe: jest.fn(),
disconnect: jest.fn(),
unobserve: jest.fn(),
}
})

global.ResizeObserver = mockResizeObserver
})

const forceOnLayout = () => {
// Simuler un changement de taille
const list = screen.getByTestId('chronicle-list')
const listParent = list.parentElement

if (!listParent) {
return
}

Object.defineProperties(listParent, {
offsetHeight: { value: 400 },
offsetWidth: { value: 4000 },
})

Object.defineProperties(list, {
scrollWidth: { value: 4000 },
offsetWidth: { value: 400 },
})

mockCallback([
{
target: listParent,
contentRect: { width: 4000, height: 400, top: 0, left: 0 },
},
])
}

it('should render the ChronicleCardList correctly', async () => {
renderChronicleList()
forceOnLayout()

await screen.findByTestId('chronicle-list-right-arrow')

expect(screen.getByText('Le Voyage Extraordinaire')).toBeInTheDocument()
expect(screen.getByText('L’Art de la Cuisine')).toBeInTheDocument()
})

it('should render the ChronicleCardList with horizontal mode', () => {
render(<ChronicleCardList data={chroniclesSnap} />)
it('should render the ChronicleCardList in horizontal mode', async () => {
renderChronicleList()
forceOnLayout()

expect(screen.getByTestId('chronicle-list-right-arrow')).toBeInTheDocument()
expect(await screen.findByTestId('chronicle-list-right-arrow')).toBeInTheDocument()
})

it('should render the ChronicleCardList with vertical mode', () => {
render(<ChronicleCardList data={chroniclesSnap} horizontal={false} />)
it('should render the ChronicleCardList in vertical mode', async () => {
renderChronicleList({ horizontal: false })
forceOnLayout()

expect(screen.queryByTestId('chronicle-list-left-arrow')).not.toBeInTheDocument()
expect(screen.queryByTestId('chronicle-list-right-arrow')).not.toBeInTheDocument()
await waitFor(() => {
expect(screen.queryByTestId('chronicle-list-left-arrow')).not.toBeInTheDocument()
expect(screen.queryByTestId('chronicle-list-right-arrow')).not.toBeInTheDocument()
})
})

it('should go to next page when right arrow is pressed', () => {
render(<ChronicleCardList data={chroniclesSnap} horizontal />)
it('should go to next page when right arrow is pressed', async () => {
renderChronicleList()
forceOnLayout()

await screen.findByTestId('chronicle-list-right-arrow')

fireEvent.click(screen.getByTestId('chronicle-list-right-arrow'))

Expand All @@ -38,19 +96,18 @@ describe('ChronicleCardList', () => {
})

it('should go to previous page when left arrow is pressed', async () => {
render(<ChronicleCardList data={chroniclesSnap} horizontal />)
renderChronicleList()
forceOnLayout()

const listElement = screen.getByTestId('chronicle-list')
Object.defineProperty(listElement, 'scrollWidth', { get: () => 900 })
Object.defineProperty(listElement, 'offsetWidth', { get: () => 300 })

await screen.findByTestId('chronicle-list-right-arrow')

fireEvent.click(screen.getByTestId('chronicle-list-right-arrow'))
// We have to force scroll event. onScroll is not triggered when using scrollToOffset via ref
fireEvent.scroll(listElement)

await screen.findByTestId('chronicle-list-left-arrow')

fireEvent.click(screen.getByTestId('chronicle-list-left-arrow'))
fireEvent.click(await screen.findByTestId('chronicle-list-left-arrow'))
fireEvent.scroll(listElement)

await waitFor(() => {
Expand All @@ -59,26 +116,34 @@ describe('ChronicleCardList', () => {
})
})

it('should disable the left arrow when on the first item', () => {
render(<ChronicleCardList data={chroniclesSnap} horizontal />)
it('should disable the left arrow when on the first item', async () => {
renderChronicleList()
forceOnLayout()

await screen.findByTestId('chronicle-list-right-arrow')

// Ensure that the left arrow is not clickable on the first item
expect(screen.queryByTestId('chronicle-list-left-arrow')).not.toBeInTheDocument()
})

it('should disable the right arrow when on the last item', async () => {
render(<ChronicleCardList data={chroniclesSnap.slice(0, 2)} horizontal />)
renderChronicleList({ data: chroniclesSnap.slice(0, 2) })

const listElement = screen.getByTestId('chronicle-list')
Object.defineProperty(listElement, 'scrollWidth', { get: () => 900 })
Object.defineProperty(listElement, 'offsetWidth', { get: () => 300 })

fireEvent.scroll(listElement, {
target: { scrollLeft: 600 },
target: { scrollLeft: 3600 },
})

await waitFor(() =>
expect(screen.queryByTestId('chronicle-list-right-arrow')).not.toBeInTheDocument()
)
})
})

const renderChronicleList = (props?: Partial<ChronicleCardListProps>) => {
render(<ChronicleCardList {...props} data={props?.data || chroniclesSnap} />)

const listElement = screen.getByTestId('chronicle-list')
fireEvent.scroll(listElement)
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import React, { FunctionComponent, useState } from 'react'
import {
LayoutChangeEvent,
LayoutRectangle,
NativeScrollEvent,
NativeSyntheticEvent,
} from 'react-native'
import React, { FunctionComponent, useRef } from 'react'
import { useWindowDimensions } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
import { useTheme } from 'styled-components'
import styled from 'styled-components/native'

import { CHRONICLE_CARD_WIDTH } from 'features/chronicle/constant'
import { useHorizontalFlatListScroll } from 'ui/hooks/useHorizontalFlatListScroll'
import { PlaylistArrowButton } from 'ui/Playlist/PlaylistArrowButton'

import {
Expand All @@ -25,70 +22,52 @@ export const ChronicleCardList: FunctionComponent<ChronicleCardListProps> = ({
headerComponent,
separatorSize = SEPARATOR_DEFAULT_VALUE,
}) => {
const [userOffset, setUserOffset] = useState(0)
const [scrollOffset, setScrollOffset] = useState(0)
const [layout, setLayout] = useState<LayoutRectangle>()
const [leftArrowVisible, setLeftArrowVisible] = useState(false)
const [rightArrowVisible, setRightArrowVisible] = useState(true)

const { isDesktopViewport } = useTheme()
const { width: windowWidth } = useWindowDimensions()

const pageWidth = isDesktopViewport ? layout?.width ?? 0 : CHRONICLE_CARD_WIDTH
const goToPreviousPage = () => setUserOffset(Math.max(scrollOffset - pageWidth, 0))
const goToNextPage = () => setUserOffset(scrollOffset + pageWidth)

const handleLayout = (event: LayoutChangeEvent) => {
setLayout(event.nativeEvent.layout)
}

const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
const { contentSize, layoutMeasurement, contentOffset } = event.nativeEvent
const progress = contentOffset.x / (contentSize.width - layoutMeasurement.width)

setScrollOffset(contentOffset.x)
const listRef = useRef<FlatList>(null)

switch (progress) {
case 0:
setLeftArrowVisible(false)
setRightArrowVisible(true)
break
case 1:
setLeftArrowVisible(true)
setRightArrowVisible(false)
break
default:
setLeftArrowVisible(true)
setRightArrowVisible(true)
}
}
const {
onScroll,
handleScrollNext,
handleScrollPrevious,
onContainerLayout,
isEnd,
isStart,
onContentSizeChange,
} = useHorizontalFlatListScroll({
ref: listRef,
scrollRatio: isDesktopViewport ? 1 : (cardWidth ?? CHRONICLE_CARD_WIDTH) / windowWidth,
})

return (
<FlatListContainer onLayout={handleLayout}>
<FlatListContainer onLayout={onContainerLayout}>
{horizontal ? (
<React.Fragment>
{leftArrowVisible ? (
{isStart ? null : (
<PlaylistArrowButton
direction="left"
onPress={goToPreviousPage}
onPress={handleScrollPrevious}
testID="chronicle-list-left-arrow"
/>
) : null}
)}

{rightArrowVisible ? (
{isEnd ? null : (
<PlaylistArrowButton
direction="right"
onPress={goToNextPage}
onPress={handleScrollNext}
testID="chronicle-list-right-arrow"
/>
) : null}
)}
</React.Fragment>
) : null}
<ChronicleCardListBase
data={data}
offset={userOffset}
ref={listRef}
horizontal={horizontal}
cardWidth={cardWidth}
onScroll={handleScroll}
onScroll={onScroll}
onContentSizeChange={onContentSizeChange}
headerComponent={headerComponent}
separatorSize={separatorSize}
contentContainerStyle={contentContainerStyle}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react'
import React, { createRef } from 'react'
import { FlatList } from 'react-native-gesture-handler'

import { CHRONICLE_CARD_WIDTH } from 'features/chronicle/constant'
import { chroniclesSnap } from 'features/chronicle/fixtures/chroniclesSnap'
Expand All @@ -7,20 +8,29 @@ import { render, screen } from 'tests/utils'
import { ChronicleCardListBase } from './ChronicleCardListBase'

describe('ChronicleCardListBase', () => {
const ref = createRef<FlatList>()

it('should display all chronicle cards in the list in horizontal', () => {
render(<ChronicleCardListBase data={chroniclesSnap} horizontal separatorSize={10} />)
render(<ChronicleCardListBase data={chroniclesSnap} horizontal separatorSize={10} ref={ref} />)

expect(screen.getByText('Le Voyage Extraordinaire')).toBeOnTheScreen()
})

it('should display all chronicle cards in the list in vertical', () => {
render(<ChronicleCardListBase data={chroniclesSnap} separatorSize={20} />)
render(<ChronicleCardListBase data={chroniclesSnap} separatorSize={20} ref={ref} />)

expect(screen.getByText('Le Voyage Extraordinaire')).toBeOnTheScreen()
})

it('should scroll to the correct page when offset is provided', () => {
render(<ChronicleCardListBase data={chroniclesSnap} offset={CHRONICLE_CARD_WIDTH} horizontal />)
render(
<ChronicleCardListBase
data={chroniclesSnap}
offset={CHRONICLE_CARD_WIDTH}
horizontal
ref={ref}
/>
)

expect(screen.getByText('La Nature Sauvage')).toBeOnTheScreen()
})
Expand Down
Loading

0 comments on commit e391fc7

Please sign in to comment.