Repository navigation
Commit prebuilt Appduct playground apps as end-to-end fixtures #476
Description
Part of #466.
Scope
After this PR the repo holds two ready-made sample apps: an iOS simulator
build and an Android debug build of Appduct's native playground. Both are
built from one pinned Appduct commit. The agent-device slow tests (#477) install
them without building an app or downloading anything.
In short
Today simlock's repo has no app to install, so a test cannot show that an
agent's install of a local app works through simlock. This task adds two
built apps under e2e/fixtures/appduct/, with a README that says where they
came from and how to build them again.
A fixture app here is a built app committed to the repo for tests, for
example e2e/fixtures/appduct/android/AppductPlayground.apk.
flowchart LR
A[Appduct repo at the pinned commit] --> B[xcodebuild / gradlew]
B --> C["e2e/fixtures/appduct/ (new)"]
C --> D[#477 slow tests: agent-device install]
If this goes wrong: no simlock user notices. #477's slow tests fail at
install, or cannot find the screen ids they click.
Technical spec
Modules touched
e2e/fixtures/appduct/README.md(new)e2e/fixtures/appduct/ios/AppductPlayground.app/(new, about 1.6 MB)e2e/fixtures/appduct/android/AppductPlayground.apk(new, about 10 MB)e2e/appduct-fixtures.test.ts(new, fast e2e lane)src/source-hygiene.test.ts(changed: skips files undere2e/fixtures/)
flowchart LR
T["e2e/appduct-fixtures.test.ts (new)"] --> R["fixtures/appduct/README.md (new)"]
T --> F["fixtures/appduct/ios, android (new)"]
H["src/source-hygiene.test.ts (changed)"] -. skips .-> F
The source:
- Repo:
https://github.com/callstackincubator/appduct. - Pin: tag
v0.15.0, commit0e68131bdd4b8a789314812caf1995b496c52ae9.
It is the newest release. It holds the lastplayground-nativechange
(7edfa7d) and the last native SDK change (0963162). - The builds in the local
../cordieritecheckout are older than the pin.
Do not copy them; build fresh at the pin.
Build commands (they go in the README word for word):
# iOS, from playground-native/ios at the pin (needs Xcode and xcodegen)
xcodegen generate
xcodebuild build -project AppductPlayground.xcodeproj -scheme AppductPlayground \
-configuration Debug -sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' -derivedDataPath build \
ARCHS=arm64 CODE_SIGNING_ALLOWED=NO
# -> build/Build/Products/Debug-iphonesimulator/AppductPlayground.app
# Android, from playground-native/android at the pin (needs JDK 17 and ANDROID_HOME)
./gradlew :app:assembleDebug
# -> app/build/outputs/apk/debug/app-debug.apk, committed as AppductPlayground.apkThe README says:
- the repo, the tag and the full commit;
- the build commands above, and where each output is copied;
- the tool versions used for this build (Xcode, xcodegen, JDK, Android SDK
platform); - the app ids: iOS
com.callstack.appduct.playgroundnative, Android
com.callstack.appduct.playground; - the screen ids End-to-end tests: agent-device through a simlock worker on real iOS and Android devices #477 uses, from Appduct's playground contract:
tab-tools,
tab-status,connection-state,call-count; - that the iOS build runs on arm64 simulators only (Apple silicon Macs);
- a table of every fixture file with its SHA-256, in the format below;
- how to refresh: build at a new pin, replace the files, update the pin and
the table in the same commit.
The README's fixed lines, which the test parses (everything else is free text):
Repo: https://github.com/callstackincubator/appduct
Commit: `0e68131bdd4b8a789314812caf1995b496c52ae9`
## Files
| File | SHA-256 |
| --- | --- |
| `android/AppductPlayground.apk` | `3f5a…` (64 hex digits) |
| `ios/AppductPlayground.app/AppductPlayground` | `9c1e…` (64 hex digits) |- "Names the Appduct repo" means a line
Repo: https://github.com/callstackincubator/appduct.
The commit is the lineCommit:followed by 40 lowercase hex digits in backticks. - The table is the only table under the
## Filesheading. Its first column
is the path relative toe2e/fixtures/appduct/, in backticks; its second
is the SHA-256 as 64 lowercase hex digits, in backticks. One row per file;
the README itself has no row. - The test splits each row on
|and trims each cell, so the padding oxfmt
adds when it realigns the table (lefthookformaton*.md) changes
nothing.
Debug builds are used on both platforms, as Appduct's own device suite does.
The iOS build is unsigned; the arm64 linker signs it ad hoc, which the
simulator accepts. The Android build is signed with the builder's debug key.
Contract and event changes
None. Searched: the only file under src/ it changes is the test src/source-hygiene.test.ts; no contract shape, schema or event is touched.
Other code on the same state
Searched for fixtures, .gitattributes, LFS and the globs that reach e2e/:
-
No
e2e/fixtures/directory exists today. No.gitattributesand no git
LFS in the repo. The files go in as ordinary git blobs. The repo's pack is
35.7 MiB today; this adds about 11.5 MB, and every refresh adds as much
again to history. -
vitest.config.tse2e project includese2e/**/*.test.ts. Only the new
test file matches; the fixture directory holds no test file. -
lefthook.ymlformats staged*.{ts,tsx,js,mjs,json,md,yml,yaml}. It
formats the README. The built bundle holds onlyInfo.plist,PkgInfo,
the executable and its debug dylibs, so no fixture file matches. -
package.jsonfilesships onlydist, so the fixtures never reach the
npm package. -
e2e/tsconfig.typecheck.jsonincludes**/*.ts; no fixture file is
TypeScript. Fallow reads only JS and TS sources. -
src/source-hygiene.test.tslists every tracked file withgit ls-files
and fails "contain no raw NUL byte" on any file holding a 0x00 byte. The
APK, the Mach-O executable, its dylibs and the binaryInfo.plistall hold
NUL bytes, so as it stands the test would fail on this PR. The fixtures
win: the test skips paths undere2e/fixtures/(built binaries, never
searched as text), and its doc comment and title say so ("tracked files
outsidee2e/fixtures/contain no raw NUL byte, so grep and ripgrep can
search them"). It still sees every other tracked file.
Nothing else reads or writes these paths.
Rules in play
testing.md: the checksum test must go red when a fixture byte or a
README hash changes. Rule 4: the hygiene test's narrowed claim must say
what it skips.safety.md: no implicit downloads. The apps are committed, so no test
fetches one.documentation.md: the README is a maintainer file undere2e/, not an
end-user doc.
Tests
Seam: a fast-lane vitest file that lists the fixture files with
git ls-files -s e2e/fixtures/appduct (tracked files only, so a Finder
.DS_Store or a rebuild leftover on disk changes nothing) and reads the
README; it starts no daemon. Model: the describe/it shape of
e2e/helpers/cli.test.ts, and src/source-hygiene.test.ts for the
git ls-files call.
- every tracked file under
e2e/fixtures/appduct/except the README is
listed in the README's table, and the SHA-256 of the file on disk (read
withfs, not the git blob id) matches the one listed - the tracked files include
ios/AppductPlayground.app/Info.plist,
ios/AppductPlayground.app/AppductPlaygroundand
android/AppductPlayground.apk, under exactly those names - the README's table lists no file that git does not track under
e2e/fixtures/appduct/ - the iOS executable
ios/AppductPlayground.app/AppductPlaygroundis
tracked with mode100755 - the README has the
Repo:line naming
https://github.com/callstackincubator/appductand aCommit:line with
40 lowercase hex digits - (
src/source-hygiene.test.ts) the hygiene test's file list holds no path
undere2e/fixtures/and still holdse2e/appduct-fixtures.test.ts
Done when
pnpm test:e2e e2e/appduct-fixtures.test.tsand
pnpm test:unit src/source-hygiene.test.tspass with the fixtures committed.- Changing one byte of a fixture, or one digit of a README hash, makes the
checksum test fail;git update-index --chmod=-xon the iOS executable
makes the mode test fail. - On a Mac:
plutil -extract CFBundleIdentifier raw e2e/fixtures/appduct/ios/AppductPlayground.app/Info.plist
printscom.callstack.appduct.playgroundnative, and
lipo -info e2e/fixtures/appduct/ios/AppductPlayground.app/AppductPlayground
namesarm64. - With the Android SDK:
aapt dump badging e2e/fixtures/appduct/android/AppductPlayground.apk
(from$ANDROID_HOME/build-tools/<version>/) names package
com.callstack.appduct.playground. git ls-remote https://github.com/callstackincubator/appduct v0.15.0
prints the commit the README names.- The bundle id, the package name and the arm64 architecture above are
checked by hand at each refresh; End-to-end tests: agent-device through a simlock worker on real iOS and Android devices #477's slow tests prove them on every
run, since they install and launch the apps by those ids. - That both apps install and run on real devices is proven by End-to-end tests: agent-device through a simlock worker on real iOS and Android devices #477's slow
tests, not here.
Out of scope
- A script or CI job that rebuilds the apps. The README's commands are the
record. - Release builds, and Appduct's Expo and Flutter playgrounds.
- git LFS.
- Any test that installs the apps (End-to-end tests: agent-device through a simlock worker on real iOS and Android devices #477).
Depends on
Approval
- Approved for delivery
Written by an agent.
Activity
V3RON commentedon Oct 12, 2026
Spec updated: fixes from the spec check (source-hygiene test skips e2e/fixtures/, git ls-files listing, executable mode check, README table format defined).
Written by an agent.
V3RON commentedon Oct 12, 2026
Spec updated: fixes from the second spec check (hash of the file on disk, named files required, manual checks tied to #477, contract-search line).
Written by an agent.
github-actions commentedon Oct 12, 2026
Now
task:ready: approved, technical spec present.test: commit prebuilt Appduct playground apps as end-to-end fixtures (#…
test: skip e2e/fixtures/ in the NUL-byte hygiene check (#476)
test: format and comment-lint the Appduct fixture tests (#476)
test: queue the waiter before the last match is released so quarantin…
test(e2e): commit prebuilt Appduct playground apps as fixtures (#493)