Skip to content

test(dada-client): characterize the untested surface (LIVE-35224) - #20276

Merged
LucasWerey merged 2 commits into
developfrom
test/dada-client-LIVE-35224-characterization-tests
Aug 3, 2026
Merged

test(dada-client): characterize the untested surface (LIVE-35224)#20276
LucasWerey merged 2 commits into
developfrom
test/dada-client-LIVE-35224-characterization-tests

Conversation

@LucasWerey

@LucasWerey LucasWerey commented Jul 31, 2026

Copy link
Copy Markdown
Member

✅ Checklist

  • npx changeset was attached.
  • Covered by automatic tests. This PR is the tests.
  • Impact of the changes:
    - No runtime impact — no production code was changed. The diff is 11 new test files plus a changeset.
    - CI signal only: the src/dada-client suite goes from 10 suites / 96 tests to 21 suites / 245 tests.
    - No QA pass needed. Nothing to test in the apps.

📝 Description

Problem. 14 source files under libs/ledger-live-common/src/dada-client had no colocated test, and the one existing api test covered only buildAssetsQueryParams and the two fetchAll*ByCategory helpers — not the RTK Query endpoints, getChunkedAssetsData, convertApiAssets, or transformAssetsResponse. The package is about to be relocated into DDD packages under LIVE-35223, and a green CI run would not have proven that relocation behaviour-neutral. The riskiest code in the package is also the least typed: createCurrencyDataSelector walks RTK Query's internal cache layout (queries[*].data.pages[*][key][id]) on Record<string, unknown>, so no refactor there can ever produce a type error.

Solution. 149 characterization tests pinning current behaviour, with no production change. These become the contract for the rest of the migration epic: they must keep passing unmodified, and a test that needs editing to accommodate a later change signals broken behaviour rather than a wrong test.

File Tests Pins
state-manager/__tests__/apiTransforms.test.ts 30 convertApiAssets, transformAssetsResponse, getChunkedAssetsData
hooks/__tests__/useMarketByCurrencies.test.tsx 19 both-fields-required, float rounding
entities/__tests__/selectorUtils.test.ts 16 cache-shape walk, cross-query bleed, first-match-wins, falsy-as-absent
utils/__test__/mergeAssetsDataPages.test.ts 13 shallow merge, last-page-wins, no input mutation
hooks/__tests__/useInterestRatesByCurrencies.test.tsx 13 APY-type allowlist, zero-is-a-value, isEqual stability
hooks/__tests__/useStockAssetIds.test.ts 13 Set wrapping, shared empty-set identity
hooks/__tests__/useDrawerConfiguration.test.ts 13 flag gating, config precedence
hooks/__tests__/useAssetData.test.ts 11 param narrowing, isLoading ‖ isFetching
hooks/__tests__/useChunkedAssetsData.test.ts 11 skip separation, full ErrorInfo shape
entities/__tests__/interestRateSelectors.test.ts 5 reads interestRates only
entities/__tests__/marketSelectors.test.ts 5 reads markets only

Four invariants that break silently are now pinned executably, since none of them can produce a type error:

  1. assetsDataApi.reducerPath is the literal string "assetsDataApi" — read by string in selectorUtils.ts:25 and preloaded by three Storybook files.
  2. The cache selectors scan every cache entry regardless of query args, so a value cached by one query is served to callers of another. Characterized, not endorsed.
  3. convertApiAssets is deliberately lenient: it silently drops tokens whose parent chain is unknown, and synthesises a currency (color: "#999999", explorerViews: []) for cryptos missing from the local registry rather than dropping them.
  4. getChunkedAssetsData succeeds if any chunk resolves.

The contract already proved itself

This branch was rebased onto 59 new develop commits, two of which changed dada-client production code (perf(modular-drawer): forward network filters to dada, adding networkIds to GetAssetsDataParams and buildAssetsQueryParams). Every characterization test passed unmodified through that rebase.

That change did open one gap, closed by the second commit here: networkIds also flows through getChunkedAssetsData, where — unlike currencyIds, which is split across chunks — it must be repeated in full on every request. buildAssetsQueryParams is covered by that change's own tests, but the chunked path's forwarding was not. Exactly the kind of detail a relocation drops silently.

Notes for reviewers

  • convertApiAssets, transformAssetsResponse and emptyAssetsData are module-private and this task must not touch production code, so they are driven through the getAssetData / getChunkedAssetsData endpoints with a real store and a stubbed fetch. That pins the observable contract rather than internals, which is what the migration has to preserve anyway.
  • getAssetData goes through fetchBaseQuery, so fetch receives a Request; the chunked path calls fetch with a string. requestedUrl() normalises both.
  • Bug surfaced, not fixed here: an asset with id: "" makes CryptoCurrencyIdSchema.parse throw and fails the entire query, not just that asset. Pinned as current behaviour in apiTransforms.test.ts; the follow-up validation ticket (LIVE-35233) must not make it worse.
  • The useMarketByCurrencies rounding table was verified against the implementation rather than assumed. Rounding is Math.round(x * 100) / 100, so results follow float representation, not decimal intuition: -2.345 → -2.35, -1.005 → -1, and an exact .5 rounds toward +∞ (0.125 → 0.13 but -0.125 → -0.12).
  • useDrawerConfiguration is tested here although it is not DADA code — it only reads a feature flag. It is misfiled in this directory and gets relocated later in the epic, so it needs the same protection.
  • Known, deliberately unfixed: apiTransforms.test.ts leaves a worker to be force-exited (A worker process has failed to exit gracefully). Several endpoints set keepUnusedDataFor: 86400, which parks a 24-hour timer. Releasing the subscription via unsubscribe() was tried and was not sufficient; the real fix is fake timers or a resetApiState teardown. Left out of scope on purpose so this PR stays tests-only.
  • Changeset is patch on @ledgerhq/live-common — internal-only change, no runtime behaviour affected.

❓ Context


🧐 Checklist for the PR Reviewers

  • The code aligns with the requirements described in the linked JIRA or GitHub issue.
  • The PR description clearly documents the changes made and explains any technical trade-offs or design decisions.
  • There are no undocumented trade-offs, technical debt, or maintainability issues.
  • The PR has been tested thoroughly, and any potential edge cases have been considered and handled.
  • Any new dependencies have been justified and documented.
  • Performance considerations have been taken into account. (changes have been profiled or benchmarked if necessary)

Copilot AI review requested due to automatic review settings July 31, 2026 10:27
@live-github-bot live-github-bot Bot added the common Has changes in live-common label Jul 31, 2026
@live-github-bot live-github-bot Bot changed the title test(dada-client): add characterization tests for untested surface (LIVE-35224) [LWDM] test(dada-client): add characterization tests for untested surface (LIVE-35224) Jul 31, 2026
@LucasWerey LucasWerey changed the title [LWDM] test(dada-client): add characterization tests for untested surface (LIVE-35224) test(dada-client): characterize the untested surface (LIVE-35224) Jul 31, 2026
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Web Tools Build Status

Build Status Deployment
Web Tools Build ✅ Deployed https://web-tools-ojyt4hozo-ledger-hq-prd.vercel.app
Native Storybook Build ⏭️ Skipped
React Storybook Build ⏭️ Skipped

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a comprehensive characterization-test suite around libs/ledger-live-common/src/dada-client to pin current behavior ahead of the planned DDD relocation/migration, without modifying production runtime code.

Changes:

  • Add characterization tests for selector cache-walk behavior, API transforms, and RTK Query endpoints under src/dada-client.
  • Add hook-level tests for query-arg shaping, loading/error semantics, memoization/stability guarantees, and edge cases.
  • Add a patch changeset for @ledgerhq/live-common reflecting the test-only addition.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
libs/ledger-live-common/src/dada-client/utils/test/mergeAssetsDataPages.test.ts Characterizes merging semantics for paged assets data (shallow merge, last-write wins, pagination/currenciesOrder behavior).
libs/ledger-live-common/src/dada-client/state-manager/tests/apiTransforms.test.ts Exercises public RTK Query endpoints to characterize private transform/conversion behaviors and chunked fetching semantics.
libs/ledger-live-common/src/dada-client/hooks/tests/useStockAssetIds.test.ts Pins query args + Set-wrapping/memoization behavior for stock asset IDs hook.
libs/ledger-live-common/src/dada-client/hooks/tests/useMarketByCurrencies.test.tsx Pins selection/filtering + rounding behavior for market data hook and reference stability.
libs/ledger-live-common/src/dada-client/hooks/tests/useInterestRatesByCurrencies.test.tsx Pins allowlist/type filtering, zero-is-value semantics, and reference stability for interest rate hook.
libs/ledger-live-common/src/dada-client/hooks/tests/useDrawerConfiguration.test.ts Characterizes feature-flag-driven drawer configuration precedence/merging and callback stability.
libs/ledger-live-common/src/dada-client/hooks/tests/useChunkedAssetsData.test.ts Pins param shaping (skip separation), loading-state semantics, and ErrorInfo parsing.
libs/ledger-live-common/src/dada-client/hooks/tests/useAssetData.test.ts Pins param narrowing behavior and `isLoading
libs/ledger-live-common/src/dada-client/entities/tests/selectorUtils.test.ts Characterizes RTK Query cache-shape walk semantics and cross-query “first match wins” behavior.
libs/ledger-live-common/src/dada-client/entities/tests/marketSelectors.test.ts Pins selector reads-only-from-markets behavior and empty/partial handling.
libs/ledger-live-common/src/dada-client/entities/tests/interestRateSelectors.test.ts Pins selector reads-only-from-interestRates behavior and empty/field-preservation semantics.
.changeset/lucky-mirrors-observe.md Patch changeset noting added characterization tests in @ledgerhq/live-common.

@github-actions

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

Found 7 projects in monorepo, 7 projects with changes.

📊 Quick Summary
Project Total Size Change
desktop-main 2.3 MB -
desktop-preloader 7.1 KB -
desktop-renderer 80.6 MB -
desktop-webviewDappPreloader 36.9 KB -
desktop-webviewPreloader 200.0 B -
desktop-workers 36.8 KB -
mobile 261.3 MB -
📋 Detailed Reports (Click to expand)

📁 desktop-main

Path: rsdoctor/desktop-main/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 2.3 MB - -
📄 JavaScript 2.2 MB - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 135.3 KB - -

📁 desktop-preloader

Path: rsdoctor/desktop-preloader/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 7.1 KB - -
📄 JavaScript 5.3 KB - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 1.8 KB - -

📁 desktop-renderer

Path: rsdoctor/desktop-renderer/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 80.6 MB - -
📄 JavaScript 29.3 MB - -
🎨 CSS 183.1 KB - -
🌐 HTML 1.8 KB - -
📁 Other Assets 51.2 MB - -

📁 desktop-webviewDappPreloader

Path: rsdoctor/desktop-webviewDappPreloader/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 36.9 KB - -
📄 JavaScript 36.9 KB - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 0 B - -

📁 desktop-webviewPreloader

Path: rsdoctor/desktop-webviewPreloader/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 200.0 B - -
📄 JavaScript 200.0 B - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 0 B - -

📁 desktop-workers

Path: rsdoctor/desktop-workers/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 36.8 KB - -
📄 JavaScript 36.8 KB - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 0 B - -

📁 mobile

Path: rsdoctor/mobile/rsdoctor-data.json

⚠️ No baseline data found - Unable to perform comparison analysis

Metric Current Baseline Change
📊 Total Size 261.3 MB - -
📄 JavaScript 110.4 MB - -
🎨 CSS 0 B - -
🌐 HTML 0 B - -
📁 Other Assets 150.9 MB - -

Generated by Rsdoctor GitHub Action

Pin current behaviour of the dada-client code that had no test coverage, as
the safety net for the upcoming DDD relocation (LIVE-35223). No production
code changed.

Covers the cache-shape selectors, the RTK Query wrapper hooks and the API
transforms. convertApiAssets, transformAssetsResponse and emptyAssetsData are
module-private, so they are characterized through the getAssetData and
getChunkedAssetsData endpoints with a real store and a stubbed fetch.

These tests must keep passing unmodified through the migration: one that needs
editing to accommodate a later change signals broken behaviour, not a wrong
test.
develop added networkIds to GetAssetsDataParams after this branch was written
(perf(modular-drawer): forward network filters to dada). buildAssetsQueryParams
is covered by that change's own tests, but the chunked endpoint's forwarding was
not: networkIds must be repeated in full on every chunk while currencyIds are
split. Pin it so the DDD relocation cannot silently drop it.
Copilot AI review requested due to automatic review settings July 31, 2026 12:10
@LucasWerey
LucasWerey force-pushed the test/dada-client-LIVE-35224-characterization-tests branch from 3bbb92b to dd341f2 Compare July 31, 2026 12:10
@LucasWerey
LucasWerey marked this pull request as ready for review July 31, 2026 12:14
@LucasWerey
LucasWerey requested a review from a team as a code owner July 31, 2026 12:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

Suppressed comments (3)

libs/ledger-live-common/src/dada-client/state-manager/tests/apiTransforms.test.ts:100

  • Avoid jest.restoreAllMocks() here: it restores all spies/mocks (including those installed by global jest setup), which can break unrelated tests when running the suite in parallel. Prefer restoring only the local fetchSpy for this file.
afterEach(() => {
  jest.restoreAllMocks();
});

libs/ledger-live-common/src/dada-client/state-manager/tests/apiTransforms.test.ts:96

  • jest.spyOn(globalThis, "fetch") will call the real undici fetch when a test forgets to stub a response, which can accidentally hit the network and make failures slow/flaky. It’s safer for this suite to default fetch to throwing unless a test explicitly mockResolvedValueOnce/mockRejectedValueOnce.
beforeEach(() => {
  fetchSpy = jest.spyOn(globalThis, "fetch");
});

libs/ledger-live-common/src/dada-client/hooks/tests/useDrawerConfiguration.test.ts:15

  • This test mocks useFeature, but useFeature is a Redux selector hook (it uses useSelector). Repo testing guidance prefers exercising feature flags via a store state (e.g., a Provider + featureFlags.resolved.ptxEarnDrawerConfiguration) rather than mocking the hook, so the test better reflects real behavior and avoids mock drift.
import { useFeature } from "@features/platform-feature-flags";
import { useDrawerConfiguration } from "../useDrawerConfiguration";

jest.mock("@features/platform-feature-flags", () => ({ useFeature: jest.fn() }));

const mockUseFeature = jest.mocked(useFeature);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const flag = (value: unknown) => mockUseFeature.mockReturnValue(value as any);

@sonarqubecloud

Copy link
Copy Markdown

@LucasWerey
LucasWerey merged commit e0f5629 into develop Aug 3, 2026
133 of 136 checks passed
@LucasWerey
LucasWerey deleted the test/dada-client-LIVE-35224-characterization-tests branch August 3, 2026 07:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

common Has changes in live-common

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants