diff --git a/core/navigation/components/header/SearchButton.tsx b/core/navigation/components/header/SearchButton.tsx
index 6458e3caa966539188e740c4b69251c964f396a2..6299e9c0d320566fba7af35ecda2de559cc2be6c 100644
--- a/core/navigation/components/header/SearchButton.tsx
+++ b/core/navigation/components/header/SearchButton.tsx
@@ -22,6 +22,7 @@ export const SearchButton = () => {
         navigate('/search')
       }}
       size="lg"
+      testID="btn-to-search"
     />
   )
 }
diff --git a/core/screens/search/components/SearchContent.tsx b/core/screens/search/components/SearchContent.tsx
index db3db75e1067a5399dccca98eae9504b612aa2fc..4f1321aa99689f79e688be6f0236fdc5a74a5be7 100644
--- a/core/screens/search/components/SearchContent.tsx
+++ b/core/screens/search/components/SearchContent.tsx
@@ -114,7 +114,7 @@ const SearchContent = () => {
         </>
       }
     >
-      <View style={[mixins.container, styles.inner]}>
+      <View style={[mixins.container, styles.inner]} testID="search-content">
         {/* Results */}
         <SearchResultsList
           query={query}
diff --git a/core/screens/search/typesense/SearchFacetsChips.tsx b/core/screens/search/typesense/SearchFacetsChips.tsx
index 9752920033edb359c87ffa1c1954ffd38152ae8e..386e697a3eec1c3e602611bae25d34fefeb978f4 100644
--- a/core/screens/search/typesense/SearchFacetsChips.tsx
+++ b/core/screens/search/typesense/SearchFacetsChips.tsx
@@ -61,7 +61,14 @@ export const SearchFacetsChips = ({ initialFacet, onFacetChange }: SearchFacetsC
           {orderedItems.map(({ item }) => {
             const label = t(`search.typesense.facets.${item.label}`)
             return (
-              <SelectableChip id={item.value} key={item.value} color="white" size="md" aria-label={label}>
+              <SelectableChip
+                id={item.value}
+                key={item.value}
+                color="white"
+                size="md"
+                aria-label={label}
+                testID={`facet-${item.value}`}
+              >
                 {label}
               </SelectableChip>
             )
diff --git a/core/screens/search/typesense/SearchHit.tsx b/core/screens/search/typesense/SearchHit.tsx
index f3605b2fba599214dacf13a737446fb9a9fcedd8..75bd8e5dcf0b38400cac973a46ce816a28217a32 100644
--- a/core/screens/search/typesense/SearchHit.tsx
+++ b/core/screens/search/typesense/SearchHit.tsx
@@ -36,13 +36,12 @@ export const SearchHit = Trackable<SearchHitProps>(({ hit, onPress }: SearchHitP
 
   return (
     <SearchHitLink hit={hit} label={title} onPress={onPress}>
-      <View style={styles.hitItem}>
+      <View style={styles.hitItem} testID={`search-hit-${hit.type}`}>
         <Avatar
           initials={getInitials(title)}
           label={title}
           size={'md'}
           shape={hit.type === 'profile' ? 'circle' : 'square'}
-          role={'img'}
           imgSrc={hit.image_url}
         />
         <View style={styles.hitItemContent}>
diff --git a/core/screens/search/typesense/SearchTextInput.tsx b/core/screens/search/typesense/SearchTextInput.tsx
index d26c9dd6b4c41cd39f499f714d03526345e1fe07..587a4b9ee840fb7c6a80f528a431e53f6ec2acfd 100644
--- a/core/screens/search/typesense/SearchTextInput.tsx
+++ b/core/screens/search/typesense/SearchTextInput.tsx
@@ -59,13 +59,18 @@ export function SearchTextInput({ initialQuery, onQueryChange, props }: SearchBo
       }}
       trailingComponent={
         inputValue ? (
-          <Pressable onPress={() => setQuery('')} accessibilityLabel={t('search.typesense.input.clear')}>
+          <Pressable
+            onPress={() => setQuery('')}
+            accessibilityLabel={t('search.typesense.input.clear')}
+            testID="search-input-clear"
+          >
             <HoliIcon icon={CloseCircleFilled} size={22} />
           </Pressable>
         ) : (
           <HoliIcon icon={Search} size={22} />
         )
       }
+      testID="search"
     />
   )
 }
diff --git a/e2e/mobile/tests/journey/search.test.ts b/e2e/mobile/tests/journey/search.test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..73eaa87abd8fd2d76feac862c9f0da9e4a5b40c9
--- /dev/null
+++ b/e2e/mobile/tests/journey/search.test.ts
@@ -0,0 +1,69 @@
+import { continueAsGuest } from '@holi/e2e-mobile/helpers/auth'
+import { getDeviceScreenSize } from '@holi/e2e-mobile/helpers/gestures'
+import {
+  checkIfElementWithTestIdExists,
+  fillFieldByTestId,
+  pressEnter,
+  tapOnElementWithTestId,
+  waitForElementWithTestId,
+} from '@holi/e2e-mobile/helpers/selectors'
+
+describe('@Search', () => {
+  afterEach(async () => {
+    // Speeds up local execution
+    if (target === 'local') {
+      // navigate back to home screen
+      await tapOnElementWithTestId('nav-button-back')
+    }
+  })
+
+  it('should show and filter results', async () => {
+    await continueAsGuest()
+
+    // Navigate to search
+    try {
+      await tapOnElementWithTestId('btn-to-search')
+      // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    } catch (e) {
+      // On android in browserstack the above does not work
+      // Instead we touch via coordinates starting from the status bar
+      const size = await getDeviceScreenSize()
+      // @ts-ignore
+      const { pixelRatio, statBarHeight } = Appium.capabilities
+      const gap = 24 // Top + right gap to the search button
+
+      await Appium.touchAction({ action: 'tap', x: size.width - gap * pixelRatio, y: statBarHeight + gap * pixelRatio })
+    }
+
+    const oldSearch = await checkIfElementWithTestIdExists('search-content')
+    if (oldSearch) {
+      // Abort as test only handles new search variant
+      return
+    }
+
+    // Volunteering is selected by default
+    await waitForElementWithTestId('search-hit-volunteering')
+
+    // Test search by query
+    await fillFieldByTestId('search-input', 'Test')
+    await waitForElementWithTestId('search-hit-volunteering')
+
+    // Clear query to prepare for facet filtering
+    await tapOnElementWithTestId('search-input-clear')
+    await waitForElementWithTestId('search-hit-volunteering')
+
+    // Close keyboard by submitting (empty) input
+    await pressEnter('search-input')
+    await waitForElementWithTestId('search-hit-volunteering')
+
+    // Test facet filters
+    await tapOnElementWithTestId('facet-profile')
+    await waitForElementWithTestId('search-hit-profile')
+
+    await tapOnElementWithTestId('facet-space')
+    await waitForElementWithTestId('search-hit-space')
+
+    await tapOnElementWithTestId('facet-volunteering')
+    await waitForElementWithTestId('search-hit-volunteering')
+  })
+})
diff --git a/e2e/web/tests/search.spec.ts b/e2e/web/tests/search.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..412ae79c6dde6f06be4541b65794b8d9baf040ae
--- /dev/null
+++ b/e2e/web/tests/search.spec.ts
@@ -0,0 +1,42 @@
+import { byTestId, checkAccessibility, clickElementByTestId, denyConsent, locateElementByTestId } from './helpers'
+import { test } from './testmaster'
+
+test.describe('@Search', () => {
+  test('user journey', async ({ page }) => {
+    await page.goto('/search')
+
+    await denyConsent(page)
+
+    const oldSearch = await locateElementByTestId(page, 'search-content')
+    const oldSearchVisible = await oldSearch.isVisible()
+    if (oldSearchVisible) {
+      // Abort as test only handles new search variant
+      return
+    }
+
+    // Volunteering is selected by default
+    await page.waitForSelector(byTestId('search-hit-volunteering'))
+
+    // Test search by query
+    const emailInput = await locateElementByTestId(page, 'search-input')
+    await emailInput.fill('Test')
+    await page.waitForSelector(byTestId('search-hit-volunteering'))
+
+    // Clear query to prepare for facet filtering
+    await clickElementByTestId(page, 'search-input-clear')
+    await page.waitForSelector(byTestId('search-hit-volunteering'))
+
+    // Check accessibility
+    await checkAccessibility(page)
+
+    // Test facet filters
+    await clickElementByTestId(page, 'facet-profile')
+    await page.waitForSelector(byTestId('search-hit-profile'))
+
+    await clickElementByTestId(page, 'facet-space')
+    await page.waitForSelector(byTestId('search-hit-space'))
+
+    await clickElementByTestId(page, 'facet-volunteering')
+    await page.waitForSelector(byTestId('search-hit-volunteering'))
+  })
+})
diff --git a/holi-bricks/components/chips/ChipAction.tsx b/holi-bricks/components/chips/ChipAction.tsx
index 0d0501969bfe38e3926c08772aa006d1e1ab93e1..c83fb125d474c1bbf4632f0dbedb46760a5024b9 100644
--- a/holi-bricks/components/chips/ChipAction.tsx
+++ b/holi-bricks/components/chips/ChipAction.tsx
@@ -26,6 +26,7 @@ export type ChipActionProps = AccessibilityProps & {
   iconLeading?: HoliIconType
   iconTrailing?: HoliIconType
   'aria-label'?: string
+  testID?: string
 }
 
 export const ChipAction = ({
@@ -38,6 +39,7 @@ export const ChipAction = ({
   iconLeading,
   iconTrailing,
   role = 'switch',
+  testID,
   ...rest
 }: ChipActionProps) => {
   const { styles } = useStyles(stylesheet, { size, selected, disabled })
@@ -51,6 +53,7 @@ export const ChipAction = ({
       aria-checked={selected}
       role={role}
       style={({ hovered, focused }) => [styles.chip(!!hovered, !disabled && !!focused, color)]}
+      testID={testID}
     >
       {iconLeading && <HoliIcon icon={iconLeading} size={iconSize} color={styles.text.color} />}
       {children && (