fix issues in core

This commit is contained in:
2025-12-23 11:25:08 +01:00
parent 1efd971032
commit 2854ae3c5c
113 changed files with 1142 additions and 458 deletions

View File

@@ -1,36 +1,13 @@
import { describe, it, expect, vi, type Mock } from 'vitest';
import { GetAnalyticsMetricsUseCase, type GetAnalyticsMetricsInput, type GetAnalyticsMetricsOutput } from './GetAnalyticsMetricsUseCase';
import type { IPageViewRepository } from '../../domain/repositories/IPageViewRepository';
import type { Logger, UseCaseOutputPort } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
describe('GetAnalyticsMetricsUseCase', () => {
let pageViewRepository: {
save: Mock;
findById: Mock;
findByEntityId: Mock;
findBySessionId: Mock;
countByEntityId: Mock;
getUniqueVisitorsCount: Mock;
getAverageSessionDuration: Mock;
getBounceRate: Mock;
};
let logger: Logger;
let output: UseCaseOutputPort<GetAnalyticsMetricsOutput> & { present: Mock };
let useCase: GetAnalyticsMetricsUseCase;
beforeEach(() => {
pageViewRepository = {
save: vi.fn(),
findById: vi.fn(),
findByEntityId: vi.fn(),
findBySessionId: vi.fn(),
countByEntityId: vi.fn(),
getUniqueVisitorsCount: vi.fn(),
getAverageSessionDuration: vi.fn(),
getBounceRate: vi.fn(),
} as unknown as IPageViewRepository as any;
logger = {
debug: vi.fn(),
info: vi.fn(),
@@ -43,7 +20,6 @@ describe('GetAnalyticsMetricsUseCase', () => {
};
useCase = new GetAnalyticsMetricsUseCase(
pageViewRepository as unknown as IPageViewRepository,
logger,
output,
);
@@ -78,4 +54,4 @@ describe('GetAnalyticsMetricsUseCase', () => {
expect(result.isErr()).toBe(true);
expect((logger.error as unknown as Mock)).toHaveBeenCalled();
});
});
});

View File

@@ -1,7 +1,6 @@
import type { Logger, UseCase, UseCaseOutputPort } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { IPageViewRepository } from '../../domain/repositories/IPageViewRepository';
export interface GetAnalyticsMetricsInput {
startDate?: Date;
@@ -19,7 +18,7 @@ export type GetAnalyticsMetricsErrorCode = 'REPOSITORY_ERROR';
export class GetAnalyticsMetricsUseCase implements UseCase<GetAnalyticsMetricsInput, void, GetAnalyticsMetricsErrorCode> {
constructor(
private readonly pageViewRepository: IPageViewRepository,
// private readonly pageViewRepository: IPageViewRepository, // TODO: Use when implementation is ready
private readonly logger: Logger,
private readonly output: UseCaseOutputPort<GetAnalyticsMetricsOutput>,
) {}
@@ -29,7 +28,8 @@ export class GetAnalyticsMetricsUseCase implements UseCase<GetAnalyticsMetricsIn
const startDate = input.startDate ?? new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); // 30 days ago
const endDate = input.endDate ?? new Date();
// TODO static data
// TODO: Use pageViewRepository when implemented
// const pageViews = await this.pageViewRepository.countByDateRange(startDate, endDate);
const pageViews = 0;
const uniqueVisitors = 0;
const averageSessionDuration = 0;

View File

@@ -1,7 +1,6 @@
import { describe, it, expect, vi, type Mock } from 'vitest';
import { GetDashboardDataUseCase, type GetDashboardDataOutput } from './GetDashboardDataUseCase';
import type { Logger, UseCaseOutputPort } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
describe('GetDashboardDataUseCase', () => {
let logger: Logger;
@@ -36,4 +35,4 @@ describe('GetDashboardDataUseCase', () => {
expect((logger.info as unknown as Mock)).toHaveBeenCalled();
});
});
});

View File

@@ -19,7 +19,7 @@ export class GetDashboardDataUseCase implements UseCase<GetDashboardDataInput, v
private readonly output: UseCaseOutputPort<GetDashboardDataOutput>,
) {}
async execute(input: GetDashboardDataInput = {}): Promise<Result<void, ApplicationErrorCode<GetDashboardDataErrorCode, { message: string }>>> {
async execute(): Promise<Result<void, ApplicationErrorCode<GetDashboardDataErrorCode, { message: string }>>> {
try {
// Placeholder implementation - would need repositories from identity and racing domains
const totalUsers = 0;

View File

@@ -2,7 +2,6 @@ import { describe, it, expect, vi, type Mock } from 'vitest';
import { GetEntityAnalyticsQuery, type GetEntityAnalyticsInput } from './GetEntityAnalyticsQuery';
import type { IPageViewRepository } from '../repositories/IPageViewRepository';
import type { IEngagementRepository } from '@core/analytics/domain/repositories/IEngagementRepository';
import type { IAnalyticsSnapshotRepository } from '@core/analytics/domain/repositories/IAnalyticsSnapshotRepository';
import type { Logger } from '@core/shared/application';
import type { EntityType } from '../../domain/types/PageView';
@@ -14,7 +13,6 @@ describe('GetEntityAnalyticsQuery', () => {
let engagementRepository: {
getSponsorClicksForEntity: Mock;
};
let snapshotRepository: IAnalyticsSnapshotRepository;
let logger: Logger;
let useCase: GetEntityAnalyticsQuery;
@@ -28,8 +26,6 @@ describe('GetEntityAnalyticsQuery', () => {
getSponsorClicksForEntity: vi.fn(),
} as unknown as IEngagementRepository as any;
snapshotRepository = {} as IAnalyticsSnapshotRepository;
logger = {
debug: vi.fn(),
info: vi.fn(),
@@ -40,7 +36,6 @@ describe('GetEntityAnalyticsQuery', () => {
useCase = new GetEntityAnalyticsQuery(
pageViewRepository as unknown as IPageViewRepository,
engagementRepository as unknown as IEngagementRepository,
snapshotRepository,
logger,
);
});

View File

@@ -5,10 +5,9 @@
* Returns metrics formatted for display to sponsors and admins.
*/
import type { AsyncUseCase , Logger, UseCaseOutputPort } from '@core/shared/application';
import type { AsyncUseCase , Logger } from '@core/shared/application';
import type { IPageViewRepository } from '../repositories/IPageViewRepository';
import type { IEngagementRepository } from '@core/analytics/domain/repositories/IEngagementRepository';
import type { IAnalyticsSnapshotRepository } from '@core/analytics/domain/repositories/IAnalyticsSnapshotRepository';
import type { EntityType } from '../../domain/types/PageView';
import type { SnapshotPeriod } from '../../domain/types/AnalyticsSnapshot';
import { Result } from '@core/shared/application/Result';
@@ -51,7 +50,7 @@ export class GetEntityAnalyticsQuery
constructor(
private readonly pageViewRepository: IPageViewRepository,
private readonly engagementRepository: IEngagementRepository,
private readonly snapshotRepository: IAnalyticsSnapshotRepository,
// private readonly snapshotRepository: IAnalyticsSnapshotRepository, // TODO: Use when implementation is ready
private readonly logger: Logger
) {}

View File

@@ -4,7 +4,6 @@ import type { IEngagementRepository } from '../../domain/repositories/IEngagemen
import { EngagementEvent } from '../../domain/entities/EngagementEvent';
import type { Logger, UseCaseOutputPort } from '@core/shared/application';
import type { EngagementAction, EngagementEntityType } from '../../domain/types/EngagementEvent';
import { Result } from '@core/shared/application/Result';
describe('RecordEngagementUseCase', () => {
let engagementRepository: {
@@ -54,7 +53,7 @@ describe('RecordEngagementUseCase', () => {
expect(result.isOk()).toBe(true);
expect(engagementRepository.save).toHaveBeenCalledTimes(1);
const saved = (engagementRepository.save as unknown as Mock).mock.calls[0][0] as EngagementEvent;
const saved = (engagementRepository.save as unknown as Mock).mock.calls?.[0]?.[0] as EngagementEvent;
expect(saved).toBeInstanceOf(EngagementEvent);
expect(saved.id).toBeDefined();
@@ -85,4 +84,4 @@ describe('RecordEngagementUseCase', () => {
expect(result.isErr()).toBe(true);
expect((logger.error as unknown as Mock)).toHaveBeenCalled();
});
});
});

View File

@@ -1,9 +1,9 @@
import type { Logger, UseCaseOutputPort, UseCase } from '@core/shared/application';
import type { IEngagementRepository } from '../../domain/repositories/IEngagementRepository';
import { EngagementEvent } from '../../domain/entities/EngagementEvent';
import type { EngagementAction, EngagementEntityType } from '../../domain/types/EngagementEvent';
import type { Logger, UseCase, UseCaseOutputPort } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import { EngagementEvent } from '../../domain/entities/EngagementEvent';
import type { IEngagementRepository } from '../../domain/repositories/IEngagementRepository';
import type { EngagementAction, EngagementEntityType } from '../../domain/types/EngagementEvent';
export interface RecordEngagementInput {
action: EngagementAction;
@@ -36,10 +36,10 @@ export class RecordEngagementUseCase implements UseCase<RecordEngagementInput, v
action: input.action,
entityType: input.entityType,
entityId: input.entityId,
actorId: input.actorId,
actorType: input.actorType,
sessionId: input.sessionId,
metadata: input.metadata,
...(input.actorId !== undefined && { actorId: input.actorId }),
...(input.metadata !== undefined && { metadata: input.metadata }),
});
await this.engagementRepository.save(engagementEvent);

View File

@@ -4,7 +4,6 @@ import type { IPageViewRepository } from '../../domain/repositories/IPageViewRep
import { PageView } from '../../domain/entities/PageView';
import type { Logger, UseCaseOutputPort } from '@core/shared/application';
import type { EntityType, VisitorType } from '../../domain/types/PageView';
import { Result } from '@core/shared/application/Result';
describe('RecordPageViewUseCase', () => {
let pageViewRepository: {
@@ -55,7 +54,7 @@ describe('RecordPageViewUseCase', () => {
expect(result.isOk()).toBe(true);
expect(pageViewRepository.save).toHaveBeenCalledTimes(1);
const saved = (pageViewRepository.save as unknown as Mock).mock.calls[0][0] as PageView;
const saved = (pageViewRepository.save as unknown as Mock).mock.calls?.[0]?.[0] as PageView;
expect(saved).toBeInstanceOf(PageView);
expect(saved.id).toBeDefined();
@@ -84,4 +83,4 @@ describe('RecordPageViewUseCase', () => {
expect(result.isErr()).toBe(true);
expect((logger.error as unknown as Mock)).toHaveBeenCalled();
});
});
});

View File

@@ -31,17 +31,28 @@ export class RecordPageViewUseCase implements UseCase<RecordPageViewInput, void,
async execute(input: RecordPageViewInput): Promise<Result<void, ApplicationErrorCode<RecordPageViewErrorCode, { message: string }>>> {
try {
const pageView = PageView.create({
const props = {
id: crypto.randomUUID(),
entityType: input.entityType,
entityId: input.entityId,
visitorId: input.visitorId,
visitorType: input.visitorType,
sessionId: input.sessionId,
referrer: input.referrer,
userAgent: input.userAgent,
country: input.country,
});
} as any;
if (input.visitorId !== undefined) {
props.visitorId = input.visitorId;
}
if (input.referrer !== undefined) {
props.referrer = input.referrer;
}
if (input.userAgent !== undefined) {
props.userAgent = input.userAgent;
}
if (input.country !== undefined) {
props.country = input.country;
}
const pageView = PageView.create(props);
await this.pageViewRepository.save(pageView);