bitchat-android/docs/testing-conventions.md
heyaim 2fc6f47472
Clear unsent chat text when panic wipe is confirmed (#1027)
The chat screen stored the unsent message separately from the state cleared
by panic wipe, leaving old text visible after completion. Mention
suggestions could also put text back into the cleared input.

Cleared the input and its command and mention suggestions when the user
confirms the wipe. Rejected mention selections when suggestions are hidden
or the nickname is no longer in the current list, including older click
handlers and rows still visible during their closing animation.
2026-11-06 15:54:31 -08:00

3.1 KiB

Testing conventions

Purpose

These conventions keep the client-rewrite suite deterministic, reproducible, and portable across implementations.

Test locations

Test type Location Naming
JVM unit and contract tests app/src/test/ *Test.kt
Shared deterministic fakes and fixtures app/src/test/**/testsupport/ Descriptive fixture name
Robolectric tests app/src/test/ *RobolectricTest.kt
Android instrumented tests app/src/androidTest/ *InstrumentedTest.kt
Coverage-tool tests tools/coverage/ test_*.py
Interoperability fixtures app/src/test/resources/contracts/ Protocol and version in filename

Required behavior

  • Tests must not use arbitrary sleeps. Advance a fake clock or coroutine test scheduler instead.
  • Tests must not require public relays, internet access, Bluetooth hardware, or a user's persisted data.
  • Time, randomness, dispatchers, storage, and transports must be injectable in code exercised by state-machine tests.
  • Randomized failures must print a reproduction seed. Use TEST_SEED for a specific replay.
  • Mutable byte arrays returned by fixtures and fakes must be defensively copied.
  • Negative security tests must assert fail-closed behavior.
  • Protocol round trips must be paired with literal golden vectors for critical externally visible formats.
  • Asynchronous tests must have a deterministic completion condition and a bounded timeout.
  • A fixed bug must retain its smallest reproducing input as a regression test.

Naming

Test names should describe observable behavior:

@Test
fun `replayed ciphertext is rejected without advancing receive state`() {
    // ...
}

Avoid names tied to private methods or temporary implementation structure.

Fixtures and seeds

Reusable Kotlin fixtures live under com.bitchat.android.testsupport. ReproducibleTestSeed resolves TEST_SEED and provides a reproduction hint:

TEST_SEED=12345 ./gradlew clientRewriteContractTest

Never use production keys, contact information, messages, or other user data in fixtures.

Coverage

Run the full report and non-regression floor:

./gradlew clientRewriteContractTest

Reports are written to:

  • app/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml
  • app/build/reports/jacoco/jacocoTestReport/html/

Check executable production lines changed from the base branch:

COVERAGE_BASE_REF=origin/main ./gradlew checkChangedLineCoverage

Generated resource classes, Compose-generated singleton classes, platform bridges, and vendored Noise code are excluded from first-party coverage metrics.

Quarantine and skips

  • A flaky test must be fixed, not silently retried.
  • A temporary quarantine must include an issue and removal condition.
  • Unexpected skips fail review. Existing skips must be restored or replaced by equivalent coverage.

Composer UI regression

The composer panic regression runs locally in a disposable emulator with a separate installation and blocked external egress. This destructive UI suite is opt-in; default JVM and CI commands do not execute it.