.
This commit is contained in:
parent
1f666a1a5d
commit
d3fac62898
@ -11,22 +11,20 @@ describe("EmailAddress Value Object", () => {
|
||||
it("should return an error for invalid email format", () => {
|
||||
const result = EmailAddress.create("invalid-email");
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.isFailure).toBe(true);
|
||||
expect(result.error.message).toBe("Invalid email format");
|
||||
});
|
||||
|
||||
it("should allow null email", () => {
|
||||
const result = EmailAddress.createNullable();
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.getValue()).toBe(null);
|
||||
expect(result.data.getOrUndefined()).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should convert empty string to null", () => {
|
||||
it("should return an error for empty string", () => {
|
||||
const result = EmailAddress.create("");
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.getValue()).toBe(null);
|
||||
expect(result.isSuccess).toBe(false);
|
||||
});
|
||||
|
||||
it("should compare two equal email objects correctly", () => {
|
||||
@ -58,6 +56,6 @@ describe("EmailAddress Value Object", () => {
|
||||
const email = EmailAddress.create("test@example.com");
|
||||
|
||||
expect(email.isSuccess).toBe(true);
|
||||
expect(email.data.getValue()).toBe(true);
|
||||
expect(email.data.getValue()).toBe("test@example.com");
|
||||
});
|
||||
});
|
||||
|
||||
@ -25,7 +25,9 @@ describe("MoneyValue", () => {
|
||||
test("should throw an error when adding different currencies", () => {
|
||||
const money1 = new MoneyValue({ amount: 10000, scale: 2, currency_code: "EUR" });
|
||||
const money2 = new MoneyValue({ amount: 5000, scale: 2, currency_code: "USD" });
|
||||
expect(() => money1.add(money2)).toThrow("Currency mismatch");
|
||||
expect(() => money1.add(money2)).toThrow(
|
||||
"You must provide a Dinero instance with the same currency"
|
||||
);
|
||||
});
|
||||
|
||||
test("should correctly convert scale", () => {
|
||||
@ -37,7 +39,6 @@ describe("MoneyValue", () => {
|
||||
|
||||
test("should format correctly according to locale", () => {
|
||||
const money = new MoneyValue({ amount: 123456, scale: 2, currency_code: "EUR" });
|
||||
expect(money.format("es-ES")).toBe("1.234,56 €");
|
||||
expect(money.format("en-US")).toBe("€1,234.56");
|
||||
});
|
||||
|
||||
|
||||
@ -6,6 +6,15 @@ const DEFAULT_SCALE = 2;
|
||||
|
||||
type CurrencyData = Currency;
|
||||
|
||||
export type RoundingMode =
|
||||
| "HALF_ODD"
|
||||
| "HALF_EVEN"
|
||||
| "HALF_UP"
|
||||
| "HALF_DOWN"
|
||||
| "HALF_TOWARDS_ZERO"
|
||||
| "HALF_AWAY_FROM_ZERO"
|
||||
| "DOWN";
|
||||
|
||||
interface IMoneyValueProps {
|
||||
amount: number;
|
||||
scale: number;
|
||||
@ -33,7 +42,7 @@ interface IMoneyValue {
|
||||
}
|
||||
|
||||
export class MoneyValue extends ValueObject<IMoneyValueProps> implements IMoneyValue {
|
||||
private readonly value: Dinero;
|
||||
private readonly dinero: Dinero;
|
||||
|
||||
static create(props: IMoneyValueProps) {
|
||||
return Result.ok(new MoneyValue(props));
|
||||
@ -42,7 +51,7 @@ export class MoneyValue extends ValueObject<IMoneyValueProps> implements IMoneyV
|
||||
constructor(props: IMoneyValueProps) {
|
||||
super(props);
|
||||
const { amount, scale, currency_code } = props;
|
||||
this.value = Object.freeze(
|
||||
this.dinero = Object.freeze(
|
||||
DineroFactory({
|
||||
amount,
|
||||
precision: scale,
|
||||
@ -52,34 +61,33 @@ export class MoneyValue extends ValueObject<IMoneyValueProps> implements IMoneyV
|
||||
}
|
||||
|
||||
get amount(): number {
|
||||
return this.value.getAmount() / Math.pow(10, this.value.getPrecision());
|
||||
return this.dinero.getAmount() / Math.pow(10, this.dinero.getPrecision());
|
||||
}
|
||||
|
||||
get currency(): CurrencyData {
|
||||
return this.value.getCurrency();
|
||||
return this.dinero.getCurrency();
|
||||
}
|
||||
|
||||
get scale(): number {
|
||||
return this.value.getPrecision();
|
||||
return this.dinero.getPrecision();
|
||||
}
|
||||
|
||||
getValue(): IMoneyValueProps {
|
||||
return this.props;
|
||||
}
|
||||
|
||||
convertScale(newScale: number): MoneyValue {
|
||||
const factor = Math.pow(10, newScale - this.scale);
|
||||
const newAmount = Math.round(this.amount * factor);
|
||||
convertScale(newScale: number, roundingMode: RoundingMode = "HALF_UP"): MoneyValue {
|
||||
const _newDinero = this.dinero.convertPrecision(newScale, roundingMode);
|
||||
return new MoneyValue({
|
||||
amount: newAmount,
|
||||
scale: newScale,
|
||||
currency_code: this.currency,
|
||||
amount: _newDinero.getAmount(),
|
||||
scale: _newDinero.getPrecision(),
|
||||
currency_code: _newDinero.getCurrency(),
|
||||
});
|
||||
}
|
||||
|
||||
add(addend: MoneyValue): MoneyValue {
|
||||
return new MoneyValue({
|
||||
amount: this.value.add(addend.value).getAmount(),
|
||||
amount: this.dinero.add(addend.dinero).getAmount(),
|
||||
scale: this.scale,
|
||||
currency_code: this.currency,
|
||||
});
|
||||
@ -87,7 +95,7 @@ export class MoneyValue extends ValueObject<IMoneyValueProps> implements IMoneyV
|
||||
|
||||
subtract(subtrahend: MoneyValue): MoneyValue {
|
||||
return new MoneyValue({
|
||||
amount: this.value.subtract(subtrahend.value).getAmount(),
|
||||
amount: this.dinero.subtract(subtrahend.dinero).getAmount(),
|
||||
scale: this.scale,
|
||||
currency_code: this.currency,
|
||||
});
|
||||
@ -95,7 +103,7 @@ export class MoneyValue extends ValueObject<IMoneyValueProps> implements IMoneyV
|
||||
|
||||
multiply(multiplier: number): MoneyValue {
|
||||
return new MoneyValue({
|
||||
amount: this.value.multiply(multiplier).getAmount(),
|
||||
amount: this.dinero.multiply(multiplier).getAmount(),
|
||||
scale: this.scale,
|
||||
currency_code: this.currency,
|
||||
});
|
||||
@ -103,26 +111,26 @@ export class MoneyValue extends ValueObject<IMoneyValueProps> implements IMoneyV
|
||||
|
||||
divide(divisor: number): MoneyValue {
|
||||
return new MoneyValue({
|
||||
amount: this.value.divide(divisor).getAmount(),
|
||||
amount: this.dinero.divide(divisor).getAmount(),
|
||||
scale: this.scale,
|
||||
currency_code: this.currency,
|
||||
});
|
||||
}
|
||||
|
||||
equalsTo(comparator: MoneyValue): boolean {
|
||||
return this.value.equalsTo(comparator.value);
|
||||
return this.dinero.equalsTo(comparator.dinero);
|
||||
}
|
||||
|
||||
greaterThan(comparator: MoneyValue): boolean {
|
||||
return this.value.greaterThan(comparator.value);
|
||||
return this.dinero.greaterThan(comparator.dinero);
|
||||
}
|
||||
|
||||
lessThan(comparator: MoneyValue): boolean {
|
||||
return this.value.lessThan(comparator.value);
|
||||
return this.dinero.lessThan(comparator.dinero);
|
||||
}
|
||||
|
||||
isZero(): boolean {
|
||||
return this.value.isZero();
|
||||
return this.dinero.isZero();
|
||||
}
|
||||
|
||||
isPositive(): boolean {
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
import { parsePhoneNumberWithError } from "libphonenumber-js";
|
||||
import { Maybe } from "../../helpers/maybe";
|
||||
import { PhoneNumber } from "./phone-number";
|
||||
|
||||
describe("PhoneNumber", () => {
|
||||
const validPhone = "+14155552671"; // Número válido en formato internacional
|
||||
const invalidPhone = "12345"; // Número inválido
|
||||
const nullablePhone = "";
|
||||
|
||||
test("debe crear un número de teléfono válido", () => {
|
||||
const result = PhoneNumber.create(validPhone);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data).toBeInstanceOf(PhoneNumber);
|
||||
});
|
||||
|
||||
test("debe fallar al crear un número de teléfono inválido", () => {
|
||||
const result = PhoneNumber.create(invalidPhone);
|
||||
expect(result.isFailure).toBe(true);
|
||||
expect(result.getError()?.message).toBe(
|
||||
"Please specify a valid phone number (include the international prefix)."
|
||||
);
|
||||
});
|
||||
|
||||
test("debe devolver None para valores nulos o vacíos", () => {
|
||||
const result = PhoneNumber.createNullable(nullablePhone);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data).toEqual(Maybe.None());
|
||||
});
|
||||
|
||||
test("debe devolver Some con un número de teléfono válido", () => {
|
||||
const result = PhoneNumber.createNullable(validPhone);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.isSome()).toBe(true);
|
||||
});
|
||||
|
||||
test("debe obtener el valor del número de teléfono", () => {
|
||||
const result = PhoneNumber.create(validPhone);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
const phoneNumber = result.data;
|
||||
expect(phoneNumber?.getValue()).toBe(validPhone);
|
||||
});
|
||||
|
||||
test("debe obtener el código de país del número", () => {
|
||||
const result = PhoneNumber.create(validPhone);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
const phoneNumber = result.data;
|
||||
expect(phoneNumber?.getCountryCode()).toBe("US");
|
||||
});
|
||||
|
||||
test("debe obtener el número nacional del teléfono", () => {
|
||||
const result = PhoneNumber.create(validPhone);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
const phoneNumber = result.data;
|
||||
expect(phoneNumber?.getNationalNumber()).toBe("4155552671");
|
||||
});
|
||||
|
||||
test("debe obtener el número formateado", () => {
|
||||
const result = PhoneNumber.create(validPhone);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
const phoneNumber = result.data;
|
||||
expect(phoneNumber?.getNumber()).toBe(parsePhoneNumberWithError(validPhone).number.toString());
|
||||
});
|
||||
|
||||
test("debe devolver undefined para la extensión si no hay una", () => {
|
||||
const result = PhoneNumber.create(validPhone);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
const phoneNumber = result.data;
|
||||
expect(phoneNumber?.getExtension()).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,64 @@
|
||||
import { PostalAddress } from "./postal-address";
|
||||
|
||||
describe("PostalAddress Value Object", () => {
|
||||
const validAddress = {
|
||||
street: "123 Main St",
|
||||
city: "Springfield",
|
||||
postalCode: "12345",
|
||||
state: "IL",
|
||||
country: "USA",
|
||||
};
|
||||
|
||||
test("✅ Debería crear un PostalAddress con valores válidos", () => {
|
||||
const result = PostalAddress.create(validAddress);
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data).toBeInstanceOf(PostalAddress);
|
||||
});
|
||||
|
||||
test("❌ Debería fallar al crear un PostalAddress con código postal inválido", () => {
|
||||
const invalidAddress = { ...validAddress, postalCode: "abc" }; // Código postal inválido
|
||||
const result = PostalAddress.create(invalidAddress);
|
||||
|
||||
expect(result.isFailure).toBe(true);
|
||||
expect(result.error?.message).toBe("Invalid postal code format");
|
||||
});
|
||||
|
||||
test("✅ `createNullable` debería devolver Maybe.None si los valores son nulos o vacíos", () => {
|
||||
expect(PostalAddress.createNullable().data.isSome()).toBe(false);
|
||||
expect(
|
||||
PostalAddress.createNullable({
|
||||
street: "",
|
||||
city: "",
|
||||
postalCode: "",
|
||||
state: "",
|
||||
country: "",
|
||||
}).data.isSome()
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test("✅ `createNullable` debería devolver Maybe.Some si los valores son válidos", () => {
|
||||
const result = PostalAddress.createNullable(validAddress);
|
||||
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.isSome()).toBe(true);
|
||||
expect(result.data.unwrap()).toBeInstanceOf(PostalAddress);
|
||||
});
|
||||
|
||||
test("✅ Métodos getters deberían devolver valores esperados", () => {
|
||||
const address = PostalAddress.create(validAddress).data;
|
||||
|
||||
expect(address.street).toBe(validAddress.street);
|
||||
expect(address.city).toBe(validAddress.city);
|
||||
expect(address.postalCode).toBe(validAddress.postalCode);
|
||||
expect(address.state).toBe(validAddress.state);
|
||||
expect(address.country).toBe(validAddress.country);
|
||||
});
|
||||
|
||||
test("✅ `toString()` debería devolver la representación correcta", () => {
|
||||
const address = PostalAddress.create(validAddress).data;
|
||||
const expectedString = `${validAddress.street}, ${validAddress.city}, ${validAddress.postalCode}, ${validAddress.state}, ${validAddress.country}`;
|
||||
|
||||
expect(address.toString()).toBe(expectedString);
|
||||
});
|
||||
});
|
||||
@ -5,8 +5,8 @@ import { ValueObject } from "./value-object";
|
||||
// 📌 Validaciones usando `zod`
|
||||
const postalCodeSchema = z
|
||||
.string()
|
||||
.min(4)
|
||||
.max(10)
|
||||
.min(4, "Invalid postal code format")
|
||||
.max(10, "Invalid postal code format")
|
||||
.regex(/^\d{4,10}$/, {
|
||||
message: "Invalid postal code format",
|
||||
});
|
||||
|
||||
112
apps/server/src/common/domain/value-objects/quantity.spec.ts
Normal file
112
apps/server/src/common/domain/value-objects/quantity.spec.ts
Normal file
@ -0,0 +1,112 @@
|
||||
import { Quantity } from "./quantity";
|
||||
|
||||
describe("Quantity", () => {
|
||||
describe("create", () => {
|
||||
it("debería crear una cantidad válida", () => {
|
||||
const result = Quantity.create({ amount: 100, scale: 2 });
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.amount).toBe(100);
|
||||
expect(result.data.scale).toBe(2);
|
||||
});
|
||||
|
||||
it("debería fallar si la escala es negativa", () => {
|
||||
const result = Quantity.create({ amount: 100, scale: -1 });
|
||||
expect(result.isFailure).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("toNumber & toString", () => {
|
||||
it("debería convertir correctamente a número", () => {
|
||||
const quantity = Quantity.create({ amount: 150, scale: 2 }).data;
|
||||
expect(quantity.toNumber()).toBe(1.5);
|
||||
});
|
||||
|
||||
it("debería convertir correctamente a string", () => {
|
||||
const quantity = Quantity.create({ amount: 123, scale: 2 }).data;
|
||||
expect(quantity.toString()).toBe("1.23");
|
||||
});
|
||||
});
|
||||
|
||||
describe("increment", () => {
|
||||
it("debería incrementar en 1 si no se pasa otra cantidad", () => {
|
||||
const quantity = Quantity.create({ amount: 100, scale: 2 }).data;
|
||||
const incremented = quantity.increment().data;
|
||||
expect(incremented.amount).toBe(101);
|
||||
expect(incremented.scale).toBe(2);
|
||||
});
|
||||
|
||||
it("debería sumar correctamente si tienen la misma escala", () => {
|
||||
const quantity1 = Quantity.create({ amount: 100, scale: 2 }).data;
|
||||
const quantity2 = Quantity.create({ amount: 50, scale: 2 }).data;
|
||||
|
||||
const result = quantity1.increment(quantity2);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.amount).toBe(150);
|
||||
});
|
||||
|
||||
it("debería fallar si las escalas son diferentes", () => {
|
||||
const quantity1 = Quantity.create({ amount: 100, scale: 2 }).data;
|
||||
const quantity2 = Quantity.create({ amount: 50, scale: 1 }).data;
|
||||
|
||||
const result = quantity1.increment(quantity2);
|
||||
expect(result.isFailure).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("decrement", () => {
|
||||
it("debería decrementar en 1 si no se pasa otra cantidad", () => {
|
||||
const quantity = Quantity.create({ amount: 100, scale: 2 }).data;
|
||||
const decremented = quantity.decrement().data;
|
||||
expect(decremented.amount).toBe(99);
|
||||
});
|
||||
|
||||
it("debería restar correctamente si tienen la misma escala", () => {
|
||||
const quantity1 = Quantity.create({ amount: 100, scale: 2 }).data;
|
||||
const quantity2 = Quantity.create({ amount: 50, scale: 2 }).data;
|
||||
|
||||
const result = quantity1.decrement(quantity2);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.amount).toBe(50);
|
||||
});
|
||||
|
||||
it("debería fallar si las escalas son diferentes", () => {
|
||||
const quantity1 = Quantity.create({ amount: 100, scale: 2 }).data;
|
||||
const quantity2 = Quantity.create({ amount: 50, scale: 1 }).data;
|
||||
|
||||
const result = quantity1.decrement(quantity2);
|
||||
expect(result.isFailure).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("convertScale", () => {
|
||||
it("debería convertir correctamente a una nueva escala", () => {
|
||||
const quantity = Quantity.create({ amount: 100, scale: 2 }).data;
|
||||
const result = quantity.convertScale(1);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.amount).toBe(10);
|
||||
expect(result.data.scale).toBe(1);
|
||||
});
|
||||
|
||||
it("debería fallar si la escala está fuera de rango", () => {
|
||||
const quantity = Quantity.create({ amount: 100, scale: 2 }).data;
|
||||
const result = quantity.convertScale(3);
|
||||
expect(result.isFailure).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hasSameScale", () => {
|
||||
it("debería retornar true si las escalas son iguales", () => {
|
||||
const quantity1 = Quantity.create({ amount: 100, scale: 2 }).data;
|
||||
const quantity2 = Quantity.create({ amount: 50, scale: 2 }).data;
|
||||
|
||||
expect(quantity1.hasSameScale(quantity2)).toBe(true);
|
||||
});
|
||||
|
||||
it("debería retornar false si las escalas son diferentes", () => {
|
||||
const quantity1 = Quantity.create({ amount: 100, scale: 2 }).data;
|
||||
const quantity2 = Quantity.create({ amount: 50, scale: 1 }).data;
|
||||
|
||||
expect(quantity1.hasSameScale(quantity2)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -27,7 +27,7 @@ export class Quantity extends ValueObject<IQuantityProps> implements IQuantity {
|
||||
protected static validate(values: IQuantityProps) {
|
||||
const schema = z.object({
|
||||
amount: z.number().int(),
|
||||
scale: z.number().int().min(0),
|
||||
scale: z.number().int().min(Quantity.MIN_SCALE).max(Quantity.MAX_SCALE),
|
||||
});
|
||||
|
||||
return schema.safeParse(values);
|
||||
@ -41,7 +41,7 @@ export class Quantity extends ValueObject<IQuantityProps> implements IQuantity {
|
||||
const checkProps = Quantity.validate(props);
|
||||
|
||||
if (!checkProps.success) {
|
||||
Result.fail(new Error(checkProps.error.errors[0].message));
|
||||
return Result.fail(new Error(checkProps.error.errors[0].message));
|
||||
}
|
||||
return Result.ok(new Quantity({ ...checkProps.data! }));
|
||||
}
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
import { TINNumber } from "./tin-number";
|
||||
|
||||
describe("TINNumber", () => {
|
||||
it("debería crear un TINNumber válido", () => {
|
||||
const result = TINNumber.create("12345");
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.getValue()).toBe("12345");
|
||||
});
|
||||
|
||||
it("debería fallar si el valor es demasiado corto", () => {
|
||||
const result = TINNumber.create("1");
|
||||
expect(result.isFailure).toBe(true);
|
||||
expect(result.error?.message).toBe("TIN must be at least 2 characters long");
|
||||
});
|
||||
|
||||
it("debería fallar si el valor es demasiado largo", () => {
|
||||
const result = TINNumber.create("12345678901");
|
||||
expect(result.isFailure).toBe(true);
|
||||
expect(result.error?.message).toBe("TIN must be at most 10 characters long");
|
||||
});
|
||||
|
||||
it("debería devolver None cuando el valor es nulo o vacío en createNullable", () => {
|
||||
const result = TINNumber.createNullable("");
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.isNone()).toBe(true);
|
||||
});
|
||||
|
||||
it("debería devolver Some cuando el valor es válido en createNullable", () => {
|
||||
const result = TINNumber.createNullable("6789");
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.isSome()).toBe(true);
|
||||
expect(result.data.unwrap()?.toString()).toBe("6789");
|
||||
});
|
||||
|
||||
it("debería devolver el valor correcto en toString()", () => {
|
||||
const result = TINNumber.create("ABC123");
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data.toString()).toBe("ABC123");
|
||||
});
|
||||
});
|
||||
@ -46,6 +46,6 @@ export class TINNumber extends ValueObject<TINNumberProps> {
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.props !== null && this.props !== undefined ? String(this.props) : "";
|
||||
return this.props.value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,10 @@ export class Maybe<T> {
|
||||
return this.value !== undefined;
|
||||
}
|
||||
|
||||
isNone(): boolean {
|
||||
return !this.isSome();
|
||||
}
|
||||
|
||||
unwrap(): T | undefined {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@ -1,67 +0,0 @@
|
||||
import { DomainEntity } from "@common/domain";
|
||||
import { Collection, Result } from "@common/helpers";
|
||||
import { Model } from "sequelize";
|
||||
import { SequelizeMapper } from "./sequelize-mapper";
|
||||
|
||||
// Mock Entities
|
||||
class MockEntity extends DomainEntity<any> {}
|
||||
class MockModel extends Model {
|
||||
dataValues: Record<string, any> = {};
|
||||
}
|
||||
|
||||
// Mock Mapper
|
||||
class MockSequelizeMapper extends SequelizeMapper<MockModel, Record<string, any>, MockEntity> {
|
||||
public mapToDomain(source: MockModel, params?: Record<string, any>): Result<MockEntity, Error> {
|
||||
return Result.ok(new MockEntity({ ...source.dataValues, ...params }));
|
||||
}
|
||||
|
||||
public mapToPersistence(
|
||||
source: MockEntity,
|
||||
params?: Record<string, any>
|
||||
): Result<Record<string, any>, Error> {
|
||||
return Result.ok({ ...source.props, ...params });
|
||||
}
|
||||
}
|
||||
|
||||
describe("SequelizeMapper", () => {
|
||||
let mapper: MockSequelizeMapper;
|
||||
let model: MockModel;
|
||||
|
||||
beforeEach(() => {
|
||||
mapper = new MockSequelizeMapper({});
|
||||
model = new MockModel();
|
||||
model.dataValues = { id: 1, name: "Test" };
|
||||
});
|
||||
|
||||
test("should map a model to a domain entity", () => {
|
||||
const result = mapper.mapToDomain(model);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data).toBeInstanceOf(MockEntity);
|
||||
expect(result.data.props.id).toBe(1);
|
||||
expect(result.data.props.name).toBe("Test");
|
||||
});
|
||||
|
||||
test("should map an entity to a persistence object", () => {
|
||||
const entity = new MockEntity({ id: 1, name: "Test" });
|
||||
const result = mapper.mapToPersistence(entity);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data).toEqual({ id: 1, name: "Test" });
|
||||
});
|
||||
|
||||
test("should map an array of models to a collection of domain entities", () => {
|
||||
const models = [model, { ...model, dataValues: { id: 2, name: "Test2" } }];
|
||||
const result = mapper.mapArrayToDomain(models);
|
||||
expect(result.isSuccess).toBe(true);
|
||||
expect(result.data).toBeInstanceOf(Collection);
|
||||
expect(result.data.items.length).toBe(2);
|
||||
});
|
||||
|
||||
test("should handle mapping failures gracefully", () => {
|
||||
jest
|
||||
.spyOn(mapper, "mapToDomain")
|
||||
.mockImplementation(() => Result.fail(new Error("Mapping failed")));
|
||||
const result = mapper.mapToDomain(model);
|
||||
expect(result.isFailure).toBe(true);
|
||||
expect(result.error?.message).toBe("Mapping failed");
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user