Skip to content

Tier 1: complete integration-test coverage for every multi-layer flow #542

@TaprootFreak

Description

@TaprootFreak

Context

test/integration/ contains exactly one spec today (kyc_sign_flow_test.dart, added in #320). The Tier-1 definition is in docs/testing.md:8 and docs/testing.md:270:

Tier 1 — cubit / widget + SDK-boundary fake. Sign ceremonies via FakeBitboxCredentials; HTTP via MockClient from http/testing. Pre-seed JWT via getAuthToken()loadSignature()getAuthResponse().

docs/testing.md:307-310 adds the rule:

Crosses ≥ 2 production layers AND uses the FakeBitboxCredentials boundary. Runs headless, no device. A behaviour change in any of the layers should break it.

The first version of this issue listed 11 candidate flows. Eight of them do not touch the BitBox boundary at all — they don't qualify as Tier 1 under the repo's own definition. This revision keeps only the 3 that do.

How kyc_sign_flow_test.dart actually looks

The cited "reference template" wires FakeBitboxCredentials → Eip712Signer.signRegistration — one static method, one production type. It is not a cross-layer template. Use it as a fake-Bitbox example, not as a Tier-1-layered example. The first cross-layer Tier-1 spec is the work this issue creates.

Scope — true Tier-1 candidates only

Each candidate below was verified against the source. To qualify it must (a) cross ≥ 2 production layers and (b) hit the BitboxCredentials boundary so FakeBitboxCredentials is the right test seam. HTTP is mocked at the boundary per docs/testing.md:106 (MockClient + pre-seeded JWT).

In scope — 3 specs

  • kyc_registration_flow_test.dart — extend the existing signer-only spec into the multi-layer ceremony: KycRegistrationSubmitCubit → RealUnitRegistrationService → DfxAuthService → Eip712Signer → FakeBitboxCredentials. Covers the full registration submission path including BitboxNotConnectedException branch and KYC_LEVEL_REQUIRED mapping (already covered by Tier 0 service tests, but not as a multi-layer assertion).
  • sell_bitbox_flow_test.dartSellBitboxCubit → BitboxCredentials.signToSignature (EVM tx sign with chainId + isEIP1559, lib/screens/sell_bitbox/cubit/sell_bitbox_cubit.dart:193). Covers the full sell-BitBox sign ceremony including the four FakeBitboxBehavior failure modes (cancel, disconnect, timeout, malformed).
  • auth_sign_flow_test.dartDfxAuthService.signMessage lazy-fetch + 401 retry, driven through FakeBitboxCredentials. This is the common dependency for buy/sell/KYC flows (every authenticated DFX call walks this path on a cold cache). One cross-layer spec here covers regression for all consumers. Overlap note: at Tier 2 (Tier 2: extend BitBox02 firmware simulator beyond hardware_connect_bitbox #548), EthSignMessageAscii/EthSignMessageBoundary already exercise the firmware-side of signPersonalMessage. The Tier 1 spec covers the Dart-side multi-layer composition (cubit → service → signer) — distinct from Tier 2's "firmware accepts the payload bytes" assertion. Both layers are intentional.

Out of scope — these are not Tier-1 candidates

Each of the following was in the prior version of this issue. They are cubit/service cross-layer flows that do not touch BitBoxFakeBitboxCredentials is the wrong seam and they belong elsewhere (Tier 0 cross-layer test under test/, or a different ticket entirely).

  • buy_flow_test.dartBuyPaymentInfoCubit (lib/screens/buy/cubits/buy_payment_info/buy_payment_info_cubit.dart) emits BuyPaymentInfoFailure(PaymentInfoError.bitboxDisconnected) but the actual sign is DfxAuthService.signMessage (covered by the auth_sign_flow_test.dart above).
  • sell_flow_test.dart — same pattern as buy.
  • restore_wallet_flow_test.dartRestoreWalletCubit(_walletService, _authService) takes no BitboxCredentials. Pure software-wallet seed restore (bip39.validateMnemonic).
  • pin_lockout_flow_test.dartPinAuthCubit uses lockoutDuration from pin_constants.dart. No BitBox.
  • receive_flow_test.dart — derives address from wallet.currentAccount.primaryAddress. No sign ceremony.
  • transaction_history_flow_test.dart — API + DB, no BitBox.
  • support_chat_flow_test.dartDfxSupportService.sendMessage(ticketUid, message). No attachment-upload code path exists.
  • kyc_email_step_flow_test.dart — code/email-link only; only KYC registration (above) touches BitBox.
  • kyc_financial_data_flow_test.dartKycFinancialDataCubitKycService.getFinancialData(url); no BitBox.
  • delete_wallet_flow_test.dartWalletService.deleteCurrentWallet() at lib/packages/service/wallet_service.dart:275 only calls _repository.deleteWallet(id) + _settingsRepository.removeCurrentWalletId(). Does NOT clear all storages and does NOT stop the BitBox observer.

A separate cross-layer "test/" ticket (without FakeBitboxCredentials) could cover the eight removed flows if there's appetite — but they are not Tier-1.

Acceptance criteria

  • Each spec uses FakeBitboxCredentials at the BitBox boundary
  • HTTP via MockClient from package:http/testing, JWT pre-seeded (docs/testing.md:106-108)
  • Storage layer uses Drift in-memory (no platform channels)
  • Each spec asserts the happy path and at least three of the four FakeBitboxBehavior failure modes (cancel, disconnect, timeout, malformed) — success is the happy path
  • All specs run inside the existing Analyze & Test job (today ~7-9 min, timeout-minutes: 30)
  • The .coverage-floor-lines is currently 94; Tier-1 specs exercise lines already covered by Tier 0 (services + cubits already at 100 % activated-surface), so they will not move the scoped line coverage — do not commit a floor bump

Dependencies

Estimated effort

Spec Days
kyc_registration_flow_test.dart (extend existing signer-only into multi-layer) 1.0
sell_bitbox_flow_test.dart (4 behavior modes + EIP-1559 payload assertion) 1.0
auth_sign_flow_test.dart (lazy-fetch + 401 retry + JWT seeding) 0.5-1.0
Documentation + cross-link from docs/testing.md 0.25
Total ~3 engineer-days

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions