Search code examples
javascriptreactjsreact-nativexmlhttprequestfetch

fetch is never calling .then nor .catch in testing environment


I have the following web component :

import React, { useCallback, useState } from 'react'
import { ErrorBoundary } from 'react-error-boundary'
import { useFocusEffect } from '@react-navigation/native'
import styled from 'styled-components/native'
import { useEduConnect, useEduConnectClient } from '../../../IdCheckContext'

import { EduConnectErrorBoundary } from '../../../errors/eduConnect/EduConnectErrorBoundary'
import { ErrorTrigger } from '../../../errors/ErrorTrigger'
import { EduConnectError, EduConnectErrors } from '../../../errors/eduConnect'
import { PageWithHeader } from '../../layout/PageWithHeader'
import { IdCardMagnifyingGlassIcon } from '../../icons/IdCardMagnifyingGlass'
import { getSpacing } from '../../../ui/utils'
import { ButtonPrimary, Spacer, Typo } from '../../../ui/components'
import { ColorsEnum } from '../../../theme/colors'

export const EduConnectForm = () => {
  const eduConnectClient = useEduConnectClient()
  const allowEduConnect = useEduConnect()
  const [error, setError] = useState<EduConnectError | null>(allowEduConnect ? null : new EduConnectError(EduConnectErrors.unavailable))

  const checkIfEduConnectIsAvailable = useCallback(() => {
    if (allowEduConnect === false) {
      setError(new EduConnectError(EduConnectErrors.unavailable))
    }
  }, [allowEduConnect])

  const openEduConnect = useCallback(() => {
    function setWebView() {
      eduConnectClient?.getAccessToken().then((value) => {
        console.log('value', value, `${eduConnectClient.getLoginUrl()}?redirect=false`)
        const request: RequestInit = {
          headers: {
            Authorization: `Bearer ${value}`,
          } as unknown as Record<string, string>,
          mode: 'cors',
          credentials: 'include',
        }
        fetch(`${eduConnectClient.getLoginUrl()}?redirect=false`, request)
          .catch((err) => {
            console.log(1)
            console.error(err)
            setError(err)
          }) // should be 401 or something, will display default error
          .then((response) => {
            console.log(JSON.stringify(response))
            // @ts-ignore fix response typing
            if ('status' in response && response.status === 200) {
              const finalURL = response?.headers?.get('educonnect-redirect')
              if (finalURL) {
                globalThis.window.open(finalURL, '_blank')
              }
            }
          })
      })
        .catch((err) => {
          console.log(1)
          console.error(err)
          setError(err)
        })
    }
    setWebView()
  }, [eduConnectClient])

  useFocusEffect(
    useCallback(() => {
      openEduConnect()
      checkIfEduConnectIsAvailable()
    }, [checkIfEduConnectIsAvailable, openEduConnect])
  )

  if (error) {
    throw error
  }

  return (
    <ErrorBoundary FallbackComponent={EduConnectErrorBoundary}>
      <PageWithHeader
        title="Mon identité"
        scrollChildren={
          <>
            <Center>
              <IdCardMagnifyingGlassIcon size={getSpacing(47)} />
            </Center>

            <Typo.ButtonText color={ColorsEnum.GREY_DARK}>{`Identification`}</Typo.ButtonText>
            <Spacer.Column numberOfSpaces={4} />

            <Typo.Body color={ColorsEnum.GREY_DARK}>
              {`Pour procéder à ton identification, nous allons te demander de te connecter à ÉduConnect. Muni toi de ton identifiant et de ton mot de passe ÉduConnect. Dès que tu as bien complété le parcours, reviens sur ce site pour terminer ton inscription et découvrir toutes les offres du pass Culture !`}
            </Typo.Body>

            <Spacer.Column numberOfSpaces={8} />
          </>
        }
        bottomChildren={
          <ButtonPrimary
            title={`Ouvrir un onglet ÉduConnect`}
            onPress={openEduConnect}
          />
        }
      />
      <ErrorTrigger error={error} />
    </ErrorBoundary>
  )
}


const Center = styled.View({
  alignSelf: 'center',
})

In local, the fetch request succeed and it open a new tab. While in testing environment, it never call .catch nor .then. I expect to call at least one of the two.

This is my network developer tab in testing environment:

network tab

This is my console developer tab in testing environment:

console tab

Any clue what is going wrong here ?


Solution

  • This was due to the missing Access-Control-Expose-Headers necessary to allow the client to read the header to prevent XSS Attack:

    For clients to be able to access other headers, the server must list them using the Access-Control-Expose-Headers header.

    mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers