Usecase puncipal + test

This commit is contained in:
2026-03-10 14:29:25 +01:00
parent 07d49aab29
commit 863fed0350
4 changed files with 154 additions and 9 deletions

View File

@@ -1,18 +1,18 @@
import { httpclient } from "config/httpclient.config.js";
import { pgClient } from "config/pgclient.config.js";
import type { ServerContext } from "domain/ServerContext.js";
import test, { describe } from "node:test";
import test, { describe, beforeEach } from "node:test";
import { NfcUsecases } from "./Nfc.usecases.js";
import type { NfcRepository } from "infrastructure/Nfc.repository.js";
import assert from "node:assert";
describe("NFC activation code", () => {
describe("NFC activation code (Private methods)", () => {
const serverContext: ServerContext = {
PostgresClient: pgClient,
HttpClient: httpclient
}
const nfcUsecases = new NfcUsecases(serverContext)
const nfcUsecases = new NfcUsecases(serverContext, {} as NfcRepository)
test("Should generate 8 digit codes", () => {
// @ts-expect-error
@@ -43,3 +43,89 @@ describe("NFC activation code", () => {
assert(validation == false)
})
})
describe("NfcUsecases Unit Tests (Public methods with Mocks)", () => {
let mockNfcRepository: any;
let mockServerContext: ServerContext;
let nfcUsecases: NfcUsecases;
beforeEach(() => {
mockNfcRepository = {
findActivationCodes: test.mock.fn(),
createActivationCode: test.mock.fn(),
};
mockServerContext = {
PostgresClient: {} as any,
HttpClient: {} as any,
};
nfcUsecases = new NfcUsecases(mockServerContext, mockNfcRepository as unknown as NfcRepository);
});
describe("generateActivationLabel", () => {
const card_id = "test-card-id";
test("should return error if repository.findActivationCodes fails", async () => {
const expectedError = "Repository error";
mockNfcRepository.findActivationCodes.mock.mockImplementation(async () => ({
error: expectedError
}));
const usecase = nfcUsecases.generateActivationLabel();
const result = await usecase({ card_id });
assert.strictEqual(result.error, expectedError);
assert.strictEqual(mockNfcRepository.findActivationCodes.mock.callCount(), 1);
});
test("should reuse existing code if found and override is false", async () => {
const existingCode = "v1234567";
mockNfcRepository.findActivationCodes.mock.mockImplementation(async () => ({
data: [{ code_plain: existingCode }]
}));
mockNfcRepository.createActivationCode.mock.mockImplementation(async () => ({
data: { card_id, code_plain: existingCode }
}));
const usecase = nfcUsecases.generateActivationLabel();
const result = await usecase({ card_id, override: false });
assert.ok(result.data);
assert.strictEqual(result.data.code, existingCode);
assert.strictEqual(result.data.reused, true);
assert.strictEqual(result.data.overriden, false);
assert.strictEqual(mockNfcRepository.createActivationCode.mock.callCount(), 1);
});
test("should generate new code if no existing codes found", async () => {
mockNfcRepository.findActivationCodes.mock.mockImplementation(async () => ({
data: []
}));
const usecase = nfcUsecases.generateActivationLabel();
const result = await usecase({ card_id });
assert.ok(result.data);
assert.ok(result.data.code);
assert.strictEqual(result.data.reused, false);
assert.strictEqual(result.data.overriden, false);
});
test("should generate new code if override is true even if existing codes exist", async () => {
const existingCode = "v1234567";
mockNfcRepository.findActivationCodes.mock.mockImplementation(async () => ({
data: [{ code_plain: existingCode }]
}));
const usecase = nfcUsecases.generateActivationLabel();
const result = await usecase({ card_id, override: true });
assert.ok(result.data);
assert.notStrictEqual(result.data.code, existingCode);
assert.strictEqual(result.data.reused, false);
assert.strictEqual(result.data.overriden, true);
});
});
});

View File

@@ -1,12 +1,20 @@
import type { ServerContext } from "domain/ServerContext.js";
import { labelTemplate } from "./labelTemplate.js";
import type { NfcRepository } from "infrastructure/Nfc.repository.js";
import assert from "node:assert";
import type { CodeGenerationResultDTO } from "domain/NfcDTOs.js";
import type { Result } from "domain/Result.js";
export class NfcUsecases {
private ctx: ServerContext;
private nfcRepository: NfcRepository;
constructor(
serverContext: ServerContext
serverContext: ServerContext,
nfcRepository: NfcRepository
) {
this.ctx = serverContext
this.nfcRepository = nfcRepository
}
private getRandomDayOffset() {
@@ -69,16 +77,58 @@ export class NfcUsecases {
return validationChar == testValidationChar
}
/**
* Caso de uso principal, genera una etiqueta con un codigo de activación,
* si ya se ha generado uno para esa tarjeta se avisará.
* Se puede forzar generar uno nuevo.
*/
public generateActivationLabel() {
return () => {
return async (args: {
card_id: string,
override?: boolean,
}): Promise<Result<string, CodeGenerationResultDTO>> => {
const generatedCodes = await this.nfcRepository.findActivationCodes(args.card_id)
if (generatedCodes.error != undefined) {
console.error(generatedCodes.error)
return generatedCodes // Caso de error
}
if (generatedCodes.data.length > 0 && !args.override) {
// Ya se habia generado un codigo
assert(generatedCodes.data[0] != undefined)
const code = generatedCodes.data[0].code_plain
assert(code != undefined)
const label = labelTemplate(code)
this.nfcRepository.createActivationCode({
cardId: args.card_id,
code: code
})
return {
data: {
code: code,
label: label,
overriden: false,
reused: true,
}
}
}
const codigo = this.generateActivationCode()
const label = labelTemplate(codigo)
// Introducir en la bdd
// Caso base: codigo limpio generado
return {
code: codigo,
label: label
data: {
code: codigo,
label: label,
overriden: args.override ?? false,
reused: false
}
}
}
}

View File

@@ -26,3 +26,12 @@ export type ActivationLogDTO = {
geo_location: string,
created_at: Date,
}
export type CodeGenerationResultDTO = {
code: string,
label: string,
/** Si ya existia un codigo anterior pero se ha creado uno nuevo*/
overriden: boolean,
/** Si ya existia un código anterior y se ha reusado */
reused: boolean
}

View File

@@ -1,4 +1,4 @@
import type { ActivationCodeDTO } from "domain/NfcRegistry.js";
import type { ActivationCodeDTO } from "domain/NfcDTOs.js";
import type { Result } from "domain/Result.js";
import type { ServerContext } from "domain/ServerContext.js";
import { constrainedMemory } from "node:process";