Repository navigation
docs(mobile): record agent conventions for tests, variants, and file modules #13143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| # Mobile (apps/mobile) | ||
|
|
||
| React Native (Expo) client. Run commands from `apps/mobile`. Logic shared with web lives in | ||
| `packages/client-runtime`; the dev/build loop is in the [README](README.md). | ||
|
|
||
| ## Tests | ||
|
|
||
| `vp test run` (the `test` script) runs colocated `<module>.test.ts(x)` files in the Node | ||
| environment from the repository-root Vitest config. There is no native runtime, so tests swap | ||
| native/Expo modules for fakes. Pick the harness the surrounding tests use: `@effect/vitest` (its | ||
| Effect-aware `it`/`expect`, plus `assert`) for Effect-based code, and `vite-plus/test` for `vi` | ||
| and plain `describe`/`expect` — many files mix the two. Only the standalone `.mjs` config-plugin | ||
| tests under `plugins/` import from `vitest`. The established pattern for mocked tests hoists mock | ||
| fns, installs `vi.mock` factories for native/Expo packages, then imports the module under test: | ||
|
|
||
| ```ts | ||
| import { describe, expect, it, vi } from "vite-plus/test"; | ||
|
|
||
| const mocks = vi.hoisted(() => ({ read: vi.fn() })); | ||
| vi.mock("expo-file-system", () => ({ | ||
| File: class { | ||
| arrayBuffer = mocks.read; | ||
| }, | ||
| })); | ||
|
|
||
| import { collect } from "./collect"; // import after the mocks | ||
| ``` | ||
|
|
||
| The existing `.test.tsx` component tests render with `renderToStaticMarkup` from | ||
| `react-dom/server` against a mocked `react-native`; there is no native renderer in this | ||
| environment. A local `modules/*` package may keep its own test setup instead (e.g. | ||
| `react-dom/client` with DOM shims in t3-markdown-text); follow the module's existing tests. | ||
| Prefer testing logic extracted into plain `.ts` modules over full component renders when the | ||
| behavior does not need a tree. Tests for a platform variant import the concrete file and mirror | ||
| its name (`voiceTranscription.ios.test.ts` tests `voiceTranscription.ios.ts`). | ||
|
|
||
| Typecheck with `tsc --noEmit` (the `typecheck` script). JS/TS lint runs from the repo root | ||
| (`vp lint`); native Swift/Kotlin lint is `node ../../scripts/mobile-native-static-check.ts`. | ||
|
|
||
| ## Platform variants | ||
|
|
||
| Styling-only divergence uses `Platform.OS` branches over `className` strings. Uniwind | ||
| `ios:`/`android:` class variants are unguarded in this repo's Metro pipeline — Android classes | ||
| apply on iOS and vice versa — so do not use them until the pipeline is fixed or upgraded and | ||
| platform isolation is proved on both devices; #13169 reverted #13161 (`ec28eefa0d0`) for exactly | ||
| this and left no variant usages in `src` — do not reintroduce them. Behavior (not styling) | ||
| divergence branches on `Platform.OS` at runtime. When the native UI | ||
| diverges wholesale, use file variants: Metro resolves `./Name` to `Name.ios.tsx`, | ||
| `Name.android.tsx`, or `Name.native.ts` before the extensionless base, which is the fallback. | ||
| When the base and the variant share an implementation, put it in `Name.shared.tsx` and re-export | ||
| it from the extensionless base (see `src/features/home/AndroidHomeFab.tsx`) so callers never | ||
| branch on it. | ||
|
|
||
| ## Naming | ||
|
|
||
| Components and screens are PascalCase files (`HomeScreen.tsx`, route screens end in | ||
| `RouteScreen.tsx`); logic modules are kebab-case (`home-list-options.ts`). Hook files are roughly | ||
| evenly split between `useCamelCase.ts` and `use-kebab-case.ts`, so match the surrounding | ||
| directory. Feature code lives in `src/features/<feature>/`, shared UI in | ||
| `src/components`, native glue in `src/native`. Tests and platform variants sit next to their | ||
| module. | ||
|
|
||
| ## Imports | ||
|
|
||
| There is no path alias (`@/`) and no `baseUrl`; use relative imports, however deep | ||
| (`../../native/StackHeader`). `@t3tools/client-runtime` has no root export, so always import an | ||
| explicit subpath (`@t3tools/client-runtime/state/shell`) — a root-repo lint rule enforces this. | ||
|
|
||
| ## Native `file:` modules | ||
|
|
||
| `modules/*` packages are `file:` dependencies that pnpm copies (not links) into its store, and | ||
| Metro bundles the copy. After editing a module's TypeScript, run `vp i` at the repository root or | ||
| the change stays invisible to a running dev client; Swift/Kotlin compile from this checkout | ||
| directly. A JavaScript change in a local module that "has no effect" on device is usually this | ||
| missed reinstall (details in `docs/internals/mobile-development.md`). | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.