Tests
What the automated tests check, grouped by feature. Use it to review coverage and to find behavior that no test protects. How to run the suites is in CONTRIBUTING.md.
How to use this folder
- Is a behavior tested? Find its area in the coverage map and open only that file. Each area file lists behaviors, the tests that cover each one per layer, a Not tested line naming the layers without a test, then the area’s Gaps.
- Not listed means not known to be tested. If a behavior isn’t in its area file, treat it as untested until you’ve checked the tests named there.
- Nothing tests it at all? Modules and code with no tests are in untested-areas.md.
- When you add, rename or remove a test, update its entry in the area file and the test files table. When a test closes a gap, remove the gap.
Tests are written as File.testName. Swift tests drop the test prefix here, so NoteEditingUITests.testUndoRemovesTyping is written NoteEditingUITests.UndoRemovesTyping.
Layers
| Layer | Folder | What it exercises |
|---|---|---|
| Shared, common | app/sharedLogic/src/commonTest | Pure rules: Markdown codec, editor session, diff, links, search matching, trail. Runs on JVM, Android host and iOS simulator |
| Shared, JVM | app/sharedLogic/src/jvmTest | NotesCore against an in-memory SQLite (JdbcSqliteDriver): storage, revisions, organizing, export and import; the sync engine between devices through a fake server and through the real server in process (KtorDestination over HTTP) |
| Android UI | app/androidApp/src/androidTest | Compose + Espresso on a device or emulator, empty in-memory database per test |
| Android integration | app/androidApp/src/androidTest (ExportIntegrationTest) | Export and import end to end on Android SQLite and real files, no UI |
| Android screenshots | app/androidApp/src/test | Roborazzi + Robolectric on the JVM, compared with src/test/screenshots |
| iOS UI | app/iosApp/JotryUITests | XCUITest, app launched with -ui-testing (in-memory database) |
| iOS integration | app/iosApp/JotryIntegrationTests | Export and import end to end on the iOS core and real files, no UI |
| iOS snapshots | app/iosApp/JotrySnapshotTests | swift-snapshot-testing, references recorded on iPhone 17 Pro, iOS 26.5 |
| Crypto, common | crypto/src/commonTest | Sync encryption: note keys, record envelopes, QR enrollment wrap, recovery key, signing keys, key vault. Runs on JVM, iOS simulator and an Android device or emulator |
| Crypto, Android | crypto/src/androidDeviceTest | The Android Keystore secret store, on a device or emulator |
| Crypto, iOS | crypto/src/iosTest | The Keychain secret store, on a booted iOS simulator |
| Server, service | server/service/src/test | The server’s framework-free logic, and the store contracts on the in-memory stores. Runs on the JVM alone |
| Server, development build | server/dev/src/test | The development verifier (D-70), which only a development build contains. Runs on the JVM alone |
| Server, Postgres adapter | server/postgres/src/test | Migrations, the database probe and settings, and the store contracts, on a real Postgres (Testcontainers or JOTRY_TEST_DATABASE_URL), a fresh database per test |
| Sync API | syncApi/src/commonTest | The CBOR request and response classes (D-63) and the signed statements (D-68): bytes on the wire, round trips, unknown fields. Run on the JVM, iOS simulator and an Android device or emulator |
| Server, Ktor adapter | server/src/test | HTTP routes and the Koin wiring through Ktor’s test host, and the promo tool’s commands; the wiring test uses a real Postgres |
| Desktop | app/desktopUi/src/test | Compose desktop UI tests (runComposeUiTest, offscreen) and NotesCore on a SQLite file, on the JVM |
Coverage map
| Area | File | Shared | Android UI | iOS UI | Main gaps |
|---|---|---|---|---|---|
| Notebooks, pins, moving notes | notebooks-and-organizing.md | ✅ | ✅ | ✅ | Android left-edge swipe for the drawer |
| Editor, formatting, checklists, saving, titles | editor.md | ✅ | ✅ | ✅ | Headings and lists in the UI, 10-second autosave, generated titles on devices |
| Markdown parsing and writing | markdown.md | ✅ | n/a | n/a | Mermaid fences, images, deep nesting |
| Note links, web links, lookup, back and forward | links-and-navigation.md | ✅ | ✅ | ✅ | Links to trashed notes, tapping web addresses in the read view |
| History, versions and changes | history.md | ✅ | ✅ | ✅ | Spoken “added/removed”, strike-through |
| Search | search.md | ✅ | ✅ | ✅ | Selecting all results |
| Trash, delete and undo | trash.md | ✅ | ✅ | ✅ | App closing before Empty trash’s undo bar expires |
| Markdown export and import | export-import.md | ✅ | ✅ | ✅ | Importing single files from Settings, unreadable files |
| Storage, migration, hashes, ordering | storage.md | ✅ | — | — | Only the version 1 migration |
| Sync encryption (crypto module: keys, envelopes, enrollment, recovery, key storage) | sync-crypto.md | ✅ | n/a | n/a | Windows and Linux desktop key stores; the D-57 keychain backup |
| Sync engine and the apps’ sync screens (turning sync on, joining by QR code, outbox, push, pull, merging, delete-versus-edit, root key rotation) | sync-engine.md | ✅ | ✅ | ✅ | The engine not on Android or iOS; the apps’ status screen and turning sync off; records waiting for their key; how the engine handles refused writes and a read-only group |
| Sync server and API (health, migrations, groups, entitlements, promo codes, records, device auth, enrollment, recovery, root key rotation, rate limits, maintenance, CBOR) | server.md | n/a | n/a | n/a | Reverse QR and the store verifiers are not built; the sync engine calls the auth and record routes only in the shared JVM tests |
| Desktop window, editor and database | desktop.md | n/a | n/a | n/a | The native binary and the Nucleus window; most formatting; window screens beyond the main flows |
| Screenshots (visual) | screenshots.md | n/a | ✅ | ✅ | Android has no empty-search screenshot |
| No tests at all | untested-areas.md | Localization, platform text styling, sync contracts and web |
Test files
| Test file | Layer | Tests | Areas |
|---|---|---|---|
commonTest/.../domain/DomainSupportTest.kt | Shared, common | 7 | storage, export-import |
commonTest/.../editor/EditorSessionTest.kt | Shared, common | 20 | editor, links-and-navigation |
commonTest/.../history/RevisionDiffTest.kt | Shared, common | 12 | history |
commonTest/.../links/NoteLinksTest.kt | Shared, common | 7 | links-and-navigation |
commonTest/.../markdown/MarkdownCodecTest.kt | Shared, common | 12 | markdown |
commonTest/.../navigation/NoteTrailTest.kt | Shared, common | 2 | links-and-navigation |
commonTest/.../search/SearchIndexTest.kt | Shared, common | 6 | search |
jvmTest/.../NotesCoreTest.kt | Shared, JVM | 25 | storage, history, search, trash, export-import, notebooks-and-organizing, links-and-navigation, editor |
jvmTest/.../OrganizingTest.kt | Shared, JVM | 10 | notebooks-and-organizing, editor, links-and-navigation, storage |
jvmTest/.../sync/SyncEngineTest.kt | Shared, JVM | 14 | sync-engine |
jvmTest/.../sync/SyncFaultTest.kt | Shared, JVM | 4 | sync-engine |
jvmTest/.../sync/SyncOnServerTest.kt | Shared, JVM | 18 | sync-engine: SyncEngineTest and SyncFaultTest again, against the real server in process |
jvmTest/.../sync/KtorDestinationTest.kt | Shared, JVM | 9 | sync-engine |
jvmTest/.../sync/CloudSyncTest.kt | Shared, JVM | 9 | sync-engine |
jvmTest/.../sync/EnrollmentTest.kt | Shared, JVM | 5 | sync-engine |
jvmTest/.../sync/RootKeyRotationTest.kt | Shared, JVM | 10 | sync-engine |
jvmTest/.../sync/LiveSyncServerTest.kt | Shared, JVM | 1 | sync-engine; skipped unless JOTRY_SYNC_SERVER and JOTRY_PROMO_CODE are set |
jvmTest/.../sync/FakeSyncServer.kt, SyncTestServer.kt, InProcessSyncServer.kt, HttpSyncGroup.kt, SyncTestDevices.kt | Shared, JVM | 0 | Fixtures: the in-memory server with fault injection, the real server started in process, setting up a group over HTTP (create, QR enrollment), and test devices |
androidTest/.../NotebookUiTest.kt | Android UI | 12 | notebooks-and-organizing |
androidTest/.../NoteEditingUiTest.kt | Android UI | 14 | editor, links-and-navigation |
androidTest/.../HistorySearchTrashUiTest.kt | Android UI | 11 | history, search, trash, export-import (settings text) |
androidTest/.../SyncUiTest.kt | Android UI | 3 | sync-engine |
androidTest/.../ExportUiTest.kt | Android UI | 1 | export-import |
androidTest/.../ImportUiTest.kt | Android UI | 1 | export-import |
androidTest/.../ExportIntegrationTest.kt | Android integration | 1 | export-import |
androidTest/.../JotryUiTest.kt | Android UI | 0 | Base class: in-memory core, helpers such as typeInBody |
androidApp/src/test/.../ScreenshotTest.kt | Android screenshots | 12 | screenshots |
JotryUITests/NotebookUITests.swift | iOS UI | 14 | notebooks-and-organizing |
JotryUITests/NoteEditingUITests.swift | iOS UI | 14 | editor, links-and-navigation |
JotryUITests/HistorySearchTrashUITests.swift | iOS UI | 11 | history, search, trash, export-import (settings text) |
JotryUITests/SyncUITests.swift | iOS UI | 3 | sync-engine |
JotryUITests/ExportUITests.swift | iOS UI | 1 | export-import |
JotryUITests/ImportUITests.swift | iOS UI | 1 | export-import |
JotryUITests/JotryUITestCase.swift | iOS UI | 0 | Base class: launch with -ui-testing, helpers |
JotryIntegrationTests/ExportIntegrationTests.swift | iOS integration | 2 | export-import |
JotrySnapshotTests/ScreenSnapshotTests.swift | iOS snapshots | 13 | screenshots |
crypto/.../NoteKeysTest.kt | Crypto, common | 9 | sync-crypto |
crypto/.../DeviceNamesTest.kt | Crypto, common | 6 | sync-crypto |
crypto/.../RecordCipherTest.kt | Crypto, common | 9 | sync-crypto |
crypto/.../DeviceEnrollmentTest.kt | Crypto, common | 7 | sync-crypto |
crypto/.../RecoveryKeyTest.kt | Crypto, common | 12 | sync-crypto |
crypto/.../SigningKeyTest.kt | Crypto, common | 5 | sync-crypto |
crypto/.../KeyVaultTest.kt | Crypto, common | 5 | sync-crypto |
crypto/.../DeviceEncryptionKeyTest.kt | Crypto, common | 5 | sync-crypto |
crypto/src/androidDeviceTest/.../AndroidSecretStoreTest.kt | Crypto, Android | 4 | sync-crypto |
crypto/src/iosTest/.../IosSecretStoreTest.kt | Crypto, iOS | 3 | sync-crypto |
desktopUi/src/test/.../JotryDesktopUiTest.kt | Desktop | 12 | desktop |
desktopUi/src/test/.../DesktopEditorUiTest.kt | Desktop | 5 | desktop |
desktopUi/src/test/.../DatabaseTest.kt | Desktop | 3 | desktop |
desktopUi/src/test/.../LibraryEditorUiTest.kt | Desktop (ComposeTextEditor spike) | 5 | desktop |
desktopUi/src/test/.../DesktopSyncUiTest.kt | Desktop | 5 | desktop |
desktopUi/src/test/.../MacKeychainSecretStoreTest.kt | Desktop (macOS only) | 4 | desktop |
sharedUI/src/commonTest/.../SharedUICommonTest.kt | Template | 1 | Placeholder (example), tests nothing |
server/service/src/test/.../HealthServiceTest.kt | Server, service | 4 | server |
server/service/src/test/.../EntitlementPolicyTest.kt | Server, service | 8 | server |
server/service/src/test/.../InMemoryGroupStoreTest.kt | Server, service | 16 (GroupStoreContract) | server |
server/service/src/test/.../RecordServiceTest.kt | Server, service | 13 | server |
server/service/src/test/.../AuthServiceTest.kt | Server, service | 13 | server |
server/service/src/test/.../EnrollmentServiceTest.kt | Server, service | 6 | server |
server/service/src/test/.../RecoveryServiceTest.kt | Server, service | 6 | server |
server/service/src/test/.../GroupCreationTest.kt | Server, service | 9 | server |
server/service/src/test/.../PurchasesTest.kt | Server, service | 8 | server |
server/service/src/test/.../InMemoryAuthStoreTest.kt | Server, service | 16 (AuthStoreContract) | server |
server/service/src/test/.../RootKeyServiceTest.kt | Server, service | 13 | server |
server/service/src/test/.../RateLimitTest.kt | Server, service | 9 | server |
server/service/src/test/.../MaintenanceTest.kt | Server, service | 5 | server |
server/service/src/test/.../InMemoryRecordStoreTest.kt | Server, service | 8 (RecordStoreContract) | server |
server/service/src/test/.../InMemoryPromoStoreTest.kt | Server, service | 10 (PromoStoreContract) | server |
server/service/src/test/.../PromoTest.kt | Server, service | 8 (PromoCodesTest 3, PromoVerifierTest 5) | server |
server/postgres/src/test/.../PostgresDatabaseTest.kt | Server, Postgres adapter | 5 | server |
server/postgres/src/test/.../PostgresSettingsTest.kt | Server, Postgres adapter | 3 | server |
server/postgres/src/test/.../PostgresGroupStoreTest.kt | Server, Postgres adapter | 16 (GroupStoreContract) | server |
server/dev/src/test/.../DevelopmentVerifierTest.kt | Server, development build | 3 | server |
server/postgres/src/test/.../PostgresRecordStoreTest.kt | Server, Postgres adapter | 8 (RecordStoreContract) | server |
server/postgres/src/test/.../PostgresAuthStoreTest.kt | Server, Postgres adapter | 16 (AuthStoreContract) | server |
server/postgres/src/test/.../PostgresPromoStoreTest.kt | Server, Postgres adapter | 10 (PromoStoreContract) | server |
syncApi/src/commonTest/.../SyncApiTest.kt | Sync API | 7 | server |
syncApi/src/commonTest/.../SyncStatementsTest.kt | Sync API | 7 | server |
server/src/test/.../ApplicationTest.kt | Server, Ktor adapter | 3 | server (testRoot is the template placeholder) |
server/src/test/.../WiringTest.kt | Server, Ktor adapter | 3 | server |
server/src/test/.../SyncRoutesTest.kt | Server, Ktor adapter | 12 | server |
server/src/test/.../PromoToolTest.kt | Server, Ktor adapter | 5 | server |
server/src/test/.../AuthRoutesTest.kt | Server, Ktor adapter | 14 | server |
server/src/test/.../RootKeyRoutesTest.kt | Server, Ktor adapter | 6 | server |
server/src/test/.../RateLimitRoutesTest.kt | Server, Ktor adapter | 12 | server |
Totals: 169 shared tests (66 common, 103 JVM), 43 Android device tests (42 UI, 1 integration), 12 Android screenshots, 46 iOS tests (44 UI, 2 integration), 13 iOS snapshots, 34 desktop tests (27 UI, 3 database, 4 Keychain), 263 server tests (149 service, 57 Postgres adapter, 54 Ktor adapter, 3 development build), 14 sync API tests.