Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIntermediáriocódigo testado

Testes e performance no React Native com Expo

Configure Jest e Testing Library no Expo SDK 57, teste comportamento acessível e investigue performance React Native sem medir o modo dev.

Rodolfo Mori5 min de leitura

Teste de componente confirma um comportamento observável; investigação de performance mede o app no cenário próximo de produção. Nesta lição, você configura Jest com jest-expo, testa um cartão pela acessibilidade e usa uma sequência de diagnóstico antes de aplicar otimizações aleatórias.

Os exemplos continuam o componente da lição de componentes e estilos e a FlatList de listas e navegação. Não é necessário publicar o app para rodar testes unitários, mas medir apenas o servidor de desenvolvimento produz conclusões enganosas.

Ensaio e cronômetro respondem perguntas diferentes

Imagine um teatro. O ensaio verifica se o ator entra na hora, diz a fala e reage ao sinal correto. O cronômetro mede quanto a troca de cenário demora sob as condições da apresentação. Um não substitui o outro.

No mapa técnico, Jest e Testing Library fazem o teste de comportamento; o profiler, os indicadores de frames e uma build release ajudam a medir performance. Um teste verde não prova 60 ou 120 quadros por segundo, e uma tela fluida não prova que a validação rejeita entrada vazia.

O limite da analogia é que alguns problemas atravessam as duas áreas: uma renderização em excesso pode tornar o teste lento e a tela travada. Mesmo assim, tecnicamente você precisa formular a pergunta: “a callback recebeu o id?” é teste; “qual commit demora mais?” é medição.

Instale versões compatíveis com Expo SDK 57

Use o resolvedor do SDK:

bash
npx expo install jest-expo jest @types/jest \
  @testing-library/react-native -- --save-dev

No projeto executado, a matriz ficou em Jest 29.7.0, jest-expo 57.0.4 e Testing Library 14.0.1. A documentação atual não recomenda react-test-renderer: ele está depreciado e não combina com React 19 para este fluxo.

Adicione scripts ao package.json:

json
{
  "scripts": {
    "test": "jest",
    "typecheck": "tsc --noEmit"
  }
}

Typecheck e Jest têm trabalhos diferentes. O primeiro confere contratos estáticos; o segundo executa caminhos e expectativas. Rode os dois na revisão.

Configure o preset que entende React Native

Crie jest.config.js:

js
module.exports = {
  preset: 'jest-expo',
  testMatch: ['**/__tests__/**/*-test.[jt]s?(x)'],
};

jest-expo prepara transformações e mocks compatíveis com módulos Expo e React Native. Isso não simula perfeitamente Android ou iOS; cria um ambiente JavaScript controlado para lógica e árvore de componentes. No Testing Library 14, os matchers são registrados ao importar a biblioteca; o antigo caminho @testing-library/react-native/extend-expect não existe nessa versão.

Se uma biblioteca nativa não tem implementação Jest, use o mock recomendado por ela ou crie uma fronteira sua. Não substitua o módulo inteiro por jest.fn() sem preservar o comportamento que o componente realmente usa.

Teste a interface pela porta que a pessoa usa

O cartão oferece papel de checkbox, nome e estado. Teste esse contrato:

tsx
import { fireEvent, render, screen } from '@testing-library/react-native';

import { HabitCard } from '@/components/habit-card';

test('alterna o hábito pelo controle acessível', () => {
  const onToggle = jest.fn();
  render(
    <HabitCard
      habit={{ id: 'agua', title: 'Beber água', done: false }}
      onToggle={onToggle}
    />,
  );

  const checkbox = screen.getByRole('checkbox', {
    name: /beber água, pendente/i,
  });
  fireEvent.press(checkbox);

  expect(onToggle).toHaveBeenCalledTimes(1);
  expect(onToggle).toHaveBeenCalledWith('agua');
});

Buscar pelo papel acessível aproxima teste e experiência assistiva. Um seletor por nome de componente ou posição na árvore quebra numa refatoração que não mudou nada para o usuário.

Rode em modo de integração contínua:

bash
npm test -- --ci

A suíte editorial completa produziu:

PASS __tests__/habit-card-test.tsx PASS __tests__/storage-test.ts PASS __tests__/habits-test.ts PASS __tests__/daily-tip-test.ts Test Suites: 4 passed, 4 total Tests: 6 passed, 6 total

Nenhum aparelho foi aberto nessa prova. Ela cobre reducer, componente, storage mockado e serviço HTTP injetado; navegação nativa, gestos e aparência ainda pedem testes em simulador ou dispositivo.

Reproduza uma expectativa errada e leia o diagnóstico

Troque temporariamente o id esperado:

diff
-  expect(onToggle).toHaveBeenCalledWith('agua');
+  expect(onToggle).toHaveBeenCalledWith('leitura');

Jest mostra a diferença entre esperado e recebido:

Expected: "leitura" Received: "agua" Number of calls: 1

O erro não diz automaticamente se o componente ou o teste está errado. Volte ao requisito: pressionar “Beber água” deve emitir o id agua. Nesse caso, a expectativa alterada é que mentiu; restaure-a. Teste não merece vitória sobre a regra de negócio apenas porque está vermelho.

Meça fora do modo de desenvolvimento

O modo dev inclui avisos, ferramentas, verificações e Fast Refresh. Gere uma variante próxima de produção antes de comparar fluidez. Para Android local com ambiente configurado:

bash
npx expo run:android --variant release

Para inspecionar apenas se os bundles resolvem, a prova desta série usou:

bash
npx expo export --platform all --output-dir dist-proof

A exportação passou para Android, iOS e web, mas não é benchmark. Tempo de build e tamanho do bundle não medem automaticamente frames da interação. Defina um cenário, dispositivo, quantidade de itens e métrica antes de afirmar ganho.

Use as ferramentas de desenvolvimento do React Native para localizar commits de renderização e indicadores de JS/UI frames quando apropriado. Em React Native 0.86, recursos de performance global também ajudam a coletar medidas do runtime, mas o resultado precisa de contexto reproduzível.

Trate FlatList a partir do gargalo observado

Comece com identidade estável e componentes baratos:

tsx
const renderHabit = useCallback(
  ({ item }: { item: Habit }) => (
    <HabitCard habit={item} onToggle={toggleHabit} />
  ),
  [toggleHabit],
);

<FlatList
  data={habits}
  initialNumToRender={10}
  keyExtractor={(habit) => habit.id}
  renderItem={renderHabit}
  windowSize={7}
/>;

initialNumToRender equilibra primeira pintura e preenchimento da tela; windowSize equilibra memória e risco de áreas vazias durante rolagem. Não copie esses números como receita universal. Altura do item, aparelho e padrão de rolagem mudam a decisão.

Se os itens têm altura fixa, getItemLayout pode evitar medição:

tsx
const ITEM_HEIGHT = 76;

<FlatList
  data={habits}
  getItemLayout={(_, index) => ({
    index,
    length: ITEM_HEIGHT,
    offset: ITEM_HEIGHT * index,
  })}
  keyExtractor={(habit) => habit.id}
  renderItem={renderHabit}
/>;

Inclua margens e separadores no cálculo. Declarar 76 quando o item varia com texto grande gera saltos e posicionamento incorreto. A otimização só é válida quando a premissa de altura fixa também é válida.

Evite memoização por reflexo

memo, useMemo e useCallback têm custo e dependências. Primeiro confirme que o filho renderiza com props equivalentes e que esse trabalho pesa no cenário medido. Depois estabilize callbacks e estruturas onde o profiler aponta valor.

Uma função recriada não é automaticamente um problema. React ainda precisa comparar dependências, e um callback memoizado que fecha sobre estado errado pode introduzir bug. Otimização é uma hipótese seguida de medida, não um ritual para deixar o arquivo com aparência avançada.

Missão: construa uma matriz de confiança

Adicione um teste para entrada vazia, um para falha HTTP e um para a ação do cartão. Depois rode a lista com 20, 200 e 2.000 itens numa build release e anote dispositivo, duração do cenário e sintoma antes de mudar configurações.

text
Camada          Pergunta                         Prova
reducer         ação gera o próximo estado?      Jest
componente      pessoa consegue acionar?         Testing Library
navegação       rota abre e volta?               teste no app
performance     rolagem perde frames onde?        profiler + release

Ao terminar, você terá evidência separada por pergunta. O tutorial do app completo reúne essa estrutura, storage, API e Router num projeto executável.

  • testes react native
  • performance react native
  • jest expo
  • testing library
  • flatlist performance

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Node 24.16.0, Expo SDK 57.0.15, React Native 0.86.2, React 19.2.3, Jest 29.7.0, jest-expo 57.0.4 e Testing Library 14.0.1, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. Expo — Unit testing with Jest — docs.expo.dev
  2. Expo Router — Testing — docs.expo.dev
  3. React Native — Performance overview — reactnative.dev
  4. React Native — Optimizing FlatList Configuration — reactnative.dev

Continue por aqui