rating
This commit is contained in:
174
core/identity/domain/entities/RatingEvent.test.ts
Normal file
174
core/identity/domain/entities/RatingEvent.test.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import { RatingEvent } from './RatingEvent';
|
||||
import { RatingEventId } from '../value-objects/RatingEventId';
|
||||
import { RatingDimensionKey } from '../value-objects/RatingDimensionKey';
|
||||
import { RatingDelta } from '../value-objects/RatingDelta';
|
||||
import { IdentityDomainValidationError, IdentityDomainInvariantError } from '../errors/IdentityDomainError';
|
||||
|
||||
describe('RatingEvent', () => {
|
||||
const validProps = {
|
||||
id: RatingEventId.create('123e4567-e89b-12d3-a456-426614174000'),
|
||||
userId: 'user-123',
|
||||
dimension: RatingDimensionKey.create('driving'),
|
||||
delta: RatingDelta.create(10),
|
||||
occurredAt: new Date('2024-01-01T00:00:00Z'),
|
||||
createdAt: new Date('2024-01-01T00:00:00Z'),
|
||||
source: {
|
||||
type: 'race' as const,
|
||||
id: 'race-456',
|
||||
},
|
||||
reason: {
|
||||
code: 'DRIVING_FINISH_STRENGTH_GAIN',
|
||||
summary: 'Finished 3rd in strong field',
|
||||
details: { position: 3, fieldStrength: 2500 },
|
||||
},
|
||||
visibility: {
|
||||
public: true,
|
||||
redactedFields: [] as string[],
|
||||
},
|
||||
version: 1,
|
||||
};
|
||||
|
||||
describe('create', () => {
|
||||
it('should create a valid rating event', () => {
|
||||
const event = RatingEvent.create(validProps);
|
||||
|
||||
expect(event.id.value).toBe(validProps.id.value);
|
||||
expect(event.userId).toBe(validProps.userId);
|
||||
expect(event.dimension.value).toBe('driving');
|
||||
expect(event.delta.value).toBe(10);
|
||||
expect(event.occurredAt).toEqual(validProps.occurredAt);
|
||||
expect(event.source.type).toBe('race');
|
||||
expect(event.reason.code).toBe('DRIVING_FINISH_STRENGTH_GAIN');
|
||||
expect(event.visibility.public).toBe(true);
|
||||
expect(event.version).toBe(1);
|
||||
});
|
||||
|
||||
it('should create event with optional weight', () => {
|
||||
const props = { ...validProps, weight: 2 };
|
||||
const event = RatingEvent.create(props);
|
||||
|
||||
expect(event.weight).toBe(2);
|
||||
});
|
||||
|
||||
it('should create event with non-public visibility', () => {
|
||||
const props = {
|
||||
...validProps,
|
||||
visibility: { public: false, redactedFields: ['reason.summary'] },
|
||||
};
|
||||
const event = RatingEvent.create(props);
|
||||
|
||||
expect(event.visibility.public).toBe(false);
|
||||
expect(event.visibility.redactedFields).toEqual(['reason.summary']);
|
||||
});
|
||||
|
||||
it('should throw for missing userId', () => {
|
||||
const props = { ...validProps, userId: '' };
|
||||
expect(() => RatingEvent.create(props)).toThrow(IdentityDomainValidationError);
|
||||
});
|
||||
|
||||
it('should throw for missing dimension', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { dimension: _dimension, ...rest } = validProps;
|
||||
expect(() => RatingEvent.create(rest as typeof validProps)).toThrow(IdentityDomainValidationError);
|
||||
});
|
||||
|
||||
it('should throw for missing delta', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { delta: _delta, ...rest } = validProps;
|
||||
expect(() => RatingEvent.create(rest as typeof validProps)).toThrow(IdentityDomainValidationError);
|
||||
});
|
||||
|
||||
it('should throw for missing source', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { source: _source, ...rest } = validProps;
|
||||
expect(() => RatingEvent.create(rest as typeof validProps)).toThrow(IdentityDomainValidationError);
|
||||
});
|
||||
|
||||
it('should throw for missing reason', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { reason: _reason, ...rest } = validProps;
|
||||
expect(() => RatingEvent.create(rest as typeof validProps)).toThrow(IdentityDomainValidationError);
|
||||
});
|
||||
|
||||
it('should throw for missing visibility', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { visibility: _visibility, ...rest } = validProps;
|
||||
expect(() => RatingEvent.create(rest as typeof validProps)).toThrow(IdentityDomainValidationError);
|
||||
});
|
||||
|
||||
it('should throw for invalid version', () => {
|
||||
const props = { ...validProps, version: 0 };
|
||||
expect(() => RatingEvent.create(props)).toThrow(IdentityDomainValidationError);
|
||||
});
|
||||
|
||||
it('should throw for future occurredAt', () => {
|
||||
const futureDate = new Date(Date.now() + 86400000);
|
||||
const props = { ...validProps, occurredAt: futureDate };
|
||||
expect(() => RatingEvent.create(props)).toThrow(IdentityDomainValidationError);
|
||||
});
|
||||
|
||||
it('should throw for future createdAt', () => {
|
||||
const futureDate = new Date(Date.now() + 86400000);
|
||||
const props = { ...validProps, createdAt: futureDate };
|
||||
expect(() => RatingEvent.create(props)).toThrow(IdentityDomainValidationError);
|
||||
});
|
||||
|
||||
it('should throw for occurredAt after createdAt', () => {
|
||||
const props = {
|
||||
...validProps,
|
||||
occurredAt: new Date('2024-01-02T00:00:00Z'),
|
||||
createdAt: new Date('2024-01-01T00:00:00Z'),
|
||||
};
|
||||
expect(() => RatingEvent.create(props)).toThrow(IdentityDomainInvariantError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('rehydrate', () => {
|
||||
it('should rehydrate event from stored data', () => {
|
||||
const event = RatingEvent.rehydrate(validProps);
|
||||
|
||||
expect(event.id.value).toBe(validProps.id.value);
|
||||
expect(event.userId).toBe(validProps.userId);
|
||||
expect(event.dimension.value).toBe('driving');
|
||||
});
|
||||
|
||||
it('should rehydrate with optional weight', () => {
|
||||
const props = { ...validProps, weight: 2 };
|
||||
const event = RatingEvent.rehydrate(props);
|
||||
|
||||
expect(event.weight).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('equals', () => {
|
||||
it('should return true for same ID', () => {
|
||||
const event1 = RatingEvent.create(validProps);
|
||||
const event2 = RatingEvent.rehydrate(validProps);
|
||||
|
||||
expect(event1.equals(event2)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for different IDs', () => {
|
||||
const event1 = RatingEvent.create(validProps);
|
||||
const event2 = RatingEvent.create({
|
||||
...validProps,
|
||||
id: RatingEventId.create('123e4567-e89b-12d3-a456-426614174001'),
|
||||
});
|
||||
|
||||
expect(event1.equals(event2)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toJSON', () => {
|
||||
it('should return plain object representation', () => {
|
||||
const event = RatingEvent.create(validProps);
|
||||
const json = event.toJSON();
|
||||
|
||||
expect(json.id).toBe(validProps.id.value);
|
||||
expect(json.userId).toBe(validProps.userId);
|
||||
expect(json.dimension).toBe('driving');
|
||||
expect(json.delta).toBe(10);
|
||||
expect(json.source).toEqual({ type: 'race', id: 'race-456' });
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user