Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
01c8dc0
working uniwind
HugoPerard Jan 23, 2026
b31a8cd
wip
HugoPerard Jan 23, 2026
a54f953
wip
HugoPerard Feb 6, 2026
66df855
wip ficus removed
HugoPerard Feb 9, 2026
473e328
theme uniwind
HugoPerard Feb 16, 2026
ca72a79
update expo 55 and all deps
HugoPerard Mar 12, 2026
d8a966e
some clean and style improvement
HugoPerard Mar 12, 2026
657f45d
Added focus state on input and buttons, fix on android app icon
ntorionbearstudio Mar 13, 2026
910b296
themed-status-bar
HugoPerard Mar 13, 2026
4f501a3
prettier tailwind and add remeda and ts-pattern
HugoPerard Mar 13, 2026
0436c39
update onboarding animation
HugoPerard Mar 13, 2026
69baa88
update expo and eas config to manage envs, and update README docs
HugoPerard Mar 13, 2026
2a43d34
fix react doctor
HugoPerard Mar 17, 2026
205dfa5
add icons per env
HugoPerard Mar 17, 2026
fae6ca8
[ADD] CONFIG - tsconfig.json - Add the missing include of uniwind-typ…
Atama-Heitekava Apr 2, 2026
a2cb99e
[DEL] COMPONENTS - button?tsx - Remove the prop hovered
Atama-Heitekava Apr 2, 2026
f99a7a6
[ADD] TESTS - maestro - Add the maestro test e2e
Atama-Heitekava Apr 3, 2026
9bd3895
[UPD] DEPENDENCIES - package.json pnpm-lock.yaml - Change de version …
Atama-Heitekava Apr 3, 2026
67f3f42
[FIX] LINT - button.tsx - Add the missing hovered argument
Atama-Heitekava Apr 3, 2026
6948424
[FIX] TYPESCRIPT - button.tsx - Give the all object state in place of…
Atama-Heitekava Apr 3, 2026
8f86c49
[FIX] IMAGE - README.md - Remove ficusui from the technologies image,…
Atama-Heitekava Apr 7, 2026
89275b5
[UPD] COMPONENTS - testID - Add a testId prop to the tested component…
Atama-Heitekava Apr 7, 2026
250597f
[UPD] TESTS - .maestro - Change the tests to use the new prop testId …
Atama-Heitekava Apr 7, 2026
4b29f63
[FIX] TESTS - pin-input.tsx, open-first-book.yaml - Fix the error of …
Atama-Heitekava Apr 7, 2026
4b44c05
[UPD] TESTS - components - remove testId props from components
Atama-Heitekava Apr 7, 2026
fc4ca15
[UPD] TESTS -.maestro - change all the tests to work without testId
Atama-Heitekava Apr 7, 2026
42849ed
FIX] TESTS - login.yaml - Remove Hint value
Atama-Heitekava Apr 7, 2026
0f5c5c7
FIX] TESTS - login.yaml - Remove Hint value
Atama-Heitekava Apr 7, 2026
9805236
[AUPD] TESTS - .maestro - Remove useless comments
Atama-Heitekava Apr 7, 2026
f7e7abc
[ADD] TEST - smoke, logout and navigation - Add the tests for navigat…
Atama-Heitekava Apr 7, 2026
730cf73
[ADD] TESTS - workflow - first idea for the github action using maest…
Atama-Heitekava Apr 7, 2026
18e718f
[FIX] TESST - github actions - Comment the branches-inglone attribute
Atama-Heitekava Apr 7, 2026
9f29f14
[UPD] TESTS - github action - Add local launch of the github action f…
Atama-Heitekava Apr 7, 2026
9ac1b67
[FIX] TESTS - github action - Fix the error in the branch name for te…
Atama-Heitekava Apr 7, 2026
759172f
[FIX] TESTS - github action - Fix the error in the branch name for te…
Atama-Heitekava Apr 7, 2026
6e36629
[UPD] TESTS - eas, package - Create a new eas session for the test e2…
Atama-Heitekava Apr 7, 2026
3d32895
[UPD] TESTS - github action - Try to reduce metamemary by limiting th…
Atama-Heitekava Apr 7, 2026
2fd27b6
[UPD] TESTS - github action - try to optimise memory usage
Atama-Heitekava Apr 7, 2026
56bdd61
([UPD] TESTS - github action - remove one optimisation causing the fa…
Atama-Heitekava Apr 7, 2026
b8930cc
[UPD] TESTS - github action - Add new optimisation for the memory
Atama-Heitekava Apr 7, 2026
ff762cc
[UPD] TESTS - .maestro - Change the tests to use tags and env file
Atama-Heitekava Apr 7, 2026
844b088
[UPD] TESTS - README.md - Add a E2E tests section to the readme
Atama-Heitekava Apr 7, 2026
beb66df
Merge branch 'main' into atama/test-end-to-end-using-maestro
Atama-Heitekava Apr 8, 2026
8013568
[UPD] TESTS - e2e.yml - Change the APP_ENV value from development to …
Atama-Heitekava Apr 8, 2026
cdc0ad7
[FIX] TESTS - e2e.yml - Chnage the profile for production on the APK …
Atama-Heitekava Apr 8, 2026
9baa600
[FIX] TESTS - .maestro - Change the logic of the test, and remove the…
Atama-Heitekava Apr 8, 2026
04c24d9
Merge branch 'atama/test-end-to-end-using-maestro' into test/e2e/inte…
Atama-Heitekava Apr 8, 2026
35178c3
[UPD] TESTS - workflow - Change the build for a pre-build
Atama-Heitekava Apr 8, 2026
f2ea8c1
[UPD] TESTS - workflow - Change the condition to launch the test (tes…
Atama-Heitekava Apr 8, 2026
61b735a
[ADD] TESTS - worflow - add KVM right to the runner
Atama-Heitekava Apr 8, 2026
561ebaf
FIX] TESTS - workflow - Change the method to give KVM right to the ru…
Atama-Heitekava Apr 8, 2026
ab5676f
[FIX] CLAUDE - CLAUDE.md - Try saomething new to change the langauge …
Atama-Heitekava Apr 8, 2026
de586b9
[UPD] TESTS - workflow - Try to increase the timeout limit
Atama-Heitekava Apr 9, 2026
3e8e1af
[FIX] TESTS - workflow - Add new command to wait for the app to respond
Atama-Heitekava Apr 9, 2026
02167bb
[UPD] TESTS - maestro - remove when prop from the tests
Atama-Heitekava Apr 9, 2026
4a6a483
[UPD] TESTS - workflow - Change the workflow to correspond to one wor…
Atama-Heitekava Apr 9, 2026
e40843c
[FIX] TESTS - workflow - Try gto fix the metadata size problem
Atama-Heitekava Apr 9, 2026
f6e7746
[FIX] TESTS - workflow - Try gto fix the metadata size problem
Atama-Heitekava Apr 9, 2026
2d763fe
[ADD] TESTS - workflow - Try to increase the waiting timout
Atama-Heitekava Apr 10, 2026
d5b867c
[ADD] TESTS - workflow - Try to reduce the number of worker, to limit…
Atama-Heitekava Apr 10, 2026
429767f
[UPD] TESTS - maestro - Change the tests to correspond to the last te…
Atama-Heitekava Apr 10, 2026
b6a8aac
[UPD] TESTS - README.md - Change the README.md to adapt to the new tests
Atama-Heitekava Apr 10, 2026
8057ad0
[UPD] TESTS - workflow - Try to change the build from prod to staging
Atama-Heitekava Apr 10, 2026
b657e55
[ADD] TESTS - maestro - Change the tested version from producion to s…
Atama-Heitekava Apr 13, 2026
0edf681
[UPD] TESTS - workflow - Add some cache for maestro and the emulator,…
Atama-Heitekava Apr 13, 2026
154668e
[DEL] TESTS - workflow - Remove graddle cache from the build-apk job …
Atama-Heitekava Apr 13, 2026
b2aa42c
[UPD] TESTS - workflows - Try to fix warnings in the runs
Atama-Heitekava Apr 13, 2026
9f80f1a
[UPD] TESTS - workflow - Fix more warnings in the runs
Atama-Heitekava Apr 13, 2026
61fb17a
[UPD] TESTS - workflow - Change the event on which the action run
Atama-Heitekava Apr 13, 2026
fbefa14
[FIX] MERGE - test-e2e - Fix merge conflict when merging test e2e
Atama-Heitekava Apr 14, 2026
6e0964b
[UPD] TESTS - README.md - Add the new workflow to the list, and updat…
Atama-Heitekava Apr 14, 2026
10aed60
[UPD] TESTS - README.md - Add some precision for the testing part
Atama-Heitekava Apr 14, 2026
6df301e
[ADD] TESTS - README - Add new section to the readme on how to add ne…
Atama-Heitekava Apr 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
name: 🎭 E2E Tests

env:
EXPO_PUBLIC_API_URL: ${{ vars.API_URL }}
EXPO_PUBLIC_AUTH_URL: ${{ vars.AUTH_URL }}
EXPO_PUBLIC_OPENAPI_URL: ${{ vars.OPENAPI_URL }}

on:
workflow_dispatch:
pull_request:
types: [closed]
branches: [main]

jobs:
build-apk:
name: 🔨 Build APK
if: (github.event_name == 'pull_request' && github.event.pull_request.merged == true) || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: 🗑 Free disk space
uses: jlumbroso/free-disk-space@main
with:
android: false
dotnet: true
haskell: true
large-packages: true
swap-storage: true

- name: 🏗 Setup repo
uses: actions/checkout@v5

- name: 🏗 Setup pnpm
uses: pnpm/action-setup@v5
with:
version: 10

- name: 🏗 Setup Node
uses: actions/setup-node@v5
with:
node-version: 'lts/*'
cache: 'pnpm'

- name: 🏗 Setup Java
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'

- name: 📦 Install dependencies
run: pnpm install

- name: 🔑 Generate debug keystore
run: |
mkdir -p $HOME/.android
keytool -genkeypair -v \
-keystore $HOME/.android/debug.keystore \
-storepass android \
-alias androiddebugkey \
-keypass android \
-keyalg RSA \
-keysize 2048 \
-validity 10000 \
-dname "CN=Android Debug,O=Android,C=US"

- name: 🔨 Prebuild & Build APK (release)
env:
JAVA_TOOL_OPTIONS: "-XX:MaxMetaspaceSize=2048m -Dfile.encoding=UTF-8"
GRADLE_OPTS: "-Xmx4096m -XX:MaxMetaspaceSize=2048m -Dfile.encoding=UTF-8"
run: |
APP_ENV=staging npx expo prebuild --clean --platform android
cd android && ./gradlew assembleRelease --no-daemon \
-PreactNativeArchitectures=x86_64 \
-x lintVitalRelease \
--max-workers=2 \
-Pkotlin.compiler.execution.strategy=in-process \
-Pandroid.injected.signing.store.file=$HOME/.android/debug.keystore \
-Pandroid.injected.signing.store.password=android \
-Pandroid.injected.signing.key.alias=androiddebugkey \
-Pandroid.injected.signing.key.password=android

- name: 📤 Upload APK artifact
uses: actions/upload-artifact@v7
with:
name: app-release
path: android/app/build/outputs/apk/release/app-release.apk
retention-days: 1

e2e-full:
name: 🎭 Full E2E Tests
needs: build-apk
runs-on: ubuntu-latest
steps:
- name: 🏗 Enable KVM
run: sudo chmod 777 /dev/kvm

- name: 🏗 Setup repo
uses: actions/checkout@v5

- name: 🏗 Setup pnpm
uses: pnpm/action-setup@v5
with:
version: 10

- name: 🏗 Setup Node
uses: actions/setup-node@v5
with:
node-version: 'lts/*'
cache: 'pnpm'

- name: 📦 Install dependencies
run: pnpm install

- name: 📥 Download APK artifact
uses: actions/download-artifact@v8
with:
name: app-release
path: android/app/build/outputs/apk/release/

- name: 📦 Cache Maestro
uses: actions/cache@v5
with:
path: ~/.maestro
key: maestro-${{ runner.os }}

- name: 🎭 Install Maestro
run: |
if [ ! -f "$HOME/.maestro/bin/maestro" ]; then
curl -Ls "https://get.maestro.mobile.dev" | bash
fi
echo "$HOME/.maestro/bin" >> $GITHUB_PATH

- name: 🤖 Run full E2E tests on emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 34
arch: x86_64
force-avd-creation: false
disable-animations: true
pre-emulator-launch-script: |
echo "persist.sys.locale=en-US" >> $HOME/.android/avd/test.avd/config.ini
echo "persist.sys.language=en" >> $HOME/.android/avd/test.avd/config.ini
echo "persist.sys.country=US" >> $HOME/.android/avd/test.avd/config.ini
script: |
adb kill-server
adb start-server
adb wait-for-device
sleep 5
adb uninstall com.bearstudio.startuinative.staging || true
adb install android/app/build/outputs/apk/release/app-release.apk
pnpm test:e2e
15 changes: 15 additions & 0 deletions .maestro/flows/books.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Tests the books tab navigation and book detail screen.
# Relies on sign-in.yaml having run first (session state is preserved).
# Run standalone: maestro test .maestro/flows/sign-in.yaml .maestro/flows/books.yaml
appId: com.bearstudio.startuinative.staging
---
- launchApp

- tapOn: 'Books'
- waitForAnimationToEnd

- tapOn:
index: 0
below: 'Books'
- back
- assertVisible: 'Books'
10 changes: 10 additions & 0 deletions .maestro/flows/sign-in.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Tests the complete authentication journey from a clean app state.
# Run: maestro test .maestro/flows/sign-in.yaml
appId: com.bearstudio.startuinative.staging
---
- launchApp:
clearState: true

- runFlow: ../utils/handle-onboarding.yaml

- runFlow: ../utils/login.yaml
18 changes: 18 additions & 0 deletions .maestro/flows/sign-out.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Tests the logout flow from the account tab.
# Relies on sign-in.yaml having run first (session state is preserved).
# Run standalone: maestro test .maestro/flows/sign-in.yaml .maestro/flows/sign-out.yaml
appId: com.bearstudio.startuinative.staging
---
- launchApp

- tapOn: 'Account'
- tapOn: 'Sign out'

- waitForAnimationToEnd

- tapOn:
text: 'Sign out'
below: 'You are about to end your session'

- waitForAnimationToEnd
- assertVisible: 'Login to your account'
17 changes: 17 additions & 0 deletions .maestro/flows/tab-navigation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Tests navigation between the three main tabs.
# Relies on sign-in.yaml having run first (session state is preserved).
# Run standalone: maestro test .maestro/flows/sign-in.yaml .maestro/flows/tab-navigation.yaml
appId: com.bearstudio.startuinative.staging
---
- launchApp

- assertVisible: 'Home'

- tapOn: 'Books'
- assertVisible: 'Books'

- tapOn: 'Account'
- assertVisible: 'Account'

- tapOn: 'Home'
- assertVisible: 'Home'
9 changes: 9 additions & 0 deletions .maestro/utils/handle-onboarding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
appId: com.bearstudio.startuinative.staging
---
- extendedWaitUntil:
visible: 'Continue'
timeout: 60000

- tapOn: 'Continue'

- tapOn: "Let's start"
11 changes: 11 additions & 0 deletions .maestro/utils/login.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
appId: com.bearstudio.startuinative.staging
env:
TEST_EMAIL: 'user@user.com'
TEST_OTP: '000000'
---
- tapOn:
text: 'Email'
- inputText: ${TEST_EMAIL}
- tapOn: 'Continue with email'
- inputText: ${TEST_OTP}
- assertVisible: 'Home'
104 changes: 97 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,14 @@ For the **Release Production** workflow, also configure `eas.json` submit.produc
## Workflows


| Workflow | Trigger | Description |
| ------------------------- | ------------ | --------------------------------------------------------------------------------------- |
| **EAS build** | Manual | Build app — select profile (development, staging, production) in the GitHub UI |
| **EAS Development build** | Manual | Build development client (internal) |
| **EAS Update** | Manual | Publish OTA update — select channel (development, staging, production) in the GitHub UI |
| **EAS Preview** | Pull request | Publish preview update on PR branch |
| **Release Production** | Manual | Build production, then submit to App Store and Play Store |
| Workflow | Trigger | Description |
| ------------------------- | ------------------------ | --------------------------------------------------------------------------------------- |
| **EAS build** | Manual | Build app — select profile (development, staging, production) in the GitHub UI |
| **EAS Development build** | Manual | Build development client (internal) |
| **EAS Update** | Manual | Publish OTA update — select channel (development, staging, production) in the GitHub UI |
| **EAS Preview** | Pull request | Publish preview update on PR branch |
| **Release Production** | Manual | Build production, then submit to App Store and Play Store |
| **E2E Tests** | PR merged into main / Manual | Build staging APK and run Maestro flows on an Android emulator (API 34, x86_64) |


### EAS build profiles
Expand All @@ -198,3 +199,92 @@ To be able to use previews on PR, you have to setup your project with EAS
- `eas init --id {projectid}`
- `eas update:configure`

# E2E Tests (using Maestro)

End-to-end tests are written with [Maestro](https://docs.maestro.dev) and live in the `.maestro/` folder.

## Prerequisites

- **Java 17+** — required by Maestro. Verify with `java -version`, and ensure `JAVA_HOME` points to your installation.
- **Maestro CLI** — install with:

```bash
# macOS / Linux
curl -fsSL "https://get.maestro.mobile.dev" | bash

# macOS (Homebrew)
brew tap mobile-dev-inc/tap && brew install mobile-dev-inc/tap/maestro
```

Verify the installation with `maestro --help`.

> [!TIP]
> On Windows, download `maestro.zip` from the [GitHub releases](https://github.com/mobile-dev-inc/maestro/releases), extract it to `C:\maestro`, then add `C:\maestro\bin` to your `PATH`.

```text
.maestro/
├── flows/ # Test flows (one feature per file)
│ ├── sign-in.yaml
│ ├── sign-out.yaml
│ ├── tab-navigation.yaml
│ └── books.yaml
└── utils/ # Reusable sub-flows (login, onboarding...)
├── login.yaml
└── handle-onboarding.yaml
```

> [!TIP]
> Use the script to run the test to be sure to respect the launching order.

## Setup

The `appId` is set directly in each flow file. The environment variables used for authentication have default values defined in `utils/login.yaml`:

| Variable | Default | Description |
| --- | --- | --- |
| `TEST_EMAIL` | `user@user.com` | Email address of the test user |
| `TEST_OTP` | `000000` | OTP code for the test user |

## Scripts

```bash
# Run all flows locally
pnpm test:e2e
```

> [!TIP]
> Make sure the staging app (`APP_ENV=staging`) is installed and running in English on an emulator or device before launching the tests.

## Adding new tests

### New flow

Create a new file in `.maestro/flows/`. Each flow must declare the `appId` and start with `launchApp`:

```yaml
# .maestro/flows/my-feature.yaml
appId: com.bearstudio.startuinative.staging
---
- launchApp

- tapOn: 'My feature'
- assertVisible: 'Expected text'
```

If the flow requires the user to be authenticated, add `sign-in.yaml` before it in the `pnpm test:e2e` script in `package.json`. Most flows depend on session state preserved from the previous flow.

### New reusable sub-flow

Place reusable sequences in `.maestro/utils/` and include them with `runFlow:`:

```yaml
- runFlow: ../utils/my-util.yaml
```

### Register the flow in the test suite

Add the new flow to the `test:e2e` script in `package.json`, respecting the execution order (authentication must come first):

```json
"test:e2e": "maestro test .maestro/flows/sign-in.yaml ... .maestro/flows/my-feature.yaml .maestro/flows/sign-out.yaml"
```
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"gen:api": "dotenv -- npx @hey-api/openapi-ts -f ./src/lib/hey-api/config.ts",
"gen:icons": "svgr --config-file src/components/icons/svgr.config.cjs src/components/icons/svg-sources && prettier -w src/components/icons/generated",
"android": "expo run:android",
"ios": "expo run:ios"
"ios": "expo run:ios",
"test:e2e": "maestro test .maestro/flows/sign-in.yaml .maestro/flows/tab-navigation.yaml .maestro/flows/books.yaml .maestro/flows/sign-out.yaml"
},
"dependencies": {
"@bearstudio/ui-state": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/app/(logged)/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ export default function TabLayout() {
headerTintColor: themedStyle.color,
tabBarStyle: { backgroundColor: themedStyle.backgroundColor },
tabBarActiveTintColor: themedStyle.color,
tabBarButton: (props) => <HapticTab {...props} />,
sceneStyle: { backgroundColor: themedStyle.sceneBackgroundColor },
}}
>
Expand All @@ -90,6 +89,7 @@ export default function TabLayout() {
options={{
title: t(tab.translationKey),
headerShown: tab.headerShown,
tabBarButton: (props) => <HapticTab {...props} />,
tabBarIcon: (props) => {
const TabIcon = props.focused ? tab.iconFocused : tab.icon;
return (
Expand Down
Loading