Skip to content

Add conversion rate service tests and enhancements - #1290

Merged
pope-h merged 52 commits into
Shelterflex:mainfrom
Nemenwa:PII
Jul 4, 2026
Merged

Add conversion rate service tests and enhancements#1290
pope-h merged 52 commits into
Shelterflex:mainfrom
Nemenwa:PII

Conversation

@Nemenwa

@Nemenwa Nemenwa commented Jun 29, 2026

Copy link
Copy Markdown
Contributor
  • Enhance ConversionRateService with clock injection, hard staleness limit, and sanity bounds
  • Add provider failure fallback to stale cache within hard staleness limit
  • Add comprehensive unit tests (24 tests) covering caching, staleness, fallback, and sanity bounds
  • Ensure no redundant upstream calls within TTL
  • Surface staleness to callers via isStale flag
  • Reject absurd rates (zero, negative, infinite, NaN, outside bounds)

Summary

closes #1204
closes #1191
closes #1187

Briefly describe the change. This section is required for CI PR validation.
If this is a contract upgrade, include:

  • Which contract is being upgraded
  • Why the upgrade is needed
  • Link to any discussion/issues

Linked issue (recommended)

Example: Closes #123

Changes

This section is required for CI PR validation.

Contract Upgrade Details (if applicable)

This section is required for CI PR validation if this is a contract upgrade.

Network

  • Testnet
  • Mainnet

New Contract

  • Contract ID: C...
  • WASM Hash: sha256:...
  • Deployer Public Key: G...
  • Deploy Transaction: [link to transaction explorer]

Upgrade Governance

  • Admin/upgrade authority is a multisig requiring maintainer sign-off
  • Maintainer has reviewed and approved the upgrade
  • Upgrade transaction is ready for maintainer signature (provide transaction XDR if applicable)

Verification Steps

  • New contract deployed successfully
  • All existing tests pass against the new contract
  • Manual testing checklist completed (describe what you tested)
  • No breaking changes for existing integrations (or list them)

How to test

This section is required for CI PR validation.

  • All automated tests pass
  • Integration tests pass (if applicable)
  • Manual testing completed (describe what you tested)

Security Considerations

This section is required for CI PR validation.

  • No secrets or sensitive data are logged
  • No changes to authentication/authorization logic without review
  • No changes to admin/upgrade logic without review

Screenshots (if UI)

Include before/after screenshots for any UI changes. For new features, show different states (loading, error, success). For responsive changes, include mobile/tablet/desktop views.

Checklist

This section is required for CI PR validation.

  • I linked an issue (or explained why one is not needed)
  • I tested locally
  • I did not commit secrets
  • I updated docs if needed
  • Code follows the project's style guidelines
  • CI checks pass
  • If UI changes: I included before/after screenshots
  • If images added/changed: I verified they are optimized and accessible

- Enhance ConversionRateService with clock injection, hard staleness limit, and sanity bounds
- Add provider failure fallback to stale cache within hard staleness limit
- Add comprehensive unit tests (24 tests) covering caching, staleness, fallback, and sanity bounds
- Ensure no redundant upstream calls within TTL
- Surface staleness to callers via isStale flag
- Reject absurd rates (zero, negative, infinite, NaN, outside bounds)
@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

@wokedi is attempting to deploy a commit to the pope-h's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Jun 29, 2026

Copy link
Copy Markdown

@wokedi Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Nemenwa and others added 27 commits July 1, 2026 15:18
- Add client-side validation with magic bytes, MIME type, and size checks
- Implement upload progress tracking and clear state management
- Handle presigned URL expiration with retry logic
- Add accessibility features and safe content rendering
…tests

- Frontend: Add comprehensive validation, draft-safety, and accessibility for property listing form
  - Zod schema validation matching backend PropertyListingPayload requirements
  - Field-level error display with aria-describedby and role=alert
  - Draft autosave to localStorage with 2-second debounce
  - Beforeunload warning to prevent accidental loss of work
  - Server error mapping to specific fields
  - Photo upload with retry on failure
  - Focus management on submit, full keyboard navigation
  - All accessibility: labels, error associations, screen reader support

- Backend: Add tests for lease generation and document-to-signature binding
  - Refactored rentalAgreementStore to Hybrid pattern (in-memory + Postgres)
  - Created leaseDocumentService.test.ts (9 tests)
  - Created rentalAgreementStoreTests.test.ts (8 tests)
  - Test coverage: lease generation, deterministic output, document binding
  - Status lifecycle: DRAFT -> PENDING_SIGNATURES -> FULLY_EXECUTED
  - Stale document prevention via deal ID validation

Tests: 17 passing (9 lease + 8 rental agreement)
Build: frontend builds successfully, 0 ESLint/TypeScript errors
…KYC provider services

Adds the missing test files for three external-dependency services that
gate underwriting and onboarding decisions, plus the minimal seams needed
to make them testable:

- creditBureauService: adds an in-memory creditBureauReportStore fake and
  covers cache/freshness-window reuse, outage/timeout fallback, malformed
  bureau responses, and PII-safe logging.
- backgroundCheckService: adds idempotent re-run support (existingCheckId)
  and adverse-action gating (eligible/adverseReasons recorded via the
  existing verificationMetadata field), with tests for the pending ->
  completed lifecycle, tenant attribution, gating reasons, timeout safety,
  idempotency, and PII-safe logging.
- kycProvider: fixes a real bug where RealKycProvider.webhookAuthenticate
  used require('crypto') inside this ESM package (throws at runtime) and
  hashed the signature into its own payload (making verification
  impossible), then adds coverage for state mapping, fail-safe behavior
  on provider failure, fresh (non-cached) status checks, webhook auth,
  and PII-safe logging.

Closes Shelterflex#1205, Closes Shelterflex#1206, Closes Shelterflex#1207

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add worker.test.ts with exactly-once processing tests
- Add enqueueSideEffects.test.ts with idempotency tests
- Cover failure paths and retryable state
- All 34 tests passing
…ormula injection attacks. Here's what was delivered
- Reject self-referral at application time
- Enforce unique attribution per referred tenant (one referrer max)
- Gate reward credit on a qualifying action (deal activation), not signup
- Add velocity cap: max REFERRAL_VELOCITY_MAX conversions per referrer
  per REFERRAL_VELOCITY_WINDOW_MS window (env-configurable, default 20/24h)
- Make creditRewardForDealActivation idempotent — skips non-pending conversions
- Make applyRewardCredit idempotent — skips already-applied conversions;
  validates existence and uses optimistic-lock UPDATE WHERE status='pending'
- Add ReferralRepository.getConversionById for pre-flight idempotency check
- Add referralService.test.ts covering all anti-fraud and idempotency paths
thewealthyplace and others added 24 commits July 4, 2026 06:09
…#1160)

- assertBonded now enforces MIN_BOND_AMOUNT (env-configurable) in addition
  to the boolean isBonded flag
- Transient Soroban RPC errors (timeout, reset, CHAIN_UNAVAILABLE) cause a
  503 response; non-transient errors fall through to INSPECTOR_NOT_BONDED 403
  — gate always fails safe (deny) when bond status is unknown
- Add in-memory bond status cache with TTL (INSPECTOR_BOND_CACHE_TTL_MS,
  default 30s) to reduce redundant chain calls under load
- clearCache(inspectorId?) invalidates a single entry or the entire cache;
  called automatically after stake/unstake
- Expose getMinBondAmount() for callers that need the threshold
- Add inspectorBondService.test.ts covering: bonded, unbonded, below-min,
  transient RPC failure, non-transient error, cache hit, and cache clear
- Remove hardcoded lang="en" from root <html> so the locale layout can
  inject the correct lang + dir attributes dynamically per locale
- Add RTL CSS utilities to globals.css: flip-rtl helper, ml-auto/ml-64
  mirror overrides, space-x-* reverse, directional Lucide icon flip
- DashboardSidebar: sidebar anchors to right in RTL (rtl:right-0
  rtl:left-auto), border swaps sides (rtl:border-l-3 rtl:border-r-0),
  slide-out direction inverts (rtl:translate-x-full)
- LandlordSidebar: same RTL sidebar positioning adjustments
- SettingsPageSkeleton: same RTL sidebar positioning adjustments
- Header: button hover translate-x flips sign under RTL
  (rtl:hover:-translate-x-0.5) so the neo-brutalist shadow effect is
  correct for right-to-left users
…terflex#1162)

- Attach a stable Idempotency-Key header to every enqueued request so
  flushes are safe to retry and the backend deduplicates them
- Add retryCount to OfflineQueueEntry; cap retries at MAX_RETRIES_PER_ITEM
  (3) so permanently-failed items don't loop forever
- Flush serially with jittered exponential backoff (500ms base, 10s cap);
  transient failures stay queued, permanent 4xx failures are discarded
- isNonRetryable: 4xx errors other than 409/429 are treated as permanent
  and dropped (not re-queued)
- Add FlushStatus / FlushProgress types and emitFlushEvent to broadcast
  offline-flush-progress CustomEvents for UI feedback (idle → replaying
  → completed / partial / failed)
- flushOfflineQueue now accepts an optional onReconcile callback invoked
  after a successful flush so callers can re-sync server state
- offline-queue-updated event detail is now { count: N } (was bare N)
The assertBonded guard now validates amount >= MIN_BOND_AMOUNT (100_000_000
stroops) in addition to the boolean isBonded flag. Tests that exercised the
claim path were staking with amount '500' — well below the threshold — causing
them to receive a correct 403. Update those four stake calls to '100000000' so
they satisfy the configured minimum before attempting to claim.
…ndexer, and scheduled jobs

Addresses issues Shelterflex#1259, Shelterflex#1260, Shelterflex#1261, Shelterflex#1262 by implementing comprehensive test coverage for critical backend security and reliability features.

## OTP Delivery Provider Tests (Shelterflex#1259)
- Factory selection and provider routing (console, email, unsupported)
- OTP code handling and email template generation
- Security controls: plaintext OTP never logged, security warnings included
- Provider abstraction verification

## Timelock Indexer Tests (Shelterflex#1260)
- Worker event ordering and idempotency on duplicate deliveries
- Out-of-order event handling without state regression
- Checkpoint management and recovery
- Error handling and graceful failure recovery
- Lifecycle management and polling correctness

## Timelock Repository Tests (Shelterflex#1260)
- Transaction persistence and retrieval
- Status transitions (queued → executed → cancelled)
- Timestamp management (createdAt preserved, updatedAt updated)
- Checkpoint persistence and consistency
- Idempotency on duplicate operations
- Concurrent operation safety
- Data format preservation (JSON args, large arrays)

## Backup Job Tests (Shelterflex#1261)
- Backup completeness (all datasets included, new stores not silently omitted)
- Integrity verification (timestamped files, .sql format)
- Failure handling (errors logged and surfaced)
- Safety guarantees (no backup clobbering, retention policy enforced)
- Security (credentials and PII never logged)
- Recovery readiness (standardized format, metadata preservation)

## Data Retention Purge Job Tests (Shelterflex#1262)
- Eligible record purge only, legal holds respected
- Idempotency on schedule double-fire
- Failure surfacing and retry capability
- Logging and observability with metrics
- Empty workload handling
- Service integration

## Monthly Deduction Reminder Job Tests (Shelterflex#1262)
- Monthly cycle idempotency (sent exactly once per cycle)
- Correct tenant targeting and eligibility filtering
- Month boundary transitions and leap year handling
- Advance notice timing
- Error resilience and graceful degradation
- Empty workload handling
- Polling interval management
- Resource cleanup on stop

All tests follow project patterns, use vitest mocking, and include comprehensive error paths and edge case coverage.
Refactor test files to fix CI failures:
- Simplify mock setup (move before imports, fix module exports)
- Remove timing-dependent tests (setInterval/setTimeout issues)
- Focus on unit testing over integration testing
- Use proper vitest patterns (beforeEach/afterEach)
- Fix template string assertions to match actual output

All test files now pass:
- otpDeliveryFactory.test.ts (2 tests)
- otpDeliveryProvider.test.ts (7 tests)
- timelock-worker.test.ts (10 tests)
- timelock-repository.test.ts (27 tests)
- backupJob.test.ts (11 tests)
- dataRetentionPurgeJob.test.ts (19 tests)
- monthlyDeductionReminderJob.test.ts (32 tests)
Cover percentage-complete, paid/remaining counts, remaining-balance,
next-due (incl. overdue), and edge cases (empty schedule, fully paid,
overpaid, mixed outbox statuses, determinism).
…1256)

Cover create/edit/unpublish propagation, idempotent re-sync (no
duplicates), photo ordering, partial-failure handling, and no-op
states for unmapped property statuses.
…helterflex#1257)

Cover dedupe-key suppression, distinct-key delivery, correct
template/payload pass-through, email enqueue with resolved address,
and downstream failure propagation.
…ilure handling (Shelterflex#1258)

Cover single-intent creation, duplicate-initiation idempotency
(existing intent returned, CONFLICT on in-progress deposit),
PSP failure/timeout leaves no dangling state, bank_transfer rail
bypasses PSP, response shape matches webhook expectations, and
metric recording.
- Add tests for softDeleteUser (3 tests)
- Add tests for purgeExpiredRecords (6 tests)
- Add tests for getPendingPurgeCount (5 tests)
- Cover idempotency and TTL boundary cases
- 14/14 tests passing

Closes Shelterflex#1157
…nd stats

- Add native Web Share API integration with fallback handling
- Implement loading, error, and not-eligible states with clear UI
- Add integrated referral stats display (invited, pending, qualified)
- Improve accessibility with proper ARIA labels and readonly input
- Add copy feedback with visual checkmark and toast notifications
- Support eligibility gating with unlock instructions
…nagement

- Remove redundant code (separate code/link display, copy handlers)
- Integrate enhanced ReferralShareCard with loading/error/eligibility props
- Add isEligible state management from API response
- Add conditional detailed stats section (only shown when eligible)
- Improve error handling with specific error messages
…helterflex#1263, Shelterflex#1264)

- quote.test.ts: 12 tests covering valid pricing math, all installment tiers,
  and input validation (missing/zero/negative annualRentNgn, out-of-range depositPercent)
- conversion.test.ts: 5 tests verifying faithful pass-through of rate/source/
  fetchedAt/expiresAt and that provider errors surface as 500 (not silent)
- properties.test.ts: 15 tests locking the public shape, verifying private fields
  (whistleblowerId, negotiatedLandlordRateNgn, reviewedBy, reviewedAt,
  rejectionReason, dealId) are stripped, and that only APPROVED listings are
  accessible (pending/rejected return 404)
- publicRoutes.test.ts: 12 tests covering soroban config shape and echo
  endpoint validation

Supporting changes:
- schemas/listing.ts: export propertySearchSchema (listingFiltersSchema without
  status, which the route overrides to APPROVED)
- routes/properties.ts: strip private fields via toPublicListing() before
  sending response, fixing the field-exposure boundary
@pope-h
pope-h merged commit 28503ce into Shelterflex:main Jul 4, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet