Skip to content

Commit 9144312

Browse files
committed
Fix backend, frontend, and contract build/test/lint failures
Backend: - Fix missing WalletSignatureService provider in AuthModule (would have broken real login, not just tests) - Fix missing await in ProfileService.update() that let a Prisma unique constraint error bypass the catch block and leak as a raw 500 instead of a 409 ConflictException - Fix duplicate queueDepth metric registration and mismatched recordQueueDepth call signature - Add missing MetricsService methods (recordVacuumOperation, recordTableBloat, recordClaimNotificationBatch, recordJobProcessingDuration) - Fix various DI wiring gaps in test files (AdminClaimsExportService, TokenBlacklistService, MetricsCardinalityGuard, TenantOnboardingService, etc.) - Fix bullmq API mismatches (getCountsPerState -> getJobCounts) - Fix xdr-decode controller's base64 handling and removed reference to a non-existent xdr.Envelope type - Clean up all ESLint errors (unused imports/vars, explicit any) Frontend: - Fix missing useMemo import, missing useWallet import - Install missing @radix-ui/react-alert-dialog dependency - Wire up TransactionFilterBar component that was built but never rendered - Clean up all ESLint errors (unused imports/vars) Contracts: - Target wasm32v1-none instead of wasm32-unknown-unknown (required for soroban-sdk with Rust 1.82+, matches contracts-ci.yml) - Add missing InsufficientAllowanceForFee and VoterCapReached error variants - Add missing token_decimals field to Policy struct in policy_lifecycle.rs - Fix silently-swallowed Result in finalize_appeal_outcome - Fix hard panic in calculator::call_external when querying abi_version on an unreachable calculator address (now returns typed CalculatorCallFailed) - Fix compute_quote silently falling back to the local pricing engine on calculator failures, contradicting its own documented fail-closed contract - Fix various tests calling .unwrap()/.expect() on infallible client methods - Fix test bugs where a claimant voted on their own claim, masking the behavior actually under test CI: - Fix frontend-ci.yml missing required NEXT_PUBLIC_CONTRACT_ID env var, which would have failed the build step
1 parent 09992ec commit 9144312

73 files changed

Lines changed: 436 additions & 316 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/frontend-ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
working-directory: frontend
2727
env:
2828
NEXT_PUBLIC_API_URL: https://api.example.com
29+
NEXT_PUBLIC_CONTRACT_ID: CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
2930
steps:
3031
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
3132

backend/src/admin/admin.controller.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Request, Response } from 'express';
55
import { AdminController } from './admin.controller';
66
import { AdminService } from './admin.service';
77
import { AdminPoliciesService } from './admin-policies.service';
8+
import { AdminClaimsExportService } from './admin-claims-export.service';
89
import { AuditService } from './audit.service';
910
import { PrivacyService } from '../maintenance/privacy.service';
1011
import { RateLimitService } from '../rate-limit/rate-limit.service';
@@ -16,6 +17,10 @@ import { AdminTenantsService } from './admin-tenants.service';
1617
import { AdminStatsService } from './admin-stats.service';
1718
import { SorobanService } from '../rpc/soroban.service';
1819
import { AdminAnalyticsService } from './admin-analytics.service';
20+
import { TokenBlacklistService } from '../auth/token-blacklist.service';
21+
import { SupportService } from '../support/support.service';
22+
import { CommentRepository } from '../claims/comments/comment.repository';
23+
import { TenantConfigAuditService } from '../tenant/tenant-config-audit.service';
1924

2025
const mockSorobanService = {
2126
simulateGetEvidenceLimits: jest.fn(),
@@ -70,6 +75,23 @@ const mockPrismaService = {
7075
registeredVoter: { findMany: jest.fn() },
7176
claim: { findMany: jest.fn() },
7277
};
78+
const mockAdminClaimsExportService = {
79+
streamCsv: jest.fn(),
80+
};
81+
const mockTokenBlacklistService = {
82+
isBlacklisted: jest.fn(),
83+
blacklist: jest.fn(),
84+
};
85+
const mockSupportService = {
86+
listTickets: jest.fn(),
87+
getTicket: jest.fn(),
88+
};
89+
const mockCommentRepository = {
90+
findByClaimId: jest.fn(),
91+
};
92+
const mockTenantConfigAuditService = {
93+
getHistory: jest.fn(),
94+
};
7395

7496
const adminReq = (role = 'admin', scopes: string[] = ['admin:claims:override']) =>
7597
({
@@ -114,6 +136,11 @@ describe('AdminController', () => {
114136
{ provide: AdminTenantsService, useValue: mockAdminTenantsService },
115137
{ provide: require('../prisma/prisma.service').PrismaService, useValue: mockPrismaService },
116138
{ provide: SorobanService, useValue: mockSorobanService },
139+
{ provide: AdminClaimsExportService, useValue: mockAdminClaimsExportService },
140+
{ provide: TokenBlacklistService, useValue: mockTokenBlacklistService },
141+
{ provide: SupportService, useValue: mockSupportService },
142+
{ provide: CommentRepository, useValue: mockCommentRepository },
143+
{ provide: TenantConfigAuditService, useValue: mockTenantConfigAuditService },
117144
],
118145
})
119146
.overrideGuard(JwtAuthGuard)
@@ -459,6 +486,11 @@ describe('Admin Role Guard Enforcement', () => {
459486
{ provide: AdminTenantsService, useValue: mockAdminTenantsService },
460487
{ provide: require('../prisma/prisma.service').PrismaService, useValue: mockPrismaService },
461488
{ provide: SorobanService, useValue: mockSorobanService },
489+
{ provide: AdminClaimsExportService, useValue: mockAdminClaimsExportService },
490+
{ provide: TokenBlacklistService, useValue: mockTokenBlacklistService },
491+
{ provide: SupportService, useValue: mockSupportService },
492+
{ provide: CommentRepository, useValue: mockCommentRepository },
493+
{ provide: TenantConfigAuditService, useValue: mockTenantConfigAuditService },
462494
],
463495
})
464496
.overrideGuard(JwtAuthGuard)

backend/src/auth/auth.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { RefreshTokenService } from './refresh-token.service';
99
import { AuthController } from './auth.controller';
1010
import { AuthIdentityService } from './auth-identity.service';
1111
import { TokenBlacklistService } from './token-blacklist.service';
12+
import { WalletSignatureService } from './wallet-signature.service';
1213
import { CacheModule } from '../cache/cache.module';
1314

1415
@Module({
@@ -25,7 +26,7 @@ import { CacheModule } from '../cache/cache.module';
2526
}),
2627
],
2728
controllers: [AuthController],
28-
providers: [JwtStrategy, WalletAuthService, NonceService, RefreshTokenService, AuthIdentityService, TokenBlacklistService],
29+
providers: [JwtStrategy, WalletAuthService, NonceService, RefreshTokenService, AuthIdentityService, TokenBlacklistService, WalletSignatureService],
2930
exports: [PassportModule, JwtModule, AuthIdentityService, TokenBlacklistService],
3031
})
3132
export class AuthModule {}

backend/src/auth/refresh-token.integration.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { AuthController } from './auth.controller';
1717
import { WalletAuthService } from './wallet-auth.service';
1818
import { RefreshTokenService } from './refresh-token.service';
1919
import { NonceService } from './nonce.service';
20+
import { WalletSignatureService } from './wallet-signature.service';
2021
import { RedisService } from '../cache/redis.service';
2122

2223
// ── In-memory Redis mock ──────────────────────────────────────────────────
@@ -83,6 +84,7 @@ async function buildApp() {
8384
providers: [
8485
WalletAuthService,
8586
RefreshTokenService,
87+
WalletSignatureService,
8688
{ provide: NonceService, useValue: nonceService },
8789
{ provide: RedisService, useValue: redisStore },
8890
],

backend/src/auth/token-blacklist.service.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ describe('TokenBlacklistService', () => {
1212
exists: jest.fn().mockResolvedValue(0),
1313
};
1414
redisService = {
15-
client: mockRedisClient as any,
15+
getClient: jest.fn().mockReturnValue(mockRedisClient),
1616
};
1717
service = new TokenBlacklistService(redisService as RedisService);
1818
});

backend/src/cache/allowed-assets-cache.service.spec.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -73,37 +73,41 @@ describe('AllowedAssetsCacheService', () => {
7373
const jitterMs = 200;
7474

7575
service.onModuleInit();
76-
77-
// The first refresh should happen within baseInterval + jitterMs
7876
expect(jest.getTimerCount()).toBe(1);
7977

80-
const timers = jest.getTimerIntervalById(
81-
jest.getTimerIntervalById.toString().match(/\d+/)?.[0] as any,
82-
);
83-
expect(timers).toBeGreaterThanOrEqual(baseInterval);
84-
expect(timers).toBeLessThanOrEqual(baseInterval + jitterMs);
78+
const beforeTime = Date.now();
79+
jest.runOnlyPendingTimers();
80+
const elapsed = Date.now() - beforeTime;
81+
82+
expect(elapsed).toBeGreaterThanOrEqual(baseInterval);
83+
expect(elapsed).toBeLessThanOrEqual(baseInterval + jitterMs);
8584

8685
jest.useRealTimers();
8786
});
8887

89-
it('reschedules refresh after completion', (done) => {
88+
it('reschedules refresh after completion', async () => {
9089
jest.useFakeTimers();
9190
const setSpy = jest.spyOn(mockRedis, 'set' as any);
9291

9392
service.onModuleInit();
9493
expect(jest.getTimerCount()).toBe(1);
9594

9695
jest.runOnlyPendingTimers();
96+
// refresh() is async (awaits fetchAssets() then redis.set()); flush
97+
// the microtask queue so those awaited calls resolve before asserting.
98+
await Promise.resolve();
99+
await Promise.resolve();
100+
97101
expect(setSpy).toHaveBeenCalled();
98102

99-
// After refresh completes, a new timer should be scheduled
100-
setTimeout(() => {
101-
expect(jest.getTimerCount()).toBeGreaterThan(0);
102-
jest.useRealTimers();
103-
done();
104-
}, 0);
103+
// After refresh completes, a new timer should be scheduled. scheduleRefresh()
104+
// runs after the outer async callback's `await this.refresh()` resolves, one
105+
// more microtask tick beyond the redis.set() call above — flush a few more.
106+
await Promise.resolve();
107+
await Promise.resolve();
108+
expect(jest.getTimerCount()).toBeGreaterThan(0);
105109

106-
jest.runOnlyPendingTimers();
110+
jest.useRealTimers();
107111
});
108112
});
109113

backend/src/config/env.validation.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function validEnv(overrides: Record<string, unknown> = {}): Record<string, unkno
1717
FRONTEND_ORIGINS: 'http://localhost:3001',
1818
CAPTCHA_SECRET_KEY: 'dev-skip',
1919
IP_HASH_SALT: '0123456789abcdef0123456789abcdef',
20+
API_BASE_URL: 'http://localhost:3000',
2021
...overrides,
2122
};
2223
}

backend/src/dto/oracle-hooks-payload.dto.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { IsString, IsNumber, IsOptional, ValidateNested, Type, IsArray } from 'class-validator';
1+
import { IsString, IsNumber, IsOptional, ValidateNested, IsArray } from 'class-validator';
2+
import { Type } from 'class-transformer';
23

34
export class OracleHooksPayloadDto {
45
@IsString()

backend/src/experimental/__tests__/experimental-access-log.interceptor.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Test, TestingModule } from '@nestjs/testing';
21
import { ExecutionContext, Logger } from '@nestjs/common';
32
import { of } from 'rxjs';
43
import { ExperimentalAccessLogInterceptor } from '../experimental-access-log.interceptor';

backend/src/experimental/__tests__/oracle-hooks.controller.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Test, TestingModule } from '@nestjs/testing';
2-
import { BadRequestException, ValidationPipe } from '@nestjs/common';
32
import { OracleHooksController } from '../oracle-hooks.controller';
43
import { OracleHooksPayloadDto } from '../../dto/oracle-hooks-payload.dto';
54

0 commit comments

Comments
 (0)