228 lines
6.8 KiB
TypeScript
228 lines
6.8 KiB
TypeScript
import { DailyActiveStats } from '../../../../src/domain/aggregates/daily-active-stats/daily-active-stats.aggregate';
|
|
import { DauCalculatedEvent } from '../../../../src/domain/events/dau-calculated.event';
|
|
|
|
describe('DailyActiveStats Aggregate', () => {
|
|
describe('create', () => {
|
|
it('should create DailyActiveStats with required properties', () => {
|
|
const day = new Date('2025-01-01');
|
|
const stats = DailyActiveStats.create({
|
|
day,
|
|
dauCount: 1000,
|
|
});
|
|
|
|
expect(stats.day).toEqual(day);
|
|
expect(stats.dauCount).toBe(1000);
|
|
expect(stats.dauByProvince).toBeInstanceOf(Map);
|
|
expect(stats.dauByProvince.size).toBe(0);
|
|
expect(stats.dauByCity).toBeInstanceOf(Map);
|
|
expect(stats.dauByCity.size).toBe(0);
|
|
expect(stats.calculatedAt).toBeInstanceOf(Date);
|
|
expect(stats.version).toBe(1);
|
|
});
|
|
|
|
it('should create DailyActiveStats with province breakdown', () => {
|
|
const byProvince = new Map<string, number>([
|
|
['Shanghai', 500],
|
|
['Beijing', 300],
|
|
['Guangdong', 200],
|
|
]);
|
|
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 1000,
|
|
dauByProvince: byProvince,
|
|
});
|
|
|
|
expect(stats.dauByProvince.size).toBe(3);
|
|
expect(stats.dauByProvince.get('Shanghai')).toBe(500);
|
|
expect(stats.dauByProvince.get('Beijing')).toBe(300);
|
|
});
|
|
|
|
it('should create DailyActiveStats with city breakdown', () => {
|
|
const byCity = new Map<string, number>([
|
|
['Shanghai', 500],
|
|
['Shenzhen', 200],
|
|
]);
|
|
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 700,
|
|
dauByCity: byCity,
|
|
});
|
|
|
|
expect(stats.dauByCity.size).toBe(2);
|
|
expect(stats.dauByCity.get('Shanghai')).toBe(500);
|
|
});
|
|
|
|
it('should apply DauCalculatedEvent on create', () => {
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 1000,
|
|
});
|
|
|
|
const events = stats.getUncommittedEvents();
|
|
expect(events.length).toBe(1);
|
|
expect(events[0]).toBeInstanceOf(DauCalculatedEvent);
|
|
});
|
|
|
|
it('should handle zero DAU count', () => {
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 0,
|
|
});
|
|
|
|
expect(stats.dauCount).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('recalculate', () => {
|
|
it('should update DAU count', () => {
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 1000,
|
|
});
|
|
|
|
stats.commit(); // Clear initial events
|
|
const oldCalculatedAt = stats.calculatedAt;
|
|
|
|
// Wait a tiny bit to ensure calculatedAt changes
|
|
stats.recalculate(1500);
|
|
|
|
expect(stats.dauCount).toBe(1500);
|
|
expect(stats.version).toBe(2);
|
|
});
|
|
|
|
it('should update province breakdown', () => {
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 1000,
|
|
});
|
|
|
|
const newByProvince = new Map<string, number>([
|
|
['Shanghai', 800],
|
|
['Beijing', 700],
|
|
]);
|
|
|
|
stats.recalculate(1500, newByProvince);
|
|
|
|
expect(stats.dauByProvince.get('Shanghai')).toBe(800);
|
|
expect(stats.dauByProvince.get('Beijing')).toBe(700);
|
|
});
|
|
|
|
it('should update city breakdown', () => {
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 1000,
|
|
});
|
|
|
|
const newByCity = new Map<string, number>([
|
|
['Shenzhen', 300],
|
|
]);
|
|
|
|
stats.recalculate(1500, undefined, newByCity);
|
|
|
|
expect(stats.dauByCity.get('Shenzhen')).toBe(300);
|
|
});
|
|
|
|
it('should increment version', () => {
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 1000,
|
|
});
|
|
|
|
expect(stats.version).toBe(1);
|
|
|
|
stats.recalculate(1100);
|
|
expect(stats.version).toBe(2);
|
|
|
|
stats.recalculate(1200);
|
|
expect(stats.version).toBe(3);
|
|
});
|
|
|
|
it('should apply DauCalculatedEvent on recalculate', () => {
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 1000,
|
|
});
|
|
|
|
stats.commit(); // Clear create event
|
|
stats.recalculate(1500);
|
|
|
|
const events = stats.getUncommittedEvents();
|
|
expect(events.length).toBe(1);
|
|
expect(events[0]).toBeInstanceOf(DauCalculatedEvent);
|
|
});
|
|
});
|
|
|
|
describe('reconstitute', () => {
|
|
it('should reconstitute from persistence data', () => {
|
|
const day = new Date('2025-01-01');
|
|
const calculatedAt = new Date('2025-01-01T23:00:00.000Z');
|
|
const byProvince = new Map<string, number>([['Shanghai', 500]]);
|
|
const byCity = new Map<string, number>([['Shanghai', 500]]);
|
|
|
|
const stats = DailyActiveStats.reconstitute({
|
|
day,
|
|
dauCount: 2000,
|
|
dauByProvince: byProvince,
|
|
dauByCity: byCity,
|
|
calculatedAt,
|
|
version: 5,
|
|
});
|
|
|
|
expect(stats.day).toEqual(day);
|
|
expect(stats.dauCount).toBe(2000);
|
|
expect(stats.dauByProvince.get('Shanghai')).toBe(500);
|
|
expect(stats.dauByCity.get('Shanghai')).toBe(500);
|
|
expect(stats.calculatedAt).toEqual(calculatedAt);
|
|
expect(stats.version).toBe(5);
|
|
});
|
|
|
|
it('should not apply events on reconstitute', () => {
|
|
const stats = DailyActiveStats.reconstitute({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 2000,
|
|
dauByProvince: new Map(),
|
|
dauByCity: new Map(),
|
|
calculatedAt: new Date(),
|
|
version: 1,
|
|
});
|
|
|
|
const events = stats.getUncommittedEvents();
|
|
expect(events.length).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('getters return copies', () => {
|
|
it('should return a copy of dauByProvince', () => {
|
|
const byProvince = new Map<string, number>([['Shanghai', 500]]);
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 500,
|
|
dauByProvince: byProvince,
|
|
});
|
|
|
|
const returned = stats.dauByProvince;
|
|
returned.set('NewProvince', 100);
|
|
|
|
// Original should not be modified
|
|
expect(stats.dauByProvince.has('NewProvince')).toBe(false);
|
|
});
|
|
|
|
it('should return a copy of dauByCity', () => {
|
|
const byCity = new Map<string, number>([['Shenzhen', 300]]);
|
|
const stats = DailyActiveStats.create({
|
|
day: new Date('2025-01-01'),
|
|
dauCount: 300,
|
|
dauByCity: byCity,
|
|
});
|
|
|
|
const returned = stats.dauByCity;
|
|
returned.set('NewCity', 50);
|
|
|
|
// Original should not be modified
|
|
expect(stats.dauByCity.has('NewCity')).toBe(false);
|
|
});
|
|
});
|
|
});
|