eletrotupi / tcc/ frontend/e2e/README.mdcd4e510347589b652e51c97c5db46b27392f76da
4.1 KB | 107 lines Raw
1
# Mobile E2E (Maestro on a physical Android device)
2

3
Smoke coverage for the core journey: **login → register a mood → logout**. Runs
4
on a real Android device over `adb` (no emulator), against a dev build of the
5
app talking to the normal local API
6

7
## What you need
8

9
1. **API up, with the seeded user.**: the app points at whichever API
10
   `EXPO_PUBLIC_API_BASE_URL` names
11

12
   ```sh
13
   docker compose up -d db valkey api
14
   cd api && npm run seed        # idempotent; creates e2e@example.com / e2e-password
15
   ```
16

17
2. **Metro serving the dev build**, with the device-reachable API URL baked in
18
   (`EXPO_PUBLIC_*` is inlined at bundle time, so Metro must be started *after*
19
   `frontend/.env.local` is set: see `npm run test:e2e:env`)
20

21
3. **The dev build installed** (`com.eletrotupi.orbit`) and the device visible in
22
   `adb devices`
23

24
4. **Maestro** on `PATH` (`https://get.maestro.mobile.dev`)
25

26
## Running
27

28
```sh
29
cd frontend
30
npm run test:e2e          # adb prep + the tagged smoke flows
31
npm run test:e2e:env      # print the EXPO_PUBLIC_* values Metro needs
32
```
33

34
A single flow, while iterating (a few minutes faster than the whole suite):
35

36
```sh
37
cd frontend
38
maestro test e2e/mood.yaml \
39
  --env HOST_IP=$(ip route get 1 | awk '/src/{for(i=1;i<=NF;i++) if($i=="src"){print $(i+1);exit}}') \
40
  --env PORT=8081 --env E2E_EMAIL=e2e@example.com --env E2E_PASSWORD=e2e-password
41
```
42

43
Three flows take roughly 8 minutes: every flow clears app state, so each one
44
pays for a cold bundle load and the dev-client startup dance
45

46
## How the flows are structured
47

48
Every flow is **self-contained and order-independent**: Maestro runs them in an
49
arbitrary order, so none may assume another ran first. Each starts with:
50

51
```yaml
52
- runFlow:
53
    file: helpers/_login.yaml
54
```
55

56
and `helpers/_login.yaml` does the whole reset-and-authenticate: `clearState`
57
=> deep-link the dev build => log in => dismiss the notification prompt. That
58
means `clearState` is what guarantees a logged-out start, which has three
59
consequences worth knowing:
60

61
- it resets **runtime permissions**, so the notification dialog shows up again
62
  and must be allowed (see copy matches below);
63
- it resets **expo-dev-client**, so its first-run overlays appear ("Continue",
64
  then the dev-menu panel's "Close");
65
- it discards the downloaded JS bundle, hence the cold start
66

67
The app is intentionally **not** launched with `exp://`: Expo Go owns that
68
scheme, and driving Expo Go while asserting on `com.eletrotupi.orbit` will fail
69
with "element not found" everywhere. The dev build owns
70
`orbit://expo-development-client/?url=...`, kinda hacky but I don't care
71

72
## testID convention
73

74
`id`s are English even though the UI is pt-BR. Flows only touch screens that
75
pass an explicit `testID`
76

77
Auto-derived fallbacks exist when a screen passes nothing: `Button` →
78
`button-<slug(title)>`, `Input`/`TextArea` → `input-<slug(label)>`,
79
`MoodSelector` → `mood-<id>`. The slug util lives in `Button.tsx` / `Input.tsx`
80
(NFD strip, lowercase, kebab-style)
81

82
Every flow file: **including subflows** — must declare `appId:
83
com.eletrotupi.orbit` in its config section. Maestro 2.x requires it per file;
84
the workspace `.maestro/config.yaml` cannot supply it
85

86
## The unavoidable copy matches
87

88
A handful of strings cannot be reached by `testID` because they belong to the
89
OS or to dev tooling. These are deliberate, and the only ones a flow may assert
90
on:
91

92
| Where | Selector | Why |
93
| --- | --- | --- |
94
| Logout confirm `Alert` | `^Sair$` with `index: 1` | RN native dialog, no ids, will be fixed eventually |
95
| History card annotation | `"e2e smoke register"` | the one *data* assertion; proves write-through |
96
| Notification permission | `com.android.permissioncontroller:id/permission_allow_button` | AOSP system dialog |
97
| expo-dev-client onboarding | `^Continue$` | dev tooling, not app UI |
98
| expo-dev-client dev menu | `^Close$` (content-desc) | dev tooling, not app UI |
99

100
Everything else is greeted via `testID`
101

102
## Known gotchas
103

104
- **The formSheet opens at its half detent.** `entry/mood-components` uses
105
  `sheetInitialDetentIndex: 1` of `[0.25, 0.5, 1]`, so only the first rows of
106
  the component list are mounted
107
- The soft keyboard covers `button-login`; the flow calls `hideKeyboard` first