Skip to content

Commit 5e42f79

Browse files
committed
test: add rate limiting and comprehensive unit tests for creators and posts (#997, #998)
- Applied rate limiting via @UseGuards(ThrottlerGuard) to controllers - Added @Throttle({ short: { limit: 10, ttl: 60000 } }) to POST, PUT, DELETE write endpoints to limit 10 requests per minute - Expanded posts.controller.spec.ts with comprehensive unit tests covering: * create: service call, happy path, error cases * findAll: pagination, empty list, errors * findByAuthor: author filtering, empty list, errors * findOne: happy path, not found error * update: partial updates, not found error * remove (soft-delete): happy path, not found, default deletedBy handling - Added error tests to creators.controller.spec.ts for createPlan, getAllPlans, getPlans, getDashboard endpoints - All controller tests use mocked service, test happy and error paths - 429 status code will be returned by existing ThrottlerGuard when limits exceeded
1 parent 58d7eee commit 5e42f79

2 files changed

Lines changed: 426 additions & 48 deletions

File tree

backend/src/creators/creators.controller.spec.ts

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,151 @@ describe('CreatorsController', () => {
6060
await controller.listCreators('true');
6161
expect(mockCreatorsService.listCreators).toHaveBeenCalledWith(true);
6262
});
63+
64+
it('should return array of plans', async () => {
65+
const mockPlans = [
66+
{ id: 1, creator: 'user1', asset: 'native', amount: '100', intervalDays: 30 },
67+
{ id: 2, creator: 'user2', asset: 'native', amount: '50', intervalDays: 7 },
68+
];
69+
mockCreatorsService.listCreators.mockResolvedValue(mockPlans);
70+
71+
const result = await controller.listCreators('false');
72+
73+
expect(Array.isArray(result)).toBe(true);
74+
expect(result.length).toBe(2);
75+
});
76+
77+
it('should propagate service errors', async () => {
78+
const error = new Error('DB error');
79+
mockCreatorsService.listCreators.mockRejectedValue(error);
80+
81+
await expect(controller.listCreators(undefined)).rejects.toThrow(error);
82+
});
83+
});
84+
85+
describe('createPlan', () => {
86+
it('should call service.createPlan with correct parameters', async () => {
87+
const planBody = {
88+
creator: 'user1',
89+
asset: 'native',
90+
amount: '100',
91+
intervalDays: 30,
92+
};
93+
const mockPlan = { id: 1, ...planBody };
94+
mockCreatorsService.createPlan.mockResolvedValue(mockPlan);
95+
96+
await controller.createPlan(planBody);
97+
98+
expect(mockCreatorsService.createPlan).toHaveBeenCalledWith(
99+
'user1',
100+
'native',
101+
'100',
102+
30,
103+
);
104+
});
105+
106+
it('should return created plan with id', async () => {
107+
const planBody = {
108+
creator: 'user1',
109+
asset: 'native',
110+
amount: '100',
111+
intervalDays: 30,
112+
};
113+
const mockPlan = { id: 1, ...planBody };
114+
mockCreatorsService.createPlan.mockResolvedValue(mockPlan);
115+
116+
const result = await controller.createPlan(planBody);
117+
118+
expect(result).toEqual(mockPlan);
119+
expect(result.id).toBe(1);
120+
});
121+
122+
it('should propagate service errors', async () => {
123+
const planBody = {
124+
creator: 'user1',
125+
asset: 'native',
126+
amount: '100',
127+
intervalDays: 30,
128+
};
129+
const error = new Error('Invalid plan');
130+
mockCreatorsService.createPlan.mockRejectedValue(error);
131+
132+
await expect(controller.createPlan(planBody)).rejects.toThrow(error);
133+
});
134+
});
135+
136+
describe('getAllPlans', () => {
137+
it('should call service.findAllPlans with pagination', async () => {
138+
const pagination = { page: 1, limit: 20 };
139+
const mockResponse = new PaginatedResponseDto([], 20, null, false);
140+
mockCreatorsService.findAllPlans.mockReturnValue(mockResponse);
141+
142+
await controller.getAllPlans(pagination);
143+
144+
expect(mockCreatorsService.findAllPlans).toHaveBeenCalledWith(pagination);
145+
});
146+
147+
it('should return paginated plans', async () => {
148+
const pagination = { page: 1, limit: 20 };
149+
const mockPlans = [
150+
{ id: 1, creator: 'user1', asset: 'native', amount: '100', intervalDays: 30 },
151+
];
152+
const mockResponse = new PaginatedResponseDto(mockPlans, 20, null, false);
153+
mockCreatorsService.findAllPlans.mockReturnValue(mockResponse);
154+
155+
const result = await controller.getAllPlans(pagination);
156+
157+
expect(result.data).toHaveLength(1);
158+
expect(result.limit).toBe(20);
159+
});
160+
});
161+
162+
describe('getPlans', () => {
163+
it('should call service.findCreatorPlans with address and pagination', async () => {
164+
const address = 'GBCQ6C7OXWTKJ7APCIQPKK6X4CQBFGWJKW35GD7H5GMVVDANQCXLSV7';
165+
const pagination = { page: 1, limit: 20 };
166+
const mockResponse = new PaginatedResponseDto([], 20, null, false);
167+
mockCreatorsService.findCreatorPlans.mockReturnValue(mockResponse);
168+
169+
await controller.getPlans(address, pagination);
170+
171+
expect(mockCreatorsService.findCreatorPlans).toHaveBeenCalledWith(
172+
address,
173+
pagination,
174+
);
175+
});
176+
177+
it('should return creator plans', async () => {
178+
const address = 'GBCQ6C7OXWTKJ7APCIQPKK6X4CQBFGWJKW35GD7H5GMVVDANQCXLSV7';
179+
const pagination = { page: 1, limit: 20 };
180+
const mockPlans = [
181+
{ id: 1, creator: address, asset: 'native', amount: '100', intervalDays: 30 },
182+
];
183+
const mockResponse = new PaginatedResponseDto(mockPlans, 20, null, false);
184+
mockCreatorsService.findCreatorPlans.mockReturnValue(mockResponse);
185+
186+
const result = await controller.getPlans(address, pagination);
187+
188+
expect(result.data).toHaveLength(1);
189+
expect(result.data[0].creator).toBe(address);
190+
});
191+
});
192+
193+
describe('getDashboard', () => {
194+
it('should call dashboardService.getDashboard with address and query', async () => {
195+
const address = 'GBCQ6C7OXWTKJ7APCIQPKK6X4CQBFGWJKW35GD7H5GMVVDANQCXLSV7';
196+
const query = { period: 'month' };
197+
const mockDashboard = {
198+
totalRevenue: '1000',
199+
subscriberCount: 10,
200+
};
201+
const mockDashboardService = controller['dashboardService'];
202+
jest.spyOn(mockDashboardService, 'getDashboard').mockReturnValue(mockDashboard as any);
203+
204+
await controller.getDashboard(address, query as any);
205+
206+
expect(mockDashboardService.getDashboard).toHaveBeenCalledWith(address, query);
207+
});
63208
});
64209

65210

0 commit comments

Comments
 (0)