AccueilClients

Applications et sites

  • Application mĂ©tiersIntranet, back-office...
  • Applications mobilesAndroid & iOS
  • Sites InternetSites marketings et vitrines
  • Expertises techniques

  • React
  • Expo / React Native
  • Next.js
  • Node.js
  • Directus
  • TypeScript
  • Open SourceBlogContactEstimer

    1 octobre 2019

    Tester son app React Native - End-to-End avec Detox

    5 minutes de lecture

    Tester son app React Native - End-to-End avec Detox

    Si vous regardez tout en haut de la pyramide, vous apercevrez les tests end-to-end (E2E). Au dessus du typing, des tests unitaires et fonctionnels, ils permettent de tester votre application comme un utilisateur le ferait réellement. Ils ont l'avantage de s'émanciper des détails d'implémentation. Nous avions vu comment les mettre en place sur un navigateur grùce à Cypress. Mais qu'en est-il sur un simulateur iOS ou Android ?

    La rĂ©ponse : Detox, un framework de tests dĂ©veloppĂ© par Wix (connu pour ĂȘtre actif dans la communautĂ© React). L'un de ses principaux avantages est de gĂ©rer automatiquement les attentes entre les instructions de tests. Lors d'appels asynchrones (requĂȘtes, animations, timers
), Detox attend automatiquement la fin d'exĂ©cution avant de passer Ă  l'instruction suivante.

    Pourquoi des tests E2E ?

    Il existe plusieurs types de tests (unitaires, fonctionnels, E2E), le deux premiers types peuvent ĂȘtre difficiles Ă  mettre en place car il faut se soucier de l'implĂ©mentation, c'est pourquoi il est important de les Ă©crire au fil de l'eau. Les tests end-to-end, quant Ă  eux, peuvent facilement ĂȘtre mis en place en fin de dĂ©veloppement. Ils sont cependant les plus coĂ»teux en terme de ressources (simulateur iOS / Android) et en temps d'exĂ©cution.

    Installer Detox

    Installer les outils et le CLI

    Nous utilisons Homebrew pour installer applesimutils (une collection d'utilitaires pour piloter les simulateurs iOS) :

    brew tap wix/brew
    brew install applesimutils
    

    Puis le CLI Detox via Yarn :

    yarn global add detox-cli
    

    Ajouter Detox Ă  son projet React Native

    Installez la librairie Detox en dépendance de développement de votre projet :

    yarn add --dev detox
    

    Configurez Detox

    Il faut maintenant indiquer sur quel simulateur et avec quel build vous voulez exécuter vos tests. Pour cela, ajoutez une section detox à votre package.json :

    {
      ...
      "detox": {
        "configurations": {
          "ios.sim.debug": {
            "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/app.app",
            "build": "xcodebuild -workspace ios/app.xcworkspace -configuration Debug -sdk iphonesimulator -scheme app -derivedDataPath ios/build",
            "type": "ios.simulator≀",
            "name": "iPhone X"
          }
        }
      }
    }
    

    Nous créons une configuration ios.sim.debug (le choix du nom est libre) décrivant l'emplacement du binaire (binaryPath), la commande de build, le type (ios.simulator) ainsi que le nom du simulateur (dans notre cas iPhone X). Vous pouvez ajouter d'autres configurations (par exemple en mode Release ou sur un simulateur Android).

    Initialiser vos tests

    Le CLI Detox propose une commande pour créer la structure et la configuration de vos tests :

    $ detox init -r jest
    
    detox[986] INFO:  [init.js] Created a file at path: e2e/config.json
    detox[986] INFO:  [init.js] Created a file at path: e2e/init.js
    detox[986] INFO:  [init.js] Created a file at path: e2e/firstTest.spec.js
    detox[986] INFO:  [init.js] Patching package.json
    detox[986] INFO:  [init.js]   json["detox"]["test-runner"] = "jest";
    

    Celle-ci va ajouter un dossier e2e à la racine de votre projet et mettre à jour votre configuration dans le package.json avec le test runner voulu (Jest dans notre cas). Le dossier contient la config minimale et un exemple dévoilant la structure d'un test :

    describe('Example', () => {
      beforeEach(async () => {
        await device.reloadReactNative()
      })
    
      it('should have welcome screen', async () => {
        await expect(element(by.id('welcome'))).toBeVisible()
      })
    
      it('should show hello screen after tap', async () => {
        await element(by.id('hello_button')).tap()
        await expect(element(by.text('Hello!!!'))).toBeVisible()
      })
    
      it('should show world screen after tap', async () => {
        await element(by.id('world_button')).tap()
        await expect(element(by.text('World!!!'))).toBeVisible()
      })
    })
    

    Detox est compatible avec Jest et Mocha. Nous utilisons Jest qui est installé par défaut avec React Native (et que je préfÚre personnellement)

    Vous pouvez maintenant compiler et lancer vos tests :

    detox build
    detox test
    

    Si vous avez renseigné plusieurs configurations, il vous faut passer l'option --configuration avec son nom :

    detox build --configuration ios.sim.debug
    detox test --configuration ios.sim.debug
    

    Il est maintenant temps d'écrire vos tests !

    Écrire ses tests

    Les tests tournent autour de 3 concepts :

    Les actions
    📒 Documentation

    Les actions permettent d'interagir avec les élements de votre application (boutons, vues
), elles permettent de simuler les principales interactions sur mobile :

    • tap()
    • longPress()
    • multiTap()
    • scroll()
    • scrollTo()
    • swipe()
    • 


    Les sélecteurs (Matchers)
    📒 Documentation

    Les sélecteurs permettent de sélectionner des élements de votre application :

    • by.id()
    • by.text()
    • by.label()
    • 


    by.id() sélectionne un élement disposant d'un attribut testID :

    <Text testID="name">Baptiste</Text>
    

    Utiliser les attributs testID est une bonne pratique car ils découplent les tests de la logique applicative. C'est pourquoi les composants React Native supportent cet attribut.

    Les validateurs (Expectations)
    📒 Documentation

    Les validateurs permettent de valider l'existence d'un élement :

    • toBeVisible()
    • toBeNotVisible()
    • toHaveText()
    • scroll()
    • toHaveId()
    • 


    Tester un écran d'onboarding

    Nous allons tester un écran d'onboarding, mis en place grùce au composant react-native-onboarding-swiper. Il permet de créer rapidement une suite d'écrans introduisant l'application lors du premier lancement :

    react-native-onboarding-swiper

    Voici notre composant :

    const OnboardingScreen = () => (
      <View testID="scrollView" style={{ flex: 1 }}>
        <Onboarding
          pages={[
            {
              backgroundColor: '#7ed6df',
              title: <Text testID="hello">Hello 👋</Text>,
              subtitle: 'Find ticket',
            },
            {
              backgroundColor: '#f6e58d',
              title: <Text testID="fast">Fast 🐎</Text>,
              subtitle: 'Buy ticket',
            },
            {
              backgroundColor: '#fab1a0',
              title: <Text testID="secure">Secure 👀</Text>,
              subtitle: 'Encrypted communication',
            },
          ]}
        />
      </View>
    )
    

    Nous allons utiliser l'action swipe pour naviguer entre nos écrans ainsi que l'action tap pour cliquer sur le bouton Next. Enfin nous testons que chaque composant Text est bien visible :

    describe('Onboarding', () => {
      beforeEach(async () => {
        await device.reloadReactNative()
      })
    
      it('should have onboarding screen', async () => {
        const view = element(by.id('scrollView'))
    
        await expect(element(by.id('hello'))).toBeVisible()
    
        await view.swipe('left')
        await expect(element(by.id('fast'))).toBeVisible()
    
        await view.swipe('right')
        await expect(element(by.id('hello'))).toBeVisible()
    
        await view.swipe('left')
        await view.swipe('left')
        await expect(element(by.id('secure'))).toBeVisible()
    
        await view.swipe('right')
        await expect(element(by.id('fast'))).toBeVisible()
    
        await element(by.text('Next')).tap()
        await expect(element(by.id('secure'))).toBeVisible()
      })
    })
    

    Nous pouvons maintenant lancer nos tests avec la commande detox test :



    $ detox test
    Example: should have onboarding screen [OK]
     PASS  e2e/onboarding.spec.js (19.783s)
      Example
        ✓ should have onboarding screen (12146ms)
    

    Les tests passent ✅

    Et les mocks ?

    Comment faire si vous voulez mocker un appel Ă  une API tiers dans vos tests ? Avec Detox, contrairement Ă  Jest oĂč vous pouvez dĂ©finir spĂ©cifiquement des mocks au runtime, les mocks se font lors de la compilation de votre app. La mĂ©thode est de renseigner un fichier spĂ©cifique qui va venir remplacer l'original. Ces fichiers doivent ĂȘtre suffixĂ©s par .e2e.js. Prenons l'exemple d'un appel vers une API lors de l'appui sur un bouton :

    import api from './client/api'
    
    const Home = () => {
      const [movies, setMovies] = useState([])
    
      ;<View>
        <Button
          title="Get movies"
          onPress={async () => {
            const data = await api.getMovies()
            setMovies(data)
          }}
        />
      </View>
    }
    

    Pour mocker cet appel avec Detox, il vous faudra crĂ©er un fichier api.e2e.js au mĂȘme niveau que votre fichier api.js :

    > src
      Home.js
      > client
        api.js
        api.e2e.js
    

    Lors du build, Detox chargera non pas le fichier api.js mais le fichier api.e2e.js. Ce fichier peut retourner directement une payload json sans faire d'appel Ă  votre API. Pour mettre en place ce mĂ©canisme, il vous faudra tout de mĂȘme suivre ces quelques Ă©tapes.

    Aller plus loin

    Nous avons vu comment utiliser Detox pour mettre en place des tests E2E sur React Native. Detox propose d'autres fonctionnalités comme la génération de screenshots ou de vidéos. Enfin, une suite de tests n'est utile que si elle ne tourne sur un serveur d'intégration continue. La documentation explique comment faire tourner vos tests sur Travis ou Bitrise, vous pouvez la retrouver ici.

    Faites chauffer les simulateurs ! đŸ”„

    👋

    À dĂ©couvrir Ă©galement

    Premier Octet vous accompagne dans le développement de vos projets avec react-native

    En savoir plusNous contacter
    18 avenue Parmentier
    75011 Paris
    +33 1 43 57 39 11
    hello@premieroctet.com

    Suivez nos aventures

    GitHub

    X

    Flux RSS

    Bluesky

    Naviguez Ă  vue