Expand Dart test coverage 167 → 292 tests - #100
Merged
Conversation
AdEvent: enum ↔ string round-trip for every known event, unknown fallback, payload parsing (top-level code + nested payload for clicked/viewed/error), null/missing payload handling, malformed payload swallowed into .unknown, copyWith override semantics, and the skip-code constants that make up the server contract. Character: toJson required fields, optional omission, full field serialisation, additionalProperties merge (including the key-collision rule where additionalProperties wins). Message: isUser/isAssistant, toJson uses role.name + ISO-8601 UTC (converts local DateTime), equality uses (id, role, content) not createdAt, inequality on each field, identity, non-Message check. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Covers every class under lib/src/device_app_info/ using TestDefaultBinaryMessengerBinding.setMockMethodCallHandler to stub platform channels: - DeviceAudio: empty(), full response decode (volume rounding + outputType list), every AudioOutputType mapped, unknown types fall back to .other, PlatformException → empty, toJson omits nulls. - DevicePower: empty(), full response, every BatteryState, unknown state → .unknown, integer level widens to double, exception → empty, toJson uses enum name. - DeviceNetwork: empty(), full decode, every NetworkType, unknown → null, exception → empty, toJson emits enum name + omits nulls. - DeviceScreen: empty() zeros + portrait default, init() returns non-negative dimensions under the test binding, toJson shape. - DeviceHardware: empty(), toJson type pass-through, init() does not throw under the test binding (DeviceType varies by host platform, so assert isA<DeviceType> rather than a specific case). - OperationSystem: empty(), init() returns well-formed OS info under the test binding, exception fallback to empty. - AppInfo: empty() + safe defaults, init() does not throw under the test binding, storeUrl remains null on non-iOS/Android hosts. - DeviceAppInfo: empty() aggregates sub-empties, toJson shape, toJsonFresh invokes screen/audio init, init() is memoised (identity-equal across repeated calls). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TransparencyConsentFrameworkService: full channel mocking — valid shape, gdpr=0, non-0/1 gdprApplies → null, non-int or empty/non-string tcString → null, null-response handling, exception fallback. SKOverlayService: uses the injectable `isIOS` hook for full coverage — non-iOS short-circuit, empty-itunesItem short-circuit, forwards skan/ position/dismissible, false-result passthrough, UNSUPPORTED_IOS swallowed, any PlatformException swallowed, dismiss happy path + non-iOS short-circuit + error path. SKStoreProductService: non-iOS short-circuit, channel forwarding, native false/throw cases, dismiss paths. TrackingAuthorizationService: notSupported on non-iOS, enum index mapping for each TrackingStatus, value-list coverage. SKAdNetwork and AdAttributionKit: non-iOS short-circuit for every public method (initImpression/startImpression/endImpression/dispose, and initImpression/setAttributionFrame/handleTap/beginView/endView/ dispose respectively). The iOS code path is guarded by Platform.isIOS which cannot be flipped from a Dart test; that coverage lives in the respective native tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
selectBid: placement-not-enabled, code-not-matched, happy path, relevantAssistantMessageId precedence over lastAssistantMessageId, not-ready → null, mismatched messageId → null, afterUser branch (ready/not-ready/mismatch), first-bid-wins when duplicate codes. useLastMessages hook: empty list resets every setter; assistant-last emits ids and readyForStreaming=true; user-last sets readyForStreaming=false; relevantAssistantMessageId resets on a new user message id; no reset when the id is unchanged. AdsProviderData: .of returns the nearest ancestor or null; updateShouldNotify returns false on equal values and true on any of the tracked field changes (adServerUrl, isDisabled, the two readyForStreaming flags, each messageId, messages/bids/placements list, and otherParams map); deep-equal messages list and deep-equal otherParams do not retrigger. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drives the full Api → HttpClient → http.Client pipeline end-to-end with only the outermost http.Client mocked. This proves the wire contract that publishers rely on. - happy path: POSTs to /preload, publisher-token and is-disabled headers, body fields (publisherToken, conversationId, userId, enabledPlacementCodes, messages), bids decoded - isDisabled=true sends Kontextso-Is-Disabled: 1 - skip:true response propagates to PreloadResponse.skip/skipCode - network throw falls back to an empty PreloadResponse - 5xx surfaces statusCode in the response - TCF platform-channel data is merged into regulatory (gdpr + gdprConsent) without clobbering publisher-provided fields (coppa) - character/variantId/userEmail passthrough - sessionId persists across consecutive preloads when passed in Widget-level integration (AdsProvider + messages → triggered preload) was attempted but ended up flaky because AdsProvider is a HookWidget that resets HttpClient on mount; reliable simulation of the hook-driven rebuild + async preload timing in flutter_test is fragile. The API-layer integration above covers the same HTTP contract with no timing sensitivity. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- integration_test.dart: drop unused bid.dart import - message_test.dart: ignore unrelated_type_equality_checks on the "Message != non-Message" assertion (the whole point of the test) - select_bid_test.dart: flip makeData defaults to false/[] so every test explicitly opts in to the flag it exercises — removes 7 avoid_redundant_argument_values warnings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Grows Dart-side test coverage from 167 → 292 tests across every class in
lib/src/. Matches the depth we already have insdk-js,sdk-common,sdk-react-native, andsdk-swift. Full suite runs in ~30 s locally.Coverage by area
test/src/models/test/src/device_app_info/test/src/services/test/src/widgets/andwidgets/utils/test/src/integration_test.dartFile-by-file audit
Covered directly (this PR)
device_app_info/*.dart— all 8 files with a dedicated testmodels/ad_event.dart,character.dart,message.dartservices/sk_ad_network_service.dart,sk_overlay_service.dart,sk_store_product_service.dart,tracking_authorization_service.dart,transparency_consent_framework_service.dart,ad_attribution_kit_service.dartwidgets/ads_provider_data.dartwidgets/utils/select_bid.dart,use_last_messages.dartCovered by existing tests
models/bid.dart,regulatory.dartservices/advertising_id_service.dart,api.dart,http_client.dart,logger.dartutils/extensions.dart,helper_methods.dart,kontext_url_builder.dart,types.dartwidgets/ad_format.dart,ads_provider.dart,inline_ad.dart,interstitial_modal.dart,webview_console_error_limiter.dartwidgets/utils/use_preload_ads.dartIntentionally uncovered
lib/kontext_flutter_sdk.dart— public barrel file, only re-exportslib/src/main.dart— re-exportslib/src/utils/constants.dart— const values onlylib/src/utils/browser_opener.dart— 3-lineChromeSafariBrowserwrapper; not worth the native-mock plumbinglib/src/widgets/kontext_webview.dart— WebView shell, requires platform UIIntegration tests
test/src/integration_test.dartexercises the realApi→HttpClient→http.Clientpipeline end-to-end with only the outermost HTTP client mocked:/preload, correct token + is-disabled headers, body fields (publisherToken, conversationId, userId, enabledPlacementCodes, messages), bids decodedisDisabled: true→Kontextso-Is-Disabled: 1PreloadResponseA widget-level integration test (AdsProvider + message → triggered preload) was attempted but ended up flaky — AdsProvider's hooks reset
HttpClienton mount and the async preload timing isn't reliable underflutter_test. The API-layer integration above covers the same HTTP contract without timing sensitivity.Running
flutter test ./testTest plan
lib/src/file either has a dedicated test or is documented above as intentionally uncovered🤖 Generated with Claude Code