test: align resource availability metadata
Backend verify / commits (push) Skipped
Backend verify / security (push) Successful in 13s
Backend verify / verify (push) Failing after 6m21s

This commit was merged in pull request #50.
This commit is contained in:
2026-10-09 23:10:50 +03:00
committed by ksv741
parent 947ffefa9b
commit bc631e72de
9 changed files with 62 additions and 39 deletions
@@ -119,7 +119,10 @@ export class IncomeAnalyticsService {
...investmentResourceMeta({
resourceKey: `income/${accountId}/${plan.selected.from}/${plan.selected.to}`,
dataRevision: current.meta.dataRevision,
availability: current.meta.availability,
availability:
current.items === null
? 'temporarily-unavailable'
: 'available',
fetchedAt: current.meta.lastSuccessfulAt
? new Date(current.meta.lastSuccessfulAt)
: null,
@@ -113,6 +113,11 @@ function availability(value: LegacyAvailability, work: Work) {
return value;
}
if (value === 'complete') return 'available' as const;
if (value === 'partial') {
return work?.state === 'running'
? ('initial-loading' as const)
: ('temporarily-unavailable' as const);
}
return work?.state === 'running'
? ('initial-loading' as const)
: ('temporarily-unavailable' as const);
@@ -194,6 +194,7 @@ describe('persistent portfolio projection', () => {
const partial = await service.read('user', 'all');
expect(partial.data).toBeNull();
expect(partial.meta.availability).toBe('temporarily-unavailable');
expect(partial.meta.completeness).toBe('incomplete');
const saved = await service.saved('user', 'all');
expect(saved.accounts[0].snapshot?.totalsByCurrency).toEqual(
snapshot.totalsByCurrency,
@@ -32,6 +32,7 @@ import { mapPortfolio } from '../infrastructure/tbank-portfolio.mapper';
import { PortfolioDto } from '../presentation/portfolio.dto';
const MISSING_DATA_REVISION = 0;
const NO_ACCOUNTS = 0;
const membershipFreshForMs = tbankSourceTtlMs.membership;
@@ -113,7 +114,11 @@ export class PortfolioService {
const { hourly, ...saved } = await this.saved(userId, accountId);
const missing =
saved.membership.completeness === 'incomplete' ||
saved.accounts.some((account) => !account.snapshot);
(saved.accounts.length > NO_ACCOUNTS && saved.accounts.some((account) => !account.snapshot));
const available =
!missing &&
(saved.membership.availability === 'available' ||
saved.accounts.some((account) => account.snapshot));
const metadata = await this.metadata.savedMany(
saved.accounts.flatMap((account) => account.snapshot?.positions ?? []),
);
@@ -162,6 +167,11 @@ export class PortfolioService {
]
: [],
);
let availability: 'available' | 'complete' | 'missing' | 'partial';
if (available) availability = 'available';
else if (!missing) availability = 'complete';
else if (portfolios.length > NO_ACCOUNTS) availability = 'partial';
else availability = 'missing';
const lastSuccessfulAt =
// eslint-disable-next-line sonarjs/no-alphabetical-sort -- Code-unit ordering is intentional for canonical keys and ISO dates; locale collation would change persisted bindings.
portfolios.map((portfolio) => portfolio.lastSuccessfulAt).sort()[0] ??
@@ -205,11 +215,7 @@ export class PortfolioService {
]),
metadataDependencies.map((dependency) => dependency.dataRevision),
]),
availability: missing
? portfolios.length
? 'partial'
: 'missing'
: 'complete',
availability,
fetchedAt: lastSuccessfulAt ? new Date(lastSuccessfulAt) : null,
freshForMs: portfolios.length
? portfolioFreshForMs