Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 4 additions & 7 deletions .claude/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@
"version": "0.0.1",
"configurations": [
{
"name": "start",
"runtimeExecutable": "npm",
"runtimeArgs": [
"run",
"start"
],
"port": 3000
"name": "expo-web",
"runtimeExecutable": "npx",
"runtimeArgs": ["expo", "start", "--web", "--port", "5173"],
"port": 5173
}
]
}
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,34 @@ Tokens in `src/ui/tokens.ts` are transcribed from the web's `frontend/src/index.
npm run lint && npm run typecheck && npm test
```

Two integration suites are opt-in because they need a live server. They drive
the real client modules against it, and the onboarding one writes real rows
(fresh accounts and team keys per run):
The integration suites are opt-in because they need a live server. They drive
the real client modules against it — the same code the screens call — and several
of them write real rows (fresh accounts and team keys per run):

```bash
SOFTTRACK_LIVE_URL=http://localhost:8000 npm test
SOFTTRACK_LIVE_URL=http://localhost:8000 npm run test:live
```

The live suites between them register a handful of real accounts per run, and
registration is throttled per IP and charged even on success — so a few full runs
in a row will eventually 429. The counter lives in the API process, so
`test:live` rather than `npm test`, because these suites **cannot run in
parallel**. Registration is throttled per IP and charged even on success, and
several suites register: run concurrently they exhaust the budget immediately,
and the 429 that comes back is an `AxiosError` whose circular `req`/`res` pair
crashes the jest worker trying to serialize it, so the failure surfaces as
`Test suite failed to run` rather than as the throttle it is. `--runInBand`
spreads them out. A few full runs in a row will still eventually 429; the
counter lives in the API process, so
`docker compose restart backend && docker compose up -d` clears it without
touching the database.

They also share one instance, so they pick their fixtures deliberately rather
than by position — see `src/api/__tests__/support/team.ts`. `GET /teams` promises
no order, and the team-administration and onboarding suites create teams the API
offers no way to delete, so an instance these have run against accumulates empty
teams permanently. Taking `teams[0]` eventually lands on one of those.

Production is covered separately by `live-production.test.ts`, which stays
read-only apart from a single scratch issue it deletes in the same run.

Note `experiments.typedRoutes` is a dev-time aid: the route union is written by
`expo start`, not by `expo export`, so outside the dev server every path
typechecks permissively. Paths built at runtime go through `href()` in
Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ module.exports = {
resolver: 'react-native-worklets/jest/resolver.js',
// The generated client is orval's output, not ours -- it is covered by the
// api-contract check instead.
testPathIgnorePatterns: ['/node_modules/', '/src/api/generated/'],
// `support/` holds helpers for the live suites, not suites of their own.
testPathIgnorePatterns: ['/node_modules/', '/src/api/generated/', '/__tests__/support/'],
};
183 changes: 182 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"lint": "expo lint",
"typecheck": "tsc --noEmit",
"test": "jest",
"test:live": "jest --runInBand",
"sync:openapi": "./scripts/sync-openapi.sh",
"generate:api": "orval --config orval.config.ts"
},
Expand Down Expand Up @@ -44,6 +45,7 @@
"react-native-safe-area-context": "~5.7.0",
"react-native-screens": "~4.26.0",
"react-native-svg": "15.15.4",
"react-native-web": "^0.21.2",
"react-native-worklets": "0.10.1"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions src/api/__tests__/live-attachments.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @jest-environment node
*/
import Axios from 'axios';

Check warning on line 4 in src/api/__tests__/live-attachments.test.ts

View workflow job for this annotation

GitHub Actions / Mobile · lint + typecheck + test + bundle

Using exported name 'Axios' as identifier for default import

import { AXIOS_INSTANCE } from '@/api/client';
import { loginAuthLoginPost } from '@/api/generated/endpoints/auth/auth';
Expand All @@ -13,10 +13,10 @@
createIssueTeamsTeamIdIssuesPost,
deleteIssueIssuesIssueIdDelete,
} from '@/api/generated/endpoints/issues/issues';
import { listMyTeamsTeamsGet } from '@/api/generated/endpoints/teams/teams';
import type { AttachmentRead, TeamRead } from '@/api/generated/models';
import { setInstanceUrl } from '@/api/instance';
import { persistToken, getAccessToken } from '@/auth/session';
import { seededTeam } from '@/api/__tests__/support/team';

/**
* Attachments against a real instance.
Expand Down Expand Up @@ -59,7 +59,7 @@
password: process.env.SOFTTRACK_LIVE_PASSWORD ?? 'password123',
});
await persistToken(token.access_token);
team = (await listMyTeamsTeamsGet())[0];
team = await seededTeam();
const issue = await createIssueTeamsTeamIdIssuesPost(team.id, {
title: `Attachments ${RUN}`,
});
Expand Down Expand Up @@ -98,7 +98,7 @@

// And without it: a bare client, the way a plain <img src> would ask.
expect(getAccessToken()).not.toBeNull();
const anonymous = Axios.create({ baseURL: base });

Check warning on line 101 in src/api/__tests__/live-attachments.test.ts

View workflow job for this annotation

GitHub Actions / Mobile · lint + typecheck + test + bundle

Caution: `Axios` also has a named export `create`. Check if you meant to write `import {create} from 'axios'` instead
await expect(anonymous.get(path)).rejects.toMatchObject({
response: { status: 401 },
});
Expand Down
Loading
Loading