Introduces review-logic.js: DOM-free suggestion logic (segment
splitting, overlap guards, smart-spacing, applying accepted edits) plus
deterministic per-suggestion pen-ink strike styling, loadable both as a
browser script and a Node module. Unit-tested with Node's built-in
runner via a new :server:jsTest Gradle task, wired into CI as an
explicit gate with Node set up in the build job.
ProjectLifecycleTest launches the real ProjectSelectActivity, creates a project,
waits for it to appear in the list, and confirms opening it launches
ProjectRootActivity (via ActivityMonitor). Cleans up in @After.
- Wire jetbrains-compose ui-test-junit4 into the androidTest source set.
- Tag the create-project affordance (CreateProjectButtonTestTag); "Create
Project" otherwise appears as three separate on-screen texts.
- Run the instrumented suite on an emulator in CI (android-emulator-runner) with
AVD snapshot caching.
- Convert HashTest from JUnit Jupiter to JUnit4 so the AndroidJUnit4 runner can
execute it on-device (it had "no runnable methods" otherwise); use assertEquals
since assert() is a no-op when assertions are disabled on a device. It now
verifies EntityHasher's golden vector on Android ART.
- Fix a scope-close crash: getSceneBufferDirectory used a non-recursive
createDirectory, so closing a project whose scenes/ dir is absent threw on the
teardown path and crashed the process. Use createDirectories (matching its
siblings) and order the test teardown so it doesn't delete the project mid-close.
buildDebug never touched the androidTest source set, so a stale instrumented
test could - and did - rot unnoticed: HashTest stopped compiling after `tags`
was added to EntityHasher.hashNote.
- Add a :android:assembleDebugAndroidTest step: a fast, emulator-free gate that
compiles + packages the androidTest source set on every PR.
- Fix the stale HashTest to match the current hashNote signature.
- Exclude the duplicate META-INF/LICENSE files the test deps ship so the
androidTest APK packages.
* Harden EntityHasher field-coverage test against nested and new-type drift
The descriptor-driven sensitivity test only inspected top-level fields, so a
new field on a nested DTO (ProjectTheme, WordCountGoal, Image) - or a whole new
synced type - could be added without the hasher, and no test failed.
- Recurse into owned nested @Serializable DTOs so e.g. theme.tertiary is a
tracked field path, not an invisible sub-field of `theme`.
- Cover ProjectData / ProjectDataHasher, which had no structural guard at all.
- Assert every ApiProjectEntity.Type has a sensitivity spec, so a new entity
subtype can't ship without one (reflection-free; server has no kotlin-reflect).
* Run server unit tests explicitly in CI
The server unit tests (including EntityHashSensitivityTest) previously ran only
as a side-effect of koverXmlReport gathering coverage - a kover config change
would silently stop running them. Add an explicit :server:test gate.
Spins up a real Jetty server and a real headless client in the same JVM,
runs the actual sync protocol over HTTP, and asserts against the shared
FakeFileSystem. Covers seven scenarios: smoke (handshake), client upload,
server download, independent edits, conflict resolved to server, conflict
resolved to client, and client delete.
- New :integrationTests Gradle module with the RoundTripTestBase harness,
HeadlessClient driver, and seven scenario tests.
- :server enables java-test-fixtures so EndToEndTest, E2eTestData, and
SqliteTestDatabase are shared with the new module instead of duplicated.
- CI: build.yml runs the suite on every PR/develop push; prepare-release.yml
adds an integration-tests job that gates all seven package jobs, so a
broken sync protocol blocks the release before any artifact is built.
* Moving all data into the server database
* Server projects now have UUIDs
* Client is now sending the project server ID
* Implemented Projects sync E2E test
* E2E sync test now does uploading and downloading!
* JVM 21