---
# System prepended metadata

title: 'Detox, useTypedTranslation - Mon-Fri, 11th-15th Jan, 2020'
tags: [usetranslation, translationlocalisation, e2e, programmingjournal, detox, '2021']

---

# Detox, useTypedTranslation - Mon-Fri, 11th-15th Jan, 2020

I've been slipping writing my diary so far in 2021!

### Detox

Did a lot of work getting Detox working better in CI.
A few learnings I had were:
1. Tests seem more reliable when running on simulator rather than headless 
1. Android emulator opens automatically on `detox test` command, but iOS simulator must be opened manually
1. With the exception of writing new tests, always build and test with **release** config. This prevents debug messages such as [YellowBox warnings](https://reactnative.dev/docs/0.62/debugging#warnings) interferring with tests.
1. If you are struggling with a matcher, build the app for dev (`yarn start`, then `yarn ios` / `yarn android`) and use [Flipper](https://fbflipper.com/) to inspect the underlying native view and determine if you are selecting the right element. 
1. I find `toExist` to be more reliable than `toBeVisible`

The i18n `useTranslation` hook doesn't allow me to pass a generic in order to get type safety for my different translation strings. I created an improved `useTypedTranslation` hook for the job:

My .ddetoxrc.json:
```json=
{
    "testRunner": "jest",
    "runnerConfig": "e2e/jest.config.js",
    "configurations": {
        "ios.cp.debug": {
            "binaryPath": "./ios/DerivedData/myapp/Build/Products/Debug-iphonesimulator/myapp.app",
            "build": "xcodebuild -workspace ./ios/myapp.xcworkspace -scheme myapp -configuration Debug -sdk iphonesimulator -destination 'name=iPhone 11'",
            "type": "ios.simulator",
            "name": "iPhone 11"
        },
        "ios.cp.release": {
            "binaryPath": "./ios/DerivedData/myapp/Build/Products/Release-iphonesimulator/myapp.app",
            "build": "xcodebuild -workspace ./ios/myapp.xcworkspace -scheme myapp -configuration Release -sdk iphonesimulator",
            "type": "ios.simulator",
            "device": {
                "type": "iPhone 11"
            }
        },
        "android.cp.debug": {
            "binaryPath": "./android/app/build/outputs/apk/debug/app-debug.apk",
            "build": "cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..",
            "type": "android.emulator",
            "name": "Pixel_3a_API_28"
        },
        "android.cp.release": {
            "binaryPath": "android/app/build/outputs/apk/release/app-release.apk",
            "build": "cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release && cd ..",
            "type": "android.emulator",
            "device": {
                "avdName": "Pixel_3a_API_28"
            }
        }
    }
}

```

### useTypedTranslation

```typescript=
import { useCallback } from 'react'
import { UseTranslationOptions, useTranslation } from 'react-i18next'

import { translations } from './translations'

type TranslationKeys = keyof typeof translations

type TypedTFunction = (key: TranslationKeys, options?: UseTranslationOptions) => string

export function useTypedTranslation(): { t: TypedTFunction } {
    const { t } = useTranslation()
    const typedT = useCallback((key: TranslationKeys) => t<string, TranslationKeys>(key), [t])
    return {
        t: typedT,
    }
}
```

###### tags: `programmingjournal` `2021` `translationlocalisation` `detox` `e2e` `usetranslation`