Repository: pass-culture/pass-culture-app-native
Pull request #7960: (PC-35282) feat(SearchBox): redirect to ThematicSearch when "cinema" …
Author: login: nmajorfrances-pass
Created: 2025-04-03T16:04:20Z | Merged: 2025-04-07T07:39:26Z

…query on SearchLanding

Link to JIRA ticket: https://passculture.atlassian.net/browse/PC-35282

## Flakiness

If I had to re-run tests in the CI due to flakiness, I add the incident [on Notion][2]

## Checklist

I have:

- [x] Made sure my feature is working on web.
- [x] Made sure my feature is working on mobile (depending on relevance : real or virtual devices)
- [x] Written **unit tests** native (and web when implementation is different) for my feature.
- [ ] Added a **screenshot** for UI tickets or deleted the screenshot section if no UI change
- [ ] If my PR is a bugfix, I add the link of the "résolution de problème sur le bug" [on Notion][1]
- [ ] I am aware of all the best practices and respected them.

[1]: https://www.notion.so/passcultureapp/R-solution-de-probl-mes-sur-les-bugs-5dd6df8f6a754e6887066cf613467d0a
[2]: https://www.notion.so/passcultureapp/cb45383351b44723a6f2d9e1481ad6bb?v=10fe47258701423985aa7d25bb04cfee&pvs=4

## Best Practices

<details>
  <summary>Click to expand</summary>

These rules apply to files that you make changes to.
If you can't respect one of these rules, be sure to explain why with a comment.
If you consider correcting the issue is too time consuming/complex: create a ticket. Link the ticket in the code.

- In the production code: remove type assertions with `as` (type assertions are removed at compile-time, there is no runtime checking associated with a type assertion. There won’t be an exception or `null` generated if the type assertion is wrong). In certain cases `as const` is acceptable (for example when defining readonly arrays/objects). Using `as` in tests is tolerable.
- Remove bypass type checking with `any` (when you want to accept anything because you will be blindly passing it through without interacting with it, you can use `unknown`). Using `any` in tests is tolerable.
- Remove non-null assertion operators (just like other type assertions, this doesn’t change the runtime behavior of your code, so it’s important to only use `!` when you know that the value can’t be `null` or `undefined`).
- Remove all `@ts-expect-error` and `@eslint-disable`.
- Remove all warnings, and errors that we are used to ignore (`yarn test:lint`, `yarn test:types`, `yarn start:web`...).
- Use `gap` (`ViewGap`) instead of `<Spacer.Column />`, `<Spacer.Row />` or `<Spacer.Flex />`.
- Don't add new "alias hooks" (hooks created to group other hooks together). When adding new logic, this hook will progressively become more complex and harder to maintain.
- Remove logic from components that should be dumb.
- undefined != null : undefined should be used for optionals and null when no value

### Request specific:

- A request must use `react-query`
- A hook that use `react-query` must:
  - folder
    - when used in one feature
      - be in `src/<feature>/queries/`
    - when used by several features
      - be in `src/queries/<the main feature related to the query>/`
  - file
    - when use `useQuery` or hook related (like `useInfiniteQuery`)
      - named `use<the content retrieved by the query>Query.ts`
      - returns the type `UseQueryResult<the content retrieved by the query>`
    - when use `useMutation`
      - named `use<the content mutated by the query>Mutation.ts`
      - returns the type `UseMutationResult<the content mutated by the query>`

### Test specific:

- Avoid mocking internal parts of our code. Ideally, mock only external calls.
- When you see a local variable that is over-written in every test, mock it.
- Prefer `user` to `fireEvent`.
- When mocking feature flags, use `setFeatureFlags`. If not possible, mention which one(s) you want to mock in a comment (example: `jest.spyOn(useFeatureFlagAPI, 'useFeatureFlag').mockReturnValue(true) // WIP_NEW_OFFER_TILE in renderPassPlaylist.tsx` )
- In component tests, replace `await act(async () => {})` and `await waitFor(/* ... */)` by `await screen.findBySomething()`.
- In hooks tests, use `act` by default and `waitFor` as a last resort.
- Make a snapshot test for pages and modals ONLY.
- Make a web specific snapshot when your web page/modal is specific to the web.
- Make an a11y test for web pages.

### Advice:

- Use TDD
- Use Storybook
- Use pair programming/mobs

</details>



Diff:
diff --git a/src/features/search/api/useSearchResults/useSearchResults.native.test.ts b/src/features/search/api/useSearchResults/useSearchResults.native.test.ts
index 5e8753994f7b..a7440e417eb2 100644
--- a/src/features/search/api/useSearchResults/useSearchResults.native.test.ts
+++ b/src/features/search/api/useSearchResults/useSearchResults.native.test.ts
@@ -1,13 +1,10 @@
 import { Hit } from '@algolia/client-search'
-import { Dispatch } from 'react'
 
 import algoliasearch from '__mocks__/algoliasearch'
-import { defaultDisabilitiesProperties } from 'features/accessibility/context/AccessibilityFiltersWrapper'
 import { useSearchInfiniteQuery } from 'features/search/api/useSearchResults/useSearchResults'
-import { Action, initialSearchState } from 'features/search/context/reducer'
+import { initialSearchState } from 'features/search/context/reducer'
 import { SearchState } from 'features/search/types'
 import * as useVenueMapStore from 'features/venueMap/store/venueMapStore'
-import * as doAlgoliaRedirect from 'libs/algolia/doAlgoliaRedirect'
 import { offerAttributesToRetrieve } from 'libs/algolia/fetchAlgolia/buildAlgoliaParameters/offerAttributesToRetrieve'
 import * as fetchSearchResults from 'libs/algolia/fetchAlgolia/fetchSearchResults/fetchSearchResults'
 import { adaptAlgoliaVenues } from 'libs/algolia/fetchAlgolia/fetchVenues/adaptAlgoliaVenues'
@@ -19,7 +16,7 @@ import {
 import { AlgoliaVenue } from 'libs/algolia/types'
 import { GeoCoordinates, GeolocPermissionState, GeolocationError } from 'libs/location'
 import { reactQueryProviderHOC } from 'tests/reactQueryProviderHOC'
-import { act, renderHook, waitFor } from 'tests/utils'
+import { renderHook, waitFor } from 'tests/utils'
 
 const { multipleQueries } = algoliasearch()
 
@@ -56,7 +53,6 @@ const mockFetchSearchResultsResponse = {
 }
 
 const fetchSearchResultsSpy = jest.spyOn(fetchSearchResults, 'fetchSearchResults')
-const doAlgoliaRedirectSpy = jest.spyOn(doAlgoliaRedirect, 'doAlgoliaRedirect')
 
 const mockReplaceToSearch = jest.fn()
 jest.mock('features/search/helpers/useNavigateToSearch/useNavigateToSearch', () => ({
@@ -216,39 +212,11 @@ describe('useSearchResults', () => {
       })
     })
   })
-
-  describe('When a redirect url is configured', () => {
-    const mockRedirectUrl =
-      'http://passculture.app/recherche/resultats?offerCategories=%5B%22CINEMA%22%5D&query=%22%22'
-
-    beforeAll(() => {
-      fetchSearchResultsSpy.mockResolvedValueOnce({
-        ...mockFetchSearchResultsResponse,
-        redirectUrl: mockRedirectUrl,
-      })
-    })
-
-    it('should redirect to thematicSearch', async () => {
-      const mockSearchstate = { ...initialSearchState, shouldRedirect: true }
-      renderUseSearchResults(mockSearchstate)
-
-      await act(async () => {})
-
-      expect(doAlgoliaRedirectSpy).toHaveBeenCalledWith(
-        new URL(mockRedirectUrl),
-        mockSearchstate,
-        defaultDisabilitiesProperties,
-        mockDispatch,
-        mockReplaceToSearch
-      )
-    })
-  })
 })
 
 const renderUseSearchResults = (newSearchState?: SearchState) =>
   renderHook(
-    ({ searchState, dispatch }: { searchState: SearchState; dispatch: Dispatch<Action> }) =>
-      useSearchInfiniteQuery(searchState, dispatch),
+    ({ searchState }: { searchState: SearchState }) => useSearchInfiniteQuery(searchState),
     {
       wrapper: ({ children }) => reactQueryProviderHOC(children),
       initialProps: { searchState: newSearchState ?? initialSearchState, dispatch: mockDispatch },
diff --git a/src/features/search/api/useSearchResults/useSearchResults.ts b/src/features/search/api/useSearchResults/useSearchResults.ts
index 4ee56618f01f..b770122392ba 100644
--- a/src/features/search/api/useSearchResults/useSearchResults.ts
+++ b/src/features/search/api/useSearchResults/useSearchResults.ts
@@ -1,20 +1,17 @@
 import { Hit, SearchResponse } from '@algolia/client-search'
 import flatten from 'lodash/flatten'
-import { Dispatch, useMemo, useRef } from 'react'
+import { useMemo, useRef } from 'react'
 import { useInfiniteQuery } from 'react-query'
 
 import { useAccessibilityFiltersContext } from 'features/accessibility/context/AccessibilityFiltersWrapper'
 import { useIsUserUnderage } from 'features/profile/helpers/useIsUserUnderage'
-import { Action } from 'features/search/context/reducer'
 import { useSearch } from 'features/search/context/SearchWrapper'
-import { useNavigateToSearch } from 'features/search/helpers/useNavigateToSearch/useNavigateToSearch'
 import { SearchState } from 'features/search/types'
 import { Venue } from 'features/venue/types'
 import { GeolocatedVenue } from 'features/venueMap/components/VenueMapView/types'
 import { isGeolocValid } from 'features/venueMap/helpers/isGeolocValid'
 import { removeSelectedVenue, setVenues } from 'features/venueMap/store/venueMapStore'
 import { useSearchAnalyticsState } from 'libs/algolia/analytics/SearchAnalyticsWrapper'
-import { doAlgoliaRedirect } from 'libs/algolia/doAlgoliaRedirect'
 import { fetchSearchResults } from 'libs/algolia/fetchAlgolia/fetchSearchResults/fetchSearchResults'
 import { adaptAlgoliaVenues } from 'libs/algolia/fetchAlgolia/fetchVenues/adaptAlgoliaVenues'
 import { useTransformOfferHits } from 'libs/algolia/fetchAlgolia/transformOfferHit'
@@ -37,7 +34,7 @@ export type SearchOfferHits = {
   duplicatedOffers: Offer[]
 }
 
-export const useSearchInfiniteQuery = (searchState: SearchState, dispatch: Dispatch<Action>) => {
+export const useSearchInfiniteQuery = (searchState: SearchState) => {
   const { userLocation, selectedLocationMode, aroundPlaceRadius, aroundMeRadius, geolocPosition } =
     useLocation()
   const { disabilities } = useAccessibilityFiltersContext()
@@ -45,7 +42,6 @@ export const useSearchInfiniteQuery = (searchState: SearchState, dispatch: Dispa
   const transformHits = useTransformOfferHits()
   const { setCurrentQueryID } = useSearchAnalyticsState()
   const previousPageObjectIds = useRef<string[]>([])
-  const { replaceToSearch: navigateToThematicSearch } = useNavigateToSearch('ThematicSearch')
   const { aroundPrecision } = useRemoteConfigQuery()
 
   const { data, ...infiniteQuery } = useInfiniteQuery<SearchOfferResponse>(
@@ -59,40 +55,25 @@ export const useSearchInfiniteQuery = (searchState: SearchState, dispatch: Dispa
       disabilities,
     ],
     async ({ pageParam: page = 0 }) => {
-      const {
-        offersResponse,
-        venuesResponse,
-        facetsResponse,
-        duplicatedOffersResponse,
-        redirectUrl,
-      } = await fetchSearchResults({
-        parameters: { page, ...searchState },
-        buildLocationParameterParams: {
-          userLocation,
-          selectedLocationMode,
-          aroundPlaceRadius,
-          aroundMeRadius,
-          geolocPosition,
-        },
-        isUserUnderage,
-        storeQueryID: setCurrentQueryID,
-        excludedObjectIds: previousPageObjectIds.current,
-        disabilitiesProperties: disabilities,
-        aroundPrecision,
-      })
+      const { offersResponse, venuesResponse, facetsResponse, duplicatedOffersResponse } =
+        await fetchSearchResults({
+          parameters: { page, ...searchState },
+          buildLocationParameterParams: {
+            userLocation,
+            selectedLocationMode,
+            aroundPlaceRadius,
+            aroundMeRadius,
+            geolocPosition,
+          },
+          isUserUnderage,
+          storeQueryID: setCurrentQueryID,
+          excludedObjectIds: previousPageObjectIds.current,
+          disabilitiesProperties: disabilities,
+          aroundPrecision,
+        })
 
       previousPageObjectIds.current = offersResponse.hits.map((hit: Hit<Offer>) => hit.objectID)
 
-      if (redirectUrl && searchState.shouldRedirect) {
-        doAlgoliaRedirect(
-          new URL(redirectUrl),
-          searchState,
-          disabilities,
-          dispatch,
-          navigateToThematicSearch
-        )
-      }
-
       return {
         offers: offersResponse,
         venues: venuesResponse,
@@ -167,6 +148,6 @@ export const useSearchInfiniteQuery = (searchState: SearchState, dispatch: Dispa
 }
 
 export const useSearchResults = () => {
-  const { searchState, dispatch } = useSearch()
-  return useSearchInfiniteQuery(searchState, dispatch)
+  const { searchState } = useSearch()
+  return useSearchInfiniteQuery(searchState)
 }
diff --git a/src/features/search/components/SearchBox/SearchBox.native.test.tsx b/src/features/search/components/SearchBox/SearchBox.native.test.tsx
index 3eb2232d5de0..8d1335da72e9 100644
--- a/src/features/search/components/SearchBox/SearchBox.native.test.tsx
+++ b/src/features/search/components/SearchBox/SearchBox.native.test.tsx
@@ -11,8 +11,6 @@ import * as useFilterCountAPI from 'features/search/helpers/useFilterCount/useFi
 import { BooksNativeCategoriesEnum, SearchState, SearchView } from 'features/search/types'
 import { analytics } from 'libs/analytics/__mocks__/provider'
 import { setFeatureFlags } from 'libs/firebase/firestore/featureFlags/__tests__/setFeatureFlags'
-import * as useRemoteConfigQuery from 'libs/firebase/remoteConfig/queries/useRemoteConfigQuery'
-import { DEFAULT_REMOTE_CONFIG } from 'libs/firebase/remoteConfig/remoteConfig.constants'
 import { GeoCoordinates, Position } from 'libs/location'
 import { LocationLabel, LocationMode } from 'libs/location/types'
 import { mockedSuggestedVenue } from 'libs/venue/fixtures/mockedSuggestedVenues'
@@ -145,7 +143,6 @@ jest.spyOn(useGoBack, 'useGoBack').mockReturnValue({
 jest.useFakeTimers()
 const user = userEvent.setup()
 
-const useRemoteConfigSpy = jest.spyOn(useRemoteConfigQuery, 'useRemoteConfigQuery')
 jest.mock('libs/firebase/analytics/analytics')
 
 describe('SearchBox component', () => {
@@ -171,375 +168,319 @@ describe('SearchBox component', () => {
     mockIsFocusOnSuggestions = false
   })
 
-  describe('shouldRedirectToThematicSearch remote config enabled', () => {
-    beforeAll(() => {
-      useRemoteConfigSpy.mockReturnValue({
-        ...DEFAULT_REMOTE_CONFIG,
-        shouldRedirectToThematicSearch: true,
-      })
-    })
-
-    afterAll(() => {
-      useRemoteConfigSpy.mockReturnValue({
-        ...DEFAULT_REMOTE_CONFIG,
-        shouldRedirectToThematicSearch: false,
-      })
-    })
-
-    it.each(['CINÉMA', 'Cinéma ', 'cinéma', 'cinémas', 'CINEMA', 'Cinema ', 'cinéma', 'cinémas'])(
-      'should log HasSearchedCinemaQuery analytic when queryText is `%s` and SearchView is `Landing`',
-      async (queryText) => {
-        // TODO(PC-32646): useRoute & useRemoteConfigContext are called every time a letter is inputted +1
-        useRoute.mockReturnValue({ name: SearchView.Landing })
-
-        renderSearchBox()
+  it('should render SearchBox', async () => {
+    renderSearchBox()
+    const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
 
-        const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
-
-        await user.type(searchInput, queryText, { submitEditing: true })
-
-        expect(analytics.logHasSearchedCinemaQuery).toHaveBeenCalledTimes(1)
-      }
-    )
+    expect(searchInput).toBeOnTheScreen()
+  })
 
-    it('should update searchState with remote config when current route is searchLanding', async () => {
-      // TODO(PC-32646): useRoute is called every time a letter is inputted +1 (sic!)
-      useRoute
-        .mockReturnValueOnce({ name: SearchView.Landing })
-        .mockReturnValueOnce({ name: SearchView.Landing })
-        .mockReturnValueOnce({ name: SearchView.Landing })
+  it('should set search state on submit', async () => {
+    // TODO(PC-32646): useRoute is called every time a letter is inputted +1 (sic!)
+    useRoute
+      .mockReturnValueOnce({ name: SearchView.Results })
+      .mockReturnValueOnce({ name: SearchView.Results })
 
-      renderSearchBox()
+    renderSearchBox()
 
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+    const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
 
-      await user.type(searchInput, 'HP', { submitEditing: true })
+    await user.type(searchInput, 'j', { submitEditing: true })
 
-      expect(mockDispatch).toHaveBeenNthCalledWith(1, {
-        type: 'SET_STATE',
-        payload: expect.objectContaining({
-          shouldRedirect: true,
-        }),
-      })
+    expect(mockDispatch).toHaveBeenCalledWith({
+      type: 'SET_STATE',
+      payload: {
+        ...initialSearchState,
+        query: 'j',
+        offerCategories: mockSearchState.offerCategories,
+        priceRange: mockSearchState.priceRange,
+        searchId,
+      },
     })
+  })
 
-    it('should not update searchState with remote config when current route is not searchLanding', async () => {
-      // TODO(PC-32646): useRoute is called every time a letter is inputted +1 (sic!)
-      useRoute
-        .mockReturnValueOnce({ name: SearchView.Results })
-        .mockReturnValueOnce({ name: SearchView.Results })
-        .mockReturnValueOnce({ name: SearchView.Results })
-
-      renderSearchBox()
+  it('should display error message when query submitted is longer than 150 characters', async () => {
+    renderSearchBox()
 
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+    const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
 
-      await user.type(searchInput, 'HP', { submitEditing: true })
+    await user.type(searchInput, queryWithMoreThan150characters, { submitEditing: true })
 
-      expect(mockDispatch).toHaveBeenNthCalledWith(1, {
-        type: 'SET_STATE',
-        payload: expect.not.objectContaining({
-          shouldRedirect: expect.anything(),
-        }),
-      })
+    expect(mockShowErrorSnackBar).toHaveBeenCalledWith({
+      message: 'Ta recherche ne peut pas faire plus de 150 caractères.',
+      timeout: SNACK_BAR_TIME_OUT,
     })
   })
 
-  describe('shouldRedirectToThematicSearch remote config disabled', () => {
-    beforeAll(() => {
-      useRemoteConfigSpy.mockReturnValue({
-        ...DEFAULT_REMOTE_CONFIG,
-        shouldRedirectToThematicSearch: false,
-      })
-    })
-
-    describe('Without autocomplete', () => {
-      beforeAll(() => {
-        setSettings({ appEnableAutocomplete: false })
-      })
-
-      it('should stay on the current view when focusing search input and being on the %s view', async () => {
-        useRoute.mockReturnValueOnce({ name: SearchView.Results })
-
-        renderSearchBox()
-
-        const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
-
-        await user.type(searchInput, '')
+  it('should navigate to search results on submit', async () => {
+    // TODO(PC-32646): useRoute is called every time a letter is inputted +1 (sic!)
+    useRoute.mockReturnValueOnce({}).mockReturnValueOnce({})
 
-        expect(mockDispatch).not.toHaveBeenCalled()
-      })
-
-      it('should reset input when user click on reset icon when being focus on the suggestions view', async () => {
-        useRoute.mockReturnValueOnce({ name: SearchView.Results })
+    renderSearchBox()
 
-        mockIsFocusOnSuggestions = true
-        mockSearchState = {
-          ...mockSearchState,
-          query: 'Some text',
-        }
-        renderSearchBox()
+    const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
 
-        const resetIcon = screen.getByTestId('Réinitialiser la recherche')
-        await user.press(resetIcon)
+    await user.type(searchInput, 'j', { submitEditing: true })
 
-        expect(mockDispatch).toHaveBeenCalledWith({
-          type: 'SET_STATE',
-          payload: {
-            ...mockSearchState,
-            query: '',
+    expect(useRoute).toHaveBeenCalledTimes(2)
+    expect(navigate).toHaveBeenCalledWith('TabNavigator', {
+      params: {
+        params: {
+          ...initialSearchState,
+          query: 'j',
+          offerCategories: mockSearchState.offerCategories,
+          priceRange: mockSearchState.priceRange,
+          searchId,
+          accessibilityFilter: {
+            isAudioDisabilityCompliant: undefined,
+            isMentalDisabilityCompliant: undefined,
+            isMotorDisabilityCompliant: undefined,
+            isVisualDisabilityCompliant: undefined,
           },
-        })
-        expect(mockClear).toHaveBeenCalledTimes(1)
-      })
+        },
+        screen: 'SearchResults',
+      },
+      screen: 'SearchStackNavigator',
+    })
+  })
 
-      it('should reset input when user click on reset icon when being on the search results view when isDesktopViewport', async () => {
-        mockSearchState = {
-          ...mockSearchState,
-          query: 'Some text',
-        }
-        useRoute.mockReturnValueOnce({ name: SearchView.Results })
+  it('should not navigate to searchResults when user clicks on reset icon', async () => {
+    useRoute.mockReturnValueOnce({}).mockReturnValueOnce({})
 
-        renderSearchBox(true)
+    renderSearchBox()
 
-        const resetIcon = screen.getByTestId('Réinitialiser la recherche')
-        await user.press(resetIcon)
+    const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+    await user.type(searchInput, 'j')
+    const resetSearchInputButton = screen.getByTestId('Réinitialiser la recherche')
+    await user.press(resetSearchInputButton)
 
-        expect(mockDispatch).toHaveBeenCalledWith({
-          type: 'SET_STATE',
-          payload: {
-            ...mockSearchState,
-            query: '',
-          },
-        })
-        expect(mockClear).toHaveBeenCalledTimes(1)
-      })
+    expect(mockDispatch).toHaveBeenCalledWith({
+      type: 'SET_STATE',
+      payload: mockSearchState,
     })
+    expect(navigate).not.toHaveBeenCalled()
+  })
 
-    describe('With autocomplete', () => {
-      beforeAll(() => {
-        setSettings({ appEnableAutocomplete: true })
-      })
-
-      afterAll(() => {
-        setSettings()
-      })
+  it('should not show back button when being on the search landing view', async () => {
+    useRoute.mockReturnValueOnce({ name: SearchView.Landing })
 
-      it('should unfocus from suggestion when being focus on the suggestions and press back button', async () => {
-        mockIsFocusOnSuggestions = true
-        useRoute.mockReturnValueOnce({ name: SearchView.Landing })
+    renderSearchBox()
 
-        renderSearchBox()
-        const previousButton = screen.getByTestId('Revenir en arrière')
+    const previousButton = screen.queryByTestId('Revenir en arrière')
 
-        await user.press(previousButton)
+    expect(previousButton).not.toBeOnTheScreen()
+  })
 
-        expect(mockHideSuggestions).toHaveBeenNthCalledWith(1)
-      })
+  it('should show back button when being on the search results view', async () => {
+    useRoute.mockReturnValueOnce({ name: SearchView.Results })
 
-      it('should hide suggestions when being focus on suggestions and press back button on landing view', async () => {
-        mockIsFocusOnSuggestions = true
-        useRoute.mockReturnValueOnce({ name: SearchView.Landing })
+    renderSearchBox()
 
-        renderSearchBox()
+    const previousButton = screen.getByTestId('Revenir en arrière')
 
-        const previousButton = screen.getByTestId('Revenir en arrière')
+    expect(previousButton).toBeOnTheScreen()
+  })
 
-        await user.press(previousButton)
+  it('should show back button when being focus on suggestions', async () => {
+    mockIsFocusOnSuggestions = true
+    renderSearchBox()
 
-        expect(mockHideSuggestions).toHaveBeenNthCalledWith(1)
-      })
+    const previousButton = screen.getByTestId('Revenir en arrière')
 
-      it('should reset input when user click on reset icon when being focus on suggestions', async () => {
-        mockIsFocusOnSuggestions = true
-        mockSearchState = {
-          ...mockSearchState,
-          query: 'Some text',
-        }
-        mockQuery = 'Some text'
-        renderSearchBox()
+    expect(previousButton).toBeOnTheScreen()
+  })
 
-        const resetIcon = await screen.findByTestId('Réinitialiser la recherche')
-        await user.press(resetIcon)
+  it('should show the text typed by the user', async () => {
+    renderSearchBox()
 
-        expect(screen.queryByText('Some text')).not.toBeOnTheScreen()
+    const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+    await user.type(searchInput, 'Some text')
 
-        expect(mockClear).toHaveBeenCalledTimes(1)
-      })
-    })
+    expect(searchInput.props.value).toBe('Some text')
+  })
 
-    it('should render SearchBox', async () => {
-      renderSearchBox()
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+  it('should not execute a search if input is empty', async () => {
+    renderSearchBox()
 
-      expect(searchInput).toBeOnTheScreen()
-    })
+    const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
 
-    it('should set search state on submit', async () => {
-      // TODO(PC-32646): useRoute is called every time a letter is inputted +1 (sic!)
-      useRoute
-        .mockReturnValueOnce({ name: SearchView.Results })
-        .mockReturnValueOnce({ name: SearchView.Results })
+    await user.type(searchInput, '')
 
-      renderSearchBox()
+    expect(mockDispatch).not.toHaveBeenCalled()
+  })
 
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+  it('should show reset button when search input is filled', async () => {
+    useRoute.mockReturnValueOnce({ name: SearchView.Results })
 
-      await user.type(searchInput, 'j', { submitEditing: true })
+    mockIsFocusOnSuggestions = true
+    mockQuery = 'Some text'
+    mockSearchState = {
+      ...mockSearchState,
+      query: mockQuery,
+    }
 
-      expect(mockDispatch).toHaveBeenCalledWith({
-        type: 'SET_STATE',
-        payload: {
-          ...initialSearchState,
-          query: 'j',
-          offerCategories: mockSearchState.offerCategories,
-          priceRange: mockSearchState.priceRange,
-          searchId,
-        },
-      })
-    })
+    renderSearchBox()
 
-    it('should display error message when query submitted is longer than 150 characters', async () => {
-      renderSearchBox()
+    expect(await screen.findByLabelText('Réinitialiser la recherche')).toBeOnTheScreen()
+  })
 
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+  it('should not show reset button when search input is empty', async () => {
+    useRoute.mockReturnValueOnce({ name: SearchView.Results })
 
-      await user.type(searchInput, queryWithMoreThan150characters, { submitEditing: true })
+    mockIsFocusOnSuggestions = true
 
-      expect(mockShowErrorSnackBar).toHaveBeenCalledWith({
-        message: 'Ta recherche ne peut pas faire plus de 150 caractères.',
-        timeout: SNACK_BAR_TIME_OUT,
-      })
-    })
+    renderSearchBox()
 
-    it('should navigate to search results on submit', async () => {
-      // TODO(PC-32646): useRoute is called every time a letter is inputted +1 (sic!)
-      useRoute.mockReturnValueOnce({}).mockReturnValueOnce({})
+    expect(screen.queryByLabelText('Réinitialiser la recherche')).not.toBeOnTheScreen()
+  })
 
-      renderSearchBox()
+  it('should reset searchState when user go goBack to Landing', async () => {
+    mockSearchState = {
+      ...mockSearchState,
+      query: 'Some text',
+    }
+    useRoute.mockReturnValueOnce({ name: SearchView.Results })
 
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+    mockQuery = 'Some text'
+    renderSearchBox(true)
 
-      await user.type(searchInput, 'j', { submitEditing: true })
+    const goBackIcon = screen.getByTestId('icon-back')
+    await user.press(goBackIcon)
 
-      expect(useRoute).toHaveBeenCalledTimes(2)
-      expect(navigate).toHaveBeenCalledWith('TabNavigator', {
-        params: {
-          params: {
-            ...initialSearchState,
-            query: 'j',
-            offerCategories: mockSearchState.offerCategories,
-            priceRange: mockSearchState.priceRange,
-            searchId,
-            accessibilityFilter: {
-              isAudioDisabilityCompliant: undefined,
-              isMentalDisabilityCompliant: undefined,
-              isMotorDisabilityCompliant: undefined,
-              isVisualDisabilityCompliant: undefined,
-            },
-          },
-          screen: 'SearchResults',
-        },
-        screen: 'SearchStackNavigator',
-      })
+    expect(mockDispatch).toHaveBeenCalledWith({
+      type: 'SET_STATE',
+      payload: { ...initialSearchState, offerCategories: mockSearchState.offerCategories },
     })
+  })
 
-    it('should not navigate to searchResults when user clicks on reset icon', async () => {
-      useRoute.mockReturnValueOnce({}).mockReturnValueOnce({})
-
-      renderSearchBox()
+  it('should execute a search if input is not empty', async () => {
+    useRoute
+      .mockReturnValueOnce({ name: SearchView.Results })
+      .mockReturnValueOnce({ name: SearchView.Results })
 
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
-      await user.type(searchInput, 'j')
-      const resetSearchInputButton = screen.getByTestId('Réinitialiser la recherche')
-      await user.press(resetSearchInputButton)
+    renderSearchBox()
 
-      expect(mockDispatch).toHaveBeenCalledWith({
-        type: 'SET_STATE',
-        payload: mockSearchState,
-      })
-      expect(navigate).not.toHaveBeenCalled()
-    })
-
-    it('should not show back button when being on the search landing view', async () => {
-      useRoute.mockReturnValueOnce({ name: SearchView.Landing })
-
-      renderSearchBox()
+    const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
 
-      const previousButton = screen.queryByTestId('Revenir en arrière')
+    await user.type(searchInput, 'j', { submitEditing: true })
 
-      expect(previousButton).not.toBeOnTheScreen()
+    expect(mockDispatch).toHaveBeenCalledWith({
+      type: 'SET_STATE',
+      payload: {
+        ...initialSearchState,
+        query: 'j',
+        offerCategories: mockSearchState.offerCategories,
+        priceRange: mockSearchState.priceRange,
+        searchId,
+      },
     })
+  })
 
-    it('should show back button when being on the search results view', async () => {
-      useRoute.mockReturnValueOnce({ name: SearchView.Results })
+  it('should display suggestions when focusing search input and no search executed', async () => {
+    useRoute.mockReturnValueOnce({ name: SearchView.Landing })
+    renderSearchBox()
 
-      renderSearchBox()
+    const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
 
-      const previousButton = screen.getByTestId('Revenir en arrière')
+    await user.type(searchInput, '')
 
-      expect(previousButton).toBeOnTheScreen()
-    })
+    expect(mockShowSuggestions).toHaveBeenNthCalledWith(1)
+  })
 
-    it('should show back button when being focus on suggestions', async () => {
-      mockIsFocusOnSuggestions = true
-      renderSearchBox()
+  it('should hide the search filter button when being on the search landing view', async () => {
+    mockSearchState = {
+      ...mockSearchState,
+      query: 'la fnac',
+    }
+    useRoute.mockReturnValueOnce({ name: SearchView.Landing })
 
-      const previousButton = screen.getByTestId('Revenir en arrière')
+    renderSearchBox()
 
-      expect(previousButton).toBeOnTheScreen()
+    await act(async () => {
+      expect(screen.queryByTestId(/Voir tous les filtres/)).not.toBeOnTheScreen()
     })
+  })
 
-    it('should show the text typed by the user', async () => {
-      renderSearchBox()
+  it('should hide the search filter button when being on the search result view and being focus on the suggestion', async () => {
+    mockIsFocusOnSuggestions = true
+    mockSearchState = {
+      ...mockSearchState,
+      query: 'la fnac',
+    }
+    useRoute.mockReturnValueOnce({ name: SearchView.Results })
 
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
-      await user.type(searchInput, 'Some text')
+    renderSearchBox()
 
-      expect(searchInput.props.value).toBe('Some text')
+    await act(async () => {
+      expect(screen.queryByTestId(/Voir tous les filtres/)).not.toBeOnTheScreen()
     })
+  })
 
-    it('should not execute a search if input is empty', async () => {
-      renderSearchBox()
+  it(`should not display Le Petit Rintintin 1 in location search widget when a venue is selected`, async () => {
+    mockSearchState = { ...initialSearchState, venue }
+    useRoute.mockReturnValueOnce({ name: SearchView.Results })
 
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+    renderSearchBox()
 
-      await user.type(searchInput, '')
+    expect(screen.queryByText(venue.label)).not.toBeOnTheScreen()
+  })
 
-      expect(mockDispatch).not.toHaveBeenCalled()
-    })
+  it('should not display locationSearchWidget when isDesktopViewport = true', async () => {
+    mockSearchState = {
+      ...initialSearchState,
+      locationFilter: { locationType: LocationMode.EVERYWHERE },
+    }
+    useRoute.mockReturnValueOnce({ name: SearchView.Results })
 
-    it('should show reset button when search input is filled', async () => {
-      useRoute.mockReturnValueOnce({ name: SearchView.Results })
+    mockPosition = DEFAULT_POSITION
+    renderSearchBox()
 
-      mockIsFocusOnSuggestions = true
-      mockQuery = 'Some text'
-      mockSearchState = {
-        ...mockSearchState,
-        query: mockQuery,
-      }
-
-      renderSearchBox()
+    expect(await screen.findByText(LocationLabel.everywhereLabel)).toBeOnTheScreen()
+  })
 
-      expect(await screen.findByLabelText('Réinitialiser la recherche')).toBeOnTheScreen()
-    })
+  describe('shouldRedirectToThematicSearch', () => {
+    it('should not update searchState when current route is not searchLanding', async () => {
+      // TODO(PC-32646): useRoute is called every time a letter is inputted +1 (sic!)
+      useRoute
+        .mockReturnValueOnce({ name: SearchView.Results })
+        .mockReturnValueOnce({ name: SearchView.Results })
+        .mockReturnValueOnce({ name: SearchView.Results })
 
-    it('should not show reset button when search input is empty', async () => {
-      useRoute.mockReturnValueOnce({ name: SearchView.Results })
+      renderSearchBox()
 
-      mockIsFocusOnSuggestions = true
+      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
 
-      renderSearchBox()
+      await user.type(searchInput, 'Livres', { submitEditing: true })
 
-      expect(screen.queryByLabelText('Réinitialiser la recherche')).not.toBeOnTheScreen()
+      expect(mockDispatch).toHaveBeenNthCalledWith(1, {
+        type: 'SET_STATE',
+        payload: expect.not.objectContaining({
+          shouldRedirect: expect.anything(),
+        }),
+      })
     })
 
-    it.each(['LIVRE', 'Livre ', 'livre', 'LIVRES', 'Livres', 'livres '])(
-      'should redirect to ThematicSearch when queryText is `%s` and SearchView is `Landing`',
-      async (queryText) => {
+    it.each`
+      queryText    | offerCategories
+      ${'LIVRE'}   | ${[SearchGroupNameEnumv2.LIVRES]}
+      ${'Livre'}   | ${[SearchGroupNameEnumv2.LIVRES]}
+      ${'livre'}   | ${[SearchGroupNameEnumv2.LIVRES]}
+      ${'LIVRES'}  | ${[SearchGroupNameEnumv2.LIVRES]}
+      ${'Livres'}  | ${[SearchGroupNameEnumv2.LIVRES]}
+      ${'livres'}  | ${[SearchGroupNameEnumv2.LIVRES]}
+      ${'CINÉMA'}  | ${[SearchGroupNameEnumv2.CINEMA]}
+      ${'Cinéma'}  | ${[SearchGroupNameEnumv2.CINEMA]}
+      ${'cinéma'}  | ${[SearchGroupNameEnumv2.CINEMA]}
+      ${'cinémas'} | ${[SearchGroupNameEnumv2.CINEMA]}
+      ${'CINEMA'}  | ${[SearchGroupNameEnumv2.CINEMA]}
+      ${'Cinema'}  | ${[SearchGroupNameEnumv2.CINEMA]}
+      ${'cinéma'}  | ${[SearchGroupNameEnumv2.CINEMA]}
+      ${'cinemas'} | ${[SearchGroupNameEnumv2.CINEMA]}
+    `(
+      'should redirect to ThematicSearch of $offerCategories when queryText is $queryText and SearchView is `Landing`',
+      async ({ queryText, offerCategories }) => {
         // TODO(PC-32646): useRoute is called every time a letter is inputted +1 (sic!)
         useRoute.mockReturnValue({ name: SearchView.Landing })
-
         renderSearchBox()
 
         const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
@@ -550,7 +491,7 @@ describe('SearchBox component', () => {
             params: {
               ...initialSearchState,
               query: queryText.trim(),
-              offerCategories: [SearchGroupNameEnumv2.LIVRES],
+              offerCategories,
               searchId,
               accessibilityFilter: {
                 isAudioDisabilityCompliant: undefined,
@@ -559,7 +500,6 @@ describe('SearchBox component', () => {
                 isVisualDisabilityCompliant: undefined,
               },
               priceRange: mockSearchState.priceRange,
-              shouldRedirect: false,
             },
             screen: 'ThematicSearch',
           },
@@ -568,7 +508,7 @@ describe('SearchBox component', () => {
       }
     )
 
-    it('should log HasSearchedCinemaQuery analytic when shouldRedirectToThematicSearch is disabled', async () => {
+    it('should log HasSearchedCinemaQuery analytic', async () => {
       // TODO(PC-32646): useRoute & useRemoteConfigContext are called every time a letter is inputted +1
       useRoute.mockReturnValueOnce({ name: SearchView.Landing })
 
@@ -580,259 +520,270 @@ describe('SearchBox component', () => {
 
       expect(analytics.logHasSearchedCinemaQuery).toHaveBeenCalledTimes(1)
     })
+  })
+
+  describe('Without autocomplete', () => {
+    beforeAll(() => {
+      setSettings({ appEnableAutocomplete: false })
+    })
+
+    it('should stay on the current view when focusing search input and being on the %s view', async () => {
+      useRoute.mockReturnValueOnce({ name: SearchView.Results })
+
+      renderSearchBox()
+
+      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+
+      await user.type(searchInput, '')
+
+      expect(mockDispatch).not.toHaveBeenCalled()
+    })
 
-    it('should reset searchState when user go goBack to Landing', async () => {
+    it('should reset input when user click on reset icon when being focus on the suggestions view', async () => {
+      useRoute.mockReturnValueOnce({ name: SearchView.Results })
+
+      mockIsFocusOnSuggestions = true
       mockSearchState = {
         ...mockSearchState,
         query: 'Some text',
       }
-      useRoute.mockReturnValueOnce({ name: SearchView.Results })
-
-      mockQuery = 'Some text'
-      renderSearchBox(true)
+      renderSearchBox()
 
-      const goBackIcon = screen.getByTestId('icon-back')
-      await user.press(goBackIcon)
+      const resetIcon = screen.getByTestId('Réinitialiser la recherche')
+      await user.press(resetIcon)
 
       expect(mockDispatch).toHaveBeenCalledWith({
         type: 'SET_STATE',
-        payload: { ...initialSearchState, offerCategories: mockSearchState.offerCategories },
+        payload: {
+          ...mockSearchState,
+          query: '',
+        },
       })
+      expect(mockClear).toHaveBeenCalledTimes(1)
     })
 
-    it('should execute a search if input is not empty', async () => {
-      useRoute
-        .mockReturnValueOnce({ name: SearchView.Results })
-        .mockReturnValueOnce({ name: SearchView.Results })
-
-      renderSearchBox()
+    it('should reset input when user click on reset icon when being on the search results view when isDesktopViewport', async () => {
+      mockSearchState = {
+        ...mockSearchState,
+        query: 'Some text',
+      }
+      useRoute.mockReturnValueOnce({ name: SearchView.Results })
 
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+      renderSearchBox(true)
 
-      await user.type(searchInput, 'j', { submitEditing: true })
+      const resetIcon = screen.getByTestId('Réinitialiser la recherche')
+      await user.press(resetIcon)
 
       expect(mockDispatch).toHaveBeenCalledWith({
         type: 'SET_STATE',
         payload: {
-          ...initialSearchState,
-          query: 'j',
-          offerCategories: mockSearchState.offerCategories,
-          priceRange: mockSearchState.priceRange,
-          searchId,
+          ...mockSearchState,
+          query: '',
         },
       })
+      expect(mockClear).toHaveBeenCalledTimes(1)
+    })
+  })
+
+  describe('With autocomplete', () => {
+    beforeAll(() => {
+      setSettings({ appEnableAutocomplete: true })
     })
 
-    it('should display suggestions when focusing search input and no search executed', async () => {
+    afterAll(() => {
+      setSettings()
+    })
+
+    it('should unfocus from suggestion when being focus on the suggestions and press back button', async () => {
+      mockIsFocusOnSuggestions = true
       useRoute.mockReturnValueOnce({ name: SearchView.Landing })
-      renderSearchBox()
 
-      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
+      renderSearchBox()
+      const previousButton = screen.getByTestId('Revenir en arrière')
 
-      await user.type(searchInput, '')
+      await user.press(previousButton)
 
-      expect(mockShowSuggestions).toHaveBeenNthCalledWith(1)
+      expect(mockHideSuggestions).toHaveBeenNthCalledWith(1)
     })
 
-    it('should hide the search filter button when being on the search landing view', async () => {
-      mockSearchState = {
-        ...mockSearchState,
-        query: 'la fnac',
-      }
+    it('should hide suggestions when being focus on suggestions and press back button on landing view', async () => {
+      mockIsFocusOnSuggestions = true
       useRoute.mockReturnValueOnce({ name: SearchView.Landing })
 
       renderSearchBox()
 
-      await act(async () => {
-        expect(screen.queryByTestId(/Voir tous les filtres/)).not.toBeOnTheScreen()
-      })
+      const previousButton = screen.getByTestId('Revenir en arrière')
+
+      await user.press(previousButton)
+
+      expect(mockHideSuggestions).toHaveBeenNthCalledWith(1)
     })
 
-    it('should hide the search filter button when being on the search result view and being focus on the suggestion', async () => {
+    it('should reset input when user click on reset icon when being focus on suggestions', async () => {
       mockIsFocusOnSuggestions = true
       mockSearchState = {
         ...mockSearchState,
-        query: 'la fnac',
+        query: 'Some text',
       }
-      useRoute.mockReturnValueOnce({ name: SearchView.Results })
-
+      mockQuery = 'Some text'
       renderSearchBox()
 
-      await act(async () => {
-        expect(screen.queryByTestId(/Voir tous les filtres/)).not.toBeOnTheScreen()
-      })
-    })
+      const resetIcon = await screen.findByTestId('Réinitialiser la recherche')
+      await user.press(resetIcon)
 
-    it(`should not display Le Petit Rintintin 1 in location search widget when a venue is selected`, async () => {
-      mockSearchState = { ...initialSearchState, venue }
-      useRoute.mockReturnValueOnce({ name: SearchView.Results })
+      expect(screen.queryByText('Some text')).not.toBeOnTheScreen()
 
-      renderSearchBox()
-
-      expect(screen.queryByText(venue.label)).not.toBeOnTheScreen()
+      expect(mockClear).toHaveBeenCalledTimes(1)
     })
+  })
 
-    it('should not display locationSearchWidget when isDesktopViewport = true', async () => {
-      mockSearchState = {
-        ...initialSearchState,
-        locationFilter: { locationType: LocationMode.EVERYWHERE },
-      }
+  describe('Venue previous route on search results', () => {
+    beforeEach(() => {
+      jest.mock('libs/firebase/analytics/analytics')
+      jest.spyOn(navigationRef, 'getState').mockReturnValue({
+        key: 'Navigator',
+        index: 1,
+        routeNames: ['TabNavigator'],
+        routes: mockRoutesWithVenue,
+        type: 'tab',
+        stale: false,
+      })
       useRoute.mockReturnValueOnce({ name: SearchView.Results })
+    })
 
-      mockPosition = DEFAULT_POSITION
+    it('should unselect the venue and set the view to Landing when current route is search and previous route is Venue when the user press the back button', async () => {
       renderSearchBox()
 
-      expect(await screen.findByText(LocationLabel.everywhereLabel)).toBeOnTheScreen()
-    })
+      const previousButton = screen.getByTestId('Revenir en arrière')
 
-    jest.mock('libs/firebase/analytics/analytics')
-
-    describe('Venue previous route on search results', () => {
-      beforeEach(() => {
-        jest.spyOn(navigationRef, 'getState').mockReturnValue({
-          key: 'Navigator',
-          index: 1,
-          routeNames: ['TabNavigator'],
-          routes: mockRoutesWithVenue,
-          type: 'tab',
-          stale: false,
-        })
-        useRoute.mockReturnValueOnce({ name: SearchView.Results })
+      await user.press(previousButton)
+
+      expect(mockDispatch).toHaveBeenNthCalledWith(1, {
+        type: 'SET_STATE',
+        payload: { ...initialSearchState, offerCategories: mockSearchState.offerCategories },
       })
+    })
 
-      it('should unselect the venue and set the view to Landing when current route is search and previous route is Venue when the user press the back button', async () => {
-        renderSearchBox()
+    it('should execute go back when current route is search and previous route is Venue', async () => {
+      renderSearchBox()
+
+      const previousButton = screen.getByTestId('Revenir en arrière')
 
-        const previousButton = screen.getByTestId('Revenir en arrière')
+      await user.press(previousButton)
 
-        await user.press(previousButton)
+      expect(mockGoBack).toHaveBeenCalledTimes(1)
+    })
 
-        expect(mockDispatch).toHaveBeenNthCalledWith(1, {
-          type: 'SET_STATE',
-          payload: { ...initialSearchState, offerCategories: mockSearchState.offerCategories },
+    it('should update searchState without offerNativeCategories set to undefined when a query is made from another page than ThematicSearch', async () => {
+      // TODO(PC-32646): useRoute is called every time a letter is inputted +1
+      useRoute
+        .mockReturnValueOnce({
+          name: SearchView.Results,
         })
-      })
+        .mockReturnValueOnce({ name: SearchView.Results })
+      const BOOK_OFFER_CATEGORIES = [SearchGroupNameEnumv2.LIVRES]
+      const BOOK_OFFER_NATIVE_CATEGORIES = [BooksNativeCategoriesEnum.BD_ET_COMICS]
 
-      it('should execute go back when current route is search and previous route is Venue', async () => {
-        renderSearchBox()
+      mockSearchState = {
+        ...mockSearchState,
+        offerCategories: BOOK_OFFER_CATEGORIES,
+        offerNativeCategories: BOOK_OFFER_NATIVE_CATEGORIES,
+      }
 
-        const previousButton = screen.getByTestId('Revenir en arrière')
+      renderSearchBox()
 
-        await user.press(previousButton)
+      const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
 
-        expect(mockGoBack).toHaveBeenCalledTimes(1)
-      })
+      await user.type(searchInput, 'HP', { submitEditing: true })
 
-      it('should update searchState without offerNativeCategories set to undefined when a query is made from another page than ThematicSearch', async () => {
-        // TODO(PC-32646): useRoute is called every time a letter is inputted +1
-        useRoute
-          .mockReturnValueOnce({
-            name: SearchView.Results,
-          })
-          .mockReturnValueOnce({ name: SearchView.Results })
-        const BOOK_OFFER_CATEGORIES = [SearchGroupNameEnumv2.LIVRES]
-        const BOOK_OFFER_NATIVE_CATEGORIES = [BooksNativeCategoriesEnum.BD_ET_COMICS]
-
-        mockSearchState = {
-          ...mockSearchState,
+      expect(mockDispatch).toHaveBeenNthCalledWith(1, {
+        type: 'SET_STATE',
+        payload: {
+          ...initialSearchState,
+          query: 'HP',
           offerCategories: BOOK_OFFER_CATEGORIES,
           offerNativeCategories: BOOK_OFFER_NATIVE_CATEGORIES,
-        }
-
-        renderSearchBox()
-
-        const searchInput = screen.getByPlaceholderText('Offre, artiste, lieu culturel...')
-
-        await user.type(searchInput, 'HP', { submitEditing: true })
-
-        expect(mockDispatch).toHaveBeenNthCalledWith(1, {
-          type: 'SET_STATE',
-          payload: {
-            ...initialSearchState,
-            query: 'HP',
-            offerCategories: BOOK_OFFER_CATEGORIES,
-            offerNativeCategories: BOOK_OFFER_NATIVE_CATEGORIES,
-            priceRange: mockSearchState.priceRange,
-            searchId,
-          },
-        })
+          priceRange: mockSearchState.priceRange,
+          searchId,
+        },
       })
     })
+  })
 
-    describe('ThematicSearch previous route on search results', () => {
-      beforeEach(() => {
-        jest.spyOn(navigationRef, 'getState').mockReturnValue({
-          key: 'Navigator',
-          index: 1,
-          routeNames: ['TabNavigator'],
-          routes: mockRoutesWithThematicSearch,
-          type: 'tab',
-          stale: false,
-        })
-        useRoute.mockReturnValueOnce({ name: SearchView.Thematic })
+  describe('ThematicSearch previous route on search results', () => {
+    beforeEach(() => {
+      jest.mock('libs/firebase/analytics/analytics')
+      jest.spyOn(navigationRef, 'getState').mockReturnValue({
+        key: 'Navigator',
+        index: 1,
+        routeNames: ['TabNavigator'],
+        routes: mockRoutesWithThematicSearch,
+        type: 'tab',
+        stale: false,
       })
+      useRoute.mockReturnValueOnce({ name: SearchView.Thematic })
+    })
 
-      it('should execute go back when current route is search and previous route is ThematicSearch', async () => {
-        useRoute.mockReturnValueOnce({
-          name: SearchView.Results,
-        })
+    it('should execute go back when current route is search and previous route is ThematicSearch', async () => {
+      useRoute.mockReturnValueOnce({
+        name: SearchView.Results,
+      })
 
-        renderSearchBox()
+      renderSearchBox()
 
-        const previousButton = screen.getByTestId('Revenir en arrière')
+      const previousButton = screen.getByTestId('Revenir en arrière')
 
-        await user.press(previousButton)
+      await user.press(previousButton)
 
-        expect(mockGoBack).toHaveBeenCalledTimes(1)
-      })
+      expect(mockGoBack).toHaveBeenCalledTimes(1)
+    })
 
-      it('should clear offerNativeCategories and gtls when a previous search was made on searchResults and now a query is made on ThematicSearch', async () => {
-        // TODO(PC-32646): useRoute is called every time a letter is inputted +1
-        useRoute
-          .mockReturnValueOnce({
-            name: SearchView.Thematic,
-          })
-          .mockReturnValueOnce({ name: SearchView.Thematic })
+    it('should clear offerNativeCategories and gtls when a previous search was made on searchResults and now a query is made on ThematicSearch', async () => {
+      // TODO(PC-32646): useRoute is called every time a letter is inputted +1
+      useRoute
+        .mockReturnValueOnce({
+          name: SearchView.Thematic,
+        })
+        .mockReturnValueOnce({ name: SearchView.Thematic })
 
-        const BOOK_OFFER_CATEGORIES = [SearchGroupNameEnumv2.LIVRES]
-        const BOOK_SEARCH_BOX_PLACEHOLDER = 'Livres'
+      const BOOK_OFFER_CATEGORIES = [SearchGroupNameEnumv2.LIVRES]
+      const BOOK_SEARCH_BOX_PLACEHOLDER = 'Livres'
 
-        mockSearchState = {
-          ...mockSearchState,
-          offerCategories: BOOK_OFFER_CATEGORIES,
-          offerNativeCategories: [BooksNativeCategoriesEnum.MANGAS],
-          offerGenreTypes: undefined,
-          gtls: [
-            {
-              code: '03040300',
-              label: 'Kodomo',
-              level: 3,
-            },
-            {
-              code: '03040400',
-              label: 'Shôjo',
-              level: 3,
-            },
-          ],
-        }
+      mockSearchState = {
+        ...mockSearchState,
+        offerCategories: BOOK_OFFER_CATEGORIES,
+        offerNativeCategories: [BooksNativeCategoriesEnum.MANGAS],
+        offerGenreTypes: undefined,
+        gtls: [
+          {
+            code: '03040300',
+            label: 'Kodomo',
+            level: 3,
+          },
+          {
+            code: '03040400',
+            label: 'Shôjo',
+            level: 3,
+          },
+        ],
+      }
 
-        renderSearchBox(false, BOOK_OFFER_CATEGORIES, BOOK_SEARCH_BOX_PLACEHOLDER)
+      renderSearchBox(false, BOOK_OFFER_CATEGORIES, BOOK_SEARCH_BOX_PLACEHOLDER)
 
-        const searchInput = screen.getByPlaceholderText(BOOK_SEARCH_BOX_PLACEHOLDER)
+      const searchInput = screen.getByPlaceholderText(BOOK_SEARCH_BOX_PLACEHOLDER)
 
-        await user.type(searchInput, 'HP', { submitEditing: true })
+      await user.type(searchInput, 'HP', { submitEditing: true })
 
-        expect(mockDispatch).toHaveBeenNthCalledWith(1, {
-          type: 'SET_STATE',
-          payload: {
-            ...initialSearchState,
-            query: 'HP',
-            offerCategories: BOOK_OFFER_CATEGORIES,
-            gtls: [],
-            priceRange: mockSearchState.priceRange,
-            searchId,
-          },
-        })
+      expect(mockDispatch).toHaveBeenNthCalledWith(1, {
+        type: 'SET_STATE',
+        payload: {
+          ...initialSearchState,
+          query: 'HP',
+          offerCategories: BOOK_OFFER_CATEGORIES,
+          gtls: [],
+          priceRange: mockSearchState.priceRange,
+          searchId,
+        },
       })
     })
   })
diff --git a/src/features/search/components/SearchBox/SearchBox.tsx b/src/features/search/components/SearchBox/SearchBox.tsx
index f6c3fd871810..bc67fbcec778 100644
--- a/src/features/search/components/SearchBox/SearchBox.tsx
+++ b/src/features/search/components/SearchBox/SearchBox.tsx
@@ -24,7 +24,6 @@ import { useSearch } from 'features/search/context/SearchWrapper'
 import { useNavigateToSearch } from 'features/search/helpers/useNavigateToSearch/useNavigateToSearch'
 import { CreateHistoryItem, SearchView, SearchState } from 'features/search/types'
 import { analytics } from 'libs/analytics/provider'
-import { useRemoteConfigQuery } from 'libs/firebase/remoteConfig/queries/useRemoteConfigQuery'
 import { BackButton } from 'ui/components/headers/BackButton'
 import { HiddenAccessibleText } from 'ui/components/HiddenAccessibleText'
 import { SNACK_BAR_TIME_OUT, useSnackBarContext } from 'ui/components/snackBar/SnackBarContext'
@@ -45,7 +44,7 @@ type Props = UseSearchBoxProps & {
 const accessibilityDescribedBy = uuidv4()
 
 const BOOK_KEYWORD_PATTERN = /\bLIVRES?\b$/i
-const CINEMA_KEYWORD_PATTERN = /\bCINEMAS?\b$/i
+const CINEMA_KEYWORD_PATTERN = /\bCIN[ÉE]MA?S?\b$/i
 
 export const SearchBox: React.FunctionComponent<Props> = ({
   searchInputID,
@@ -66,7 +65,6 @@ export const SearchBox: React.FunctionComponent<Props> = ({
   const route = useRoute()
   const { navigateToSearch: navigateToSearchResults } = useNavigateToSearch('SearchResults')
   const { navigateToSearch: navigateToThematicSearch } = useNavigateToSearch('ThematicSearch')
-  const { shouldRedirectToThematicSearch } = useRemoteConfigQuery()
   const currentView = route.name
 
   // Autocompletion inspired by https://github.com/algolia/doc-code-samples/tree/master/react-instantsearch-hooks-native/getting-started
@@ -92,15 +90,13 @@ export const SearchBox: React.FunctionComponent<Props> = ({
     (
       partialSearchState: Partial<SearchState>,
       options: { reset?: boolean } = {},
-      hasSearchedForBookKeyword?: boolean
+      hasSearchedForBookKeyword?: boolean,
+      hasSearchedForCinemaKeyword?: boolean
     ) => {
       const newSearchState = {
         ...searchState,
         ...(options.reset ? initialSearchState : {}),
         ...partialSearchState,
-        ...(currentView === SearchView.Landing
-          ? { shouldRedirect: shouldRedirectToThematicSearch }
-          : undefined),
       }
 
       dispatch({
@@ -108,7 +104,7 @@ export const SearchBox: React.FunctionComponent<Props> = ({
         payload: newSearchState,
       })
 
-      if (hasSearchedForBookKeyword) {
+      if (hasSearchedForBookKeyword || hasSearchedForCinemaKeyword) {
         return navigateToThematicSearch(newSearchState, defaultDisabilitiesProperties)
       }
 
@@ -116,14 +112,7 @@ export const SearchBox: React.FunctionComponent<Props> = ({
         navigateToSearchResults(newSearchState, defaultDisabilitiesProperties)
       }
     },
-    [
-      dispatch,
-      navigateToThematicSearch,
-      navigateToSearchResults,
-      searchState,
-      currentView,
-      shouldRedirectToThematicSearch,
-    ]
+    [dispatch, navigateToThematicSearch, navigateToSearchResults, searchState]
   )
 
   const hasEditableSearchInput =
@@ -242,15 +231,18 @@ export const SearchBox: React.FunctionComponent<Props> = ({
       }
 
       let hasSearchedForBookKeyword = false
-
+      let hasSearchedForCinemaKeyword = false
       if (currentView === SearchView.Landing) {
         hasSearchedForBookKeyword = BOOK_KEYWORD_PATTERN.test(queryText.trim())
+        hasSearchedForCinemaKeyword = CINEMA_KEYWORD_PATTERN.test(queryText.trim())
 
-        if (hasSearchedForBookKeyword) {
+        if (hasSearchedForBookKeyword || hasSearchedForCinemaKeyword) {
           partialSearchState = {
             ...partialSearchState,
             query: queryText.trim(),
-            offerCategories: [SearchGroupNameEnumv2.LIVRES],
+            offerCategories: hasSearchedForBookKeyword
+              ? [SearchGroupNameEnumv2.LIVRES]
+              : [SearchGroupNameEnumv2.CINEMA],
           }
         }
 
@@ -266,7 +258,7 @@ export const SearchBox: React.FunctionComponent<Props> = ({
         }
       }
 
-      pushWithSearch(partialSearchState, {}, hasSearchedForBookKeyword)
+      pushWithSearch(partialSearchState, {}, hasSearchedForBookKeyword, hasSearchedForCinemaKeyword)
       hideSuggestions()
     },
     [
diff --git a/src/features/search/types.ts b/src/features/search/types.ts
index ba11f96b48fc..9117b2b0d21a 100644
--- a/src/features/search/types.ts
+++ b/src/features/search/types.ts
@@ -65,7 +65,6 @@ export interface SearchState {
   isFromHistory?: boolean
   venue?: Venue
   gtls?: GTL[]
-  shouldRedirect?: boolean
 }
 
 export type UserData = {
diff --git a/src/libs/algolia/doAlgoliaRedirect.native.test.ts b/src/libs/algolia/doAlgoliaRedirect.native.test.ts
deleted file mode 100644
index d5cc9bbd1b7b..000000000000
--- a/src/libs/algolia/doAlgoliaRedirect.native.test.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-import { navigate } from '__mocks__/@react-navigation/native'
-import { SearchGroupNameEnumv2 } from 'api/gen'
-import { defaultDisabilitiesProperties } from 'features/accessibility/context/AccessibilityFiltersWrapper'
-import { initialSearchState } from 'features/search/context/reducer'
-import { SearchState } from 'features/search/types'
-import { doAlgoliaRedirect } from 'libs/algolia/doAlgoliaRedirect'
-
-const mockSearchstate = { ...initialSearchState, shouldRedirect: true }
-const mockDispatch = jest.fn()
-const mockNavigateToThematicSearch = navigate
-
-describe('doAlgoliaRedirect', () => {
-  it('should redirect to thematicSearch', async () => {
-    executeDoAlgoliaRedirect(mockSearchstate)
-
-    expect(mockDispatch).toHaveBeenNthCalledWith(1, {
-      type: 'SET_STATE',
-      payload: expect.objectContaining({
-        shouldRedirect: false,
-      }),
-    })
-
-    expect(mockNavigateToThematicSearch).toHaveBeenCalledWith(
-      expect.objectContaining({
-        shouldRedirect: false,
-        offerCategories: [SearchGroupNameEnumv2.CINEMA],
-      }),
-      defaultDisabilitiesProperties
-    )
-
-    expect(mockDispatch).toHaveBeenNthCalledWith(1, {
-      type: 'SET_STATE',
-      payload: expect.objectContaining({
-        query: '',
-      }),
-    })
-  })
-
-  it('should reset query after redirection to thematicSearch', async () => {
-    const mockQuery = 'cinema'
-    executeDoAlgoliaRedirect({ ...mockSearchstate, query: mockQuery })
-
-    expect(mockDispatch).toHaveBeenNthCalledWith(1, {
-      type: 'SET_STATE',
-      payload: expect.objectContaining({
-        shouldRedirect: false,
-        query: mockQuery,
-      }),
-    })
-
-    expect(mockNavigateToThematicSearch).toHaveBeenCalledWith(
-      expect.objectContaining({
-        shouldRedirect: false,
-        offerCategories: [SearchGroupNameEnumv2.CINEMA],
-        query: mockQuery,
-      }),
-      defaultDisabilitiesProperties
-    )
-
-    expect(mockDispatch).toHaveBeenCalledWith({
-      type: 'SET_STATE',
-      payload: expect.objectContaining({
-        query: '',
-      }),
-    })
-  })
-})
-
-const executeDoAlgoliaRedirect = (searchState: SearchState) => {
-  const mockUrl =
-    'http://passculture.app/recherche/resultats?offerCategories=%5B%22CINEMA%22%5D&query=%22%22'
-
-  doAlgoliaRedirect(
-    new URL(mockUrl),
-    searchState,
-    defaultDisabilitiesProperties,
-    mockDispatch,
-    mockNavigateToThematicSearch
-  )
-}
diff --git a/src/libs/algolia/doAlgoliaRedirect.ts b/src/libs/algolia/doAlgoliaRedirect.ts
deleted file mode 100644
index 588cd1c18ded..000000000000
--- a/src/libs/algolia/doAlgoliaRedirect.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { Dispatch } from 'react'
-
-import { DisabilitiesProperties } from 'features/accessibility/types'
-import { Action } from 'features/search/context/reducer'
-import { SearchState } from 'features/search/types'
-
-export const doAlgoliaRedirect = (
-  url: URL,
-  searchState: SearchState,
-  disabilities: DisabilitiesProperties,
-  dispatch: Dispatch<Action>,
-  navigateToThematicSearch: (
-    newSearchState: SearchState,
-    newAccessibilityFilter: DisabilitiesProperties
-  ) => void
-) => {
-  const offerCategories = url.searchParams.get('offerCategories') || ''
-  const newSearchState = {
-    ...searchState,
-    offerCategories: JSON.parse(offerCategories),
-    shouldRedirect: false,
-  }
-
-  dispatch({
-    type: 'SET_STATE',
-    payload: newSearchState,
-  })
-
-  navigateToThematicSearch(newSearchState, disabilities)
-
-  dispatch({
-    type: 'SET_STATE',
-    payload: { ...newSearchState, query: '' },
-  })
-}
diff --git a/src/libs/firebase/remoteConfig/helpers/getRemoteConfigFromConfigValues.ts b/src/libs/firebase/remoteConfig/helpers/getRemoteConfigFromConfigValues.ts
index 4bc69b898875..16cac077efdd 100644
--- a/src/libs/firebase/remoteConfig/helpers/getRemoteConfigFromConfigValues.ts
+++ b/src/libs/firebase/remoteConfig/helpers/getRemoteConfigFromConfigValues.ts
@@ -44,7 +44,4 @@ export const getRemoteConfigFromConfigValues = (
     parameters.shareAppModalVersion
   ).asString() as CustomRemoteConfig['shareAppModalVersion'],
   showAccessScreeningButton: getConfigValue(parameters.showAccessScreeningButton).asBoolean(),
-  shouldRedirectToThematicSearch: getConfigValue(
-    parameters.shouldRedirectToThematicSearch
-  ).asBoolean(),
 })
diff --git a/src/libs/firebase/remoteConfig/remoteConfig.constants.ts b/src/libs/firebase/remoteConfig/remoteConfig.constants.ts
index 6f953e341d54..ddc1874b5e1b 100644
--- a/src/libs/firebase/remoteConfig/remoteConfig.constants.ts
+++ b/src/libs/firebase/remoteConfig/remoteConfig.constants.ts
@@ -36,5 +36,4 @@ export const DEFAULT_REMOTE_CONFIG: CustomRemoteConfig = {
   },
   shareAppModalVersion: 'default',
   showAccessScreeningButton: false,
-  shouldRedirectToThematicSearch: false,
 }
diff --git a/src/libs/firebase/remoteConfig/remoteConfig.types.ts b/src/libs/firebase/remoteConfig/remoteConfig.types.ts
index f2e9c8f4c6f5..aa8470938c7b 100644
--- a/src/libs/firebase/remoteConfig/remoteConfig.types.ts
+++ b/src/libs/firebase/remoteConfig/remoteConfig.types.ts
@@ -24,7 +24,6 @@ export type CustomRemoteConfig = {
   subscriptionHomeEntryIds: Record<SubscriptionTheme, string>
   shareAppModalVersion: 'default' | 'A' | 'B'
   showAccessScreeningButton: boolean
-  shouldRedirectToThematicSearch: boolean
 }
 
 /* The purpose of GenericRemoteConfig is only to resolve type conflicts.


Reviews:
user: login: imouandjolobe-pass
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T14:22:53Z
user: login: imouandjolobe-pass
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T16:06:57Z

Review comments:
diff_hunk: @@ -92,38 +90,30 @@ export const SearchBox: React.FunctionComponent<Props> = ({
     (
       partialSearchState: Partial<SearchState>,
       options: { reset?: boolean } = {},
-      hasSearchedForBookKeyword?: boolean
+      hasSearchedForBookKeyword?: boolean,
+      hasSearchedForCinemaKeyword?: boolean
     ) => {
       const newSearchState = {
         ...searchState,
         ...(options.reset ? initialSearchState : {}),
         ...partialSearchState,
-        ...(currentView === SearchView.Landing
-          ? { shouldRedirect: shouldRedirectToThematicSearch }
-          : undefined),
+        ...(currentView === SearchView.Landing ? { shouldRedirect: true } : undefined),
path: src/features/search/components/SearchBox/SearchBox.tsx
user: login: imouandjolobe-pass
body: De mémoire, la propriété shouldRedirect n'avait de sens que si l'on se basait sur la règle algolia. On doit donc pouvoir l'enlever du searchState ?
created_at: 2025-04-04T14:06:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -92,38 +90,30 @@ export const SearchBox: React.FunctionComponent<Props> = ({
     (
       partialSearchState: Partial<SearchState>,
       options: { reset?: boolean } = {},
-      hasSearchedForBookKeyword?: boolean
+      hasSearchedForBookKeyword?: boolean,
+      hasSearchedForCinemaKeyword?: boolean
     ) => {
       const newSearchState = {
         ...searchState,
         ...(options.reset ? initialSearchState : {}),
         ...partialSearchState,
-        ...(currentView === SearchView.Landing
-          ? { shouldRedirect: shouldRedirectToThematicSearch }
-          : undefined),
+        ...(currentView === SearchView.Landing ? { shouldRedirect: true } : undefined),
path: src/features/search/components/SearchBox/SearchBox.tsx
user: login: imouandjolobe-pass
body: D'ailleurs, dans le ticket, on parle de supprimer la règle algolia associée, est ce qu'il y a une raison pour garder le code associé à la rule algolia ? Je parle ici du code présent dans `useSearchResults` et de la méthode `doAlgoliaRedirect`
created_at: 2025-04-04T14:12:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -45,7 +44,7 @@ type Props = UseSearchBoxProps & {
 const accessibilityDescribedBy = uuidv4()
 
 const BOOK_KEYWORD_PATTERN = /\bLIVRES?\b$/i
-const CINEMA_KEYWORD_PATTERN = /\bCINEMAS?\b$/i
+const CINEMA_KEYWORD_PATTERN = /\bCIN[ÉE]MA?S?\b/i
path: src/features/search/components/SearchBox/SearchBox.tsx
user: login: imouandjolobe-pass
body: Il manque le `$` qui indique la fin de la regex, donc si je tape "cinema ploup plip plop", je suis redirigée vers la thématique search cinéma alors que pour "livres", on est vraiment limité au mot
created_at: 2025-04-04T14:17:42Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-04-04T15:52:39Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=pass-culture_pass-culture-app-native-proxy&pullRequest=7960) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=pass-culture_pass-culture-app-native-proxy&pullRequest=7960&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=pass-culture_pass-culture-app-native-proxy&pullRequest=7960&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=pass-culture_pass-culture-app-native-proxy&pullRequest=7960&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=pass-culture_pass-culture-app-native-proxy&pullRequest=7960&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=pass-culture_pass-culture-app-native-proxy&pullRequest=7960&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=pass-culture_pass-culture-app-native-proxy&pullRequest=7960)


author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-04-04T15:58:48Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=pass-culture_pass-culture-app-native&pullRequest=7960) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=pass-culture_pass-culture-app-native&pullRequest=7960&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=pass-culture_pass-culture-app-native&pullRequest=7960&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=pass-culture_pass-culture-app-native&pullRequest=7960&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [95.2% Coverage on New Code](https://sonarcloud.io/component_measures?id=pass-culture_pass-culture-app-native&pullRequest=7960&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=pass-culture_pass-culture-app-native&pullRequest=7960&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=pass-culture_pass-culture-app-native&pullRequest=7960)


author_association: NONE