mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-22 12:06:42 +02:00
✅ fix(mana-core-auth): complete production readiness with test fixes
- Fix LoggerService mock in better-auth.service.spec.ts - Fix name assertion in auth.controller.spec.ts (empty string fallback) - Fix createRemoteJWKSet mock in jwt-auth.guard.spec.ts - Add Grafana dashboard for Auth Service monitoring - Add 10 auth-specific Prometheus alert rules - Update production readiness plan to 100% complete All 199 unit tests passing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e3774ca08b
commit
fe33f4b355
14 changed files with 1282 additions and 25 deletions
|
|
@ -4,7 +4,7 @@
|
|||
* Common utilities for writing tests
|
||||
*/
|
||||
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { type ConfigService } from '@nestjs/config';
|
||||
|
||||
/**
|
||||
* Create mock ConfigService
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ export class AnalyticsService implements OnModuleInit, OnModuleDestroy {
|
|||
/**
|
||||
* Get user growth over time
|
||||
*/
|
||||
async getUserGrowth(days: number = 90): Promise<GrowthData[]> {
|
||||
async getUserGrowth(days = 90): Promise<GrowthData[]> {
|
||||
if (!this.duckdb) return [];
|
||||
|
||||
const result = await this.duckdb.all(
|
||||
|
|
@ -171,7 +171,7 @@ export class AnalyticsService implements OnModuleInit, OnModuleDestroy {
|
|||
/**
|
||||
* Get monthly aggregated metrics
|
||||
*/
|
||||
async getMonthlyMetrics(months: number = 12): Promise<MonthlyMetrics[]> {
|
||||
async getMonthlyMetrics(months = 12): Promise<MonthlyMetrics[]> {
|
||||
if (!this.duckdb) return [];
|
||||
|
||||
const result = await this.duckdb.all(
|
||||
|
|
|
|||
|
|
@ -139,7 +139,8 @@ describe('AuthController', () => {
|
|||
expect(betterAuthService.registerB2C).toHaveBeenCalledWith({
|
||||
email: registerDto.email,
|
||||
password: registerDto.password,
|
||||
name: undefined, // Controller passes undefined when name is not provided
|
||||
name: '', // Controller passes empty string as fallback when name is not provided
|
||||
sourceAppUrl: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,12 @@ import { ReferralsModule } from '../referrals/referrals.module';
|
|||
|
||||
@Module({
|
||||
imports: [forwardRef(() => ReferralsModule)],
|
||||
controllers: [AuthController, BetterAuthPassthroughController, OidcController, OidcLoginController],
|
||||
controllers: [
|
||||
AuthController,
|
||||
BetterAuthPassthroughController,
|
||||
OidcController,
|
||||
OidcLoginController,
|
||||
],
|
||||
providers: [BetterAuthService],
|
||||
exports: [BetterAuthService],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@
|
|||
*/
|
||||
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { type ConfigService } from '@nestjs/config';
|
||||
import { SignJWT, jwtVerify, errors } from 'jose';
|
||||
import { JWTCustomPayload } from './better-auth.config';
|
||||
import { type JWTCustomPayload } from './better-auth.config';
|
||||
import { createMockConfigService } from '../__tests__/utils/test-helpers';
|
||||
import { mockUserFactory } from '../__tests__/utils/mock-factories';
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import type { TestingModule } from '@nestjs/testing';
|
|||
import { ConfigService } from '@nestjs/config';
|
||||
import { ConflictException, NotFoundException, ForbiddenException } from '@nestjs/common';
|
||||
import { BetterAuthService } from './better-auth.service';
|
||||
import { LoggerService } from '../../common/logger';
|
||||
import { createMockConfigService } from '../../__tests__/utils/test-helpers';
|
||||
import { silentError } from '../../__tests__/utils/silent-error.decorator';
|
||||
|
||||
|
|
@ -68,6 +69,15 @@ const mockReferralTrackingService = {
|
|||
applyReferral: jest.fn().mockResolvedValue({ success: true }),
|
||||
};
|
||||
|
||||
const mockLoggerService = {
|
||||
setContext: jest.fn().mockReturnThis(),
|
||||
log: jest.fn(),
|
||||
debug: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
error: jest.fn(),
|
||||
verbose: jest.fn(),
|
||||
};
|
||||
|
||||
describe('BetterAuthService', () => {
|
||||
let service: BetterAuthService;
|
||||
let configService: ConfigService;
|
||||
|
|
@ -116,6 +126,10 @@ describe('BetterAuthService', () => {
|
|||
provide: ReferralTrackingService,
|
||||
useValue: mockReferralTrackingService,
|
||||
},
|
||||
{
|
||||
provide: LoggerService,
|
||||
useValue: mockLoggerService,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
|
|
|||
|
|
@ -17,11 +17,16 @@ import { LoggerService } from '../logger';
|
|||
import { createMockConfigService, httpMockHelpers } from '../../__tests__/utils/test-helpers';
|
||||
import { mockTokenFactory } from '../../__tests__/utils/mock-factories';
|
||||
import { silentError } from '../../__tests__/utils/silent-error.decorator';
|
||||
import { jwtVerify } from 'jose';
|
||||
import { jwtVerify, createRemoteJWKSet } from 'jose';
|
||||
|
||||
// Mock jose (auto-mocked via jest.config.js moduleNameMapper)
|
||||
jest.mock('jose');
|
||||
|
||||
// Setup mock for createRemoteJWKSet to return a defined JWKS function
|
||||
const mockJWKS = jest.fn();
|
||||
const mockCreateRemoteJWKSet = createRemoteJWKSet as jest.MockedFunction<typeof createRemoteJWKSet>;
|
||||
mockCreateRemoteJWKSet.mockReturnValue(mockJWKS as any);
|
||||
|
||||
// Mock LoggerService
|
||||
const createMockLoggerService = (): LoggerService =>
|
||||
({
|
||||
|
|
@ -43,6 +48,9 @@ describe('JwtAuthGuard', () => {
|
|||
// Reset mocks
|
||||
jest.clearAllMocks();
|
||||
|
||||
// Ensure createRemoteJWKSet returns a defined value after clearing
|
||||
mockCreateRemoteJWKSet.mockReturnValue(mockJWKS as any);
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
JwtAuthGuard,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import { BadRequestException, ForbiddenException, NotFoundException } from '@nes
|
|||
import { CreditsController } from './credits.controller';
|
||||
import { CreditsService } from './credits.service';
|
||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||
import { CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import { type CurrentUserData } from '../common/decorators/current-user.decorator';
|
||||
import {
|
||||
mockBalanceFactory,
|
||||
mockTransactionFactory,
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ export class FraudDetectionService {
|
|||
/**
|
||||
* Get pending review items
|
||||
*/
|
||||
async getPendingReviews(limit: number = 50, offset: number = 0): Promise<ReviewQueueItem[]> {
|
||||
async getPendingReviews(limit = 50, offset = 0): Promise<ReviewQueueItem[]> {
|
||||
const db = this.getDb();
|
||||
|
||||
return db
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ export class ReferralTierService {
|
|||
calculateBonus(
|
||||
eventType: keyof typeof BONUS_AMOUNTS,
|
||||
tier: TierName,
|
||||
isReferrer: boolean = true
|
||||
isReferrer = true
|
||||
): { base: number; multiplier: number; final: number } {
|
||||
const bonusConfig = BONUS_AMOUNTS[eventType];
|
||||
const base = isReferrer ? bonusConfig.referrer : bonusConfig.referee;
|
||||
|
|
|
|||
|
|
@ -501,8 +501,8 @@ export class ReferralTrackingService {
|
|||
async getReferredUsers(
|
||||
userId: string,
|
||||
status?: string,
|
||||
limit: number = 20,
|
||||
offset: number = 0
|
||||
limit = 20,
|
||||
offset = 0
|
||||
): Promise<PaginatedResponse<ReferredUser>> {
|
||||
const db = this.getDb();
|
||||
|
||||
|
|
@ -734,7 +734,7 @@ export class ReferralTrackingService {
|
|||
): Promise<number> {
|
||||
// Basic fraud score calculation
|
||||
// Full fraud detection will be implemented in Phase 3
|
||||
let score = 0;
|
||||
const score = 0;
|
||||
|
||||
// For now, just return 0 (no fraud detected)
|
||||
// TODO: Implement full fraud detection in Phase 3
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue