client and some admin new

Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
2026-08-05 04:32:43 +08:00
parent 8922f7f2f4
commit 0c7f5ccd0f
33 changed files with 937 additions and 770 deletions
+91
View File
@@ -0,0 +1,91 @@
'use strict';
// ── Regression tests for the "revoke plan access, no refund" feature ────────
// revokePlanSubscriberAccess() must replicate revokeTier's single-record
// "auto-downgrade to Free only if the user holds no other active tier" rule
// (controllers/admin/tiers.controller.js) instead of blanket-downgrading
// everyone, and must fire exactly one in-app notification batch plus one
// email per affected user.
jest.mock('../../models/tiers/user_tiers.mdl', () => ({
findAll: jest.fn(),
update: jest.fn(),
count: jest.fn(),
create: jest.fn(),
}));
jest.mock('../../models/users/users.mdl', () => ({ findAll: jest.fn() }));
jest.mock('../../models/notifications/user_notification.mdl', () => ({ bulkCreate: jest.fn() }));
jest.mock('../../services/email.service', () => ({ sendEmail: jest.fn().mockResolvedValue(true) }));
const mdl_UserTiers = require('../../models/tiers/user_tiers.mdl');
const mdl_Users = require('../../models/users/users.mdl');
const UserNotification = require('../../models/notifications/user_notification.mdl');
const { sendEmail } = require('../../services/email.service');
const { revokePlanSubscriberAccess } = require('../../services/planAccess.service');
function makePlan(overrides = {}) {
return { plan_id: 10, label: 'Premium – 1 Month', ...overrides };
}
beforeEach(() => jest.clearAllMocks());
describe('revokePlanSubscriberAccess()', () => {
test('no active subscribers → no-op, returns zero count', async () => {
mdl_UserTiers.findAll.mockResolvedValue([]);
const result = await revokePlanSubscriberAccess(makePlan(), 99);
expect(result).toEqual({ revoked_user_count: 0 });
expect(mdl_UserTiers.update).not.toHaveBeenCalled();
expect(UserNotification.bulkCreate).not.toHaveBeenCalled();
expect(sendEmail).not.toHaveBeenCalled();
});
test('a user with ONLY this plan active gets auto-downgraded to Free', async () => {
mdl_UserTiers.findAll.mockResolvedValue([{ tier_id: 1, user_id: 5 }]);
mdl_UserTiers.count.mockResolvedValue(0); // no other active tier remains
mdl_Users.findAll.mockResolvedValue([{ user_id: 5, email: 'a@b.com', personal_info: { name: { full_name: 'Ana' } } }]);
const result = await revokePlanSubscriberAccess(makePlan(), 99);
expect(mdl_UserTiers.update).toHaveBeenCalledWith(
expect.objectContaining({ status: 'revoked', revoked_by: 99 }),
{ where: { tier_id: [1] } }
);
expect(mdl_UserTiers.create).toHaveBeenCalledWith(
expect.objectContaining({ user_id: '5', tier: 'free', status: 'active' })
);
expect(result).toEqual({ revoked_user_count: 1 });
});
test('a user with ANOTHER concurrently-active plan does NOT get downgraded', async () => {
mdl_UserTiers.findAll.mockResolvedValue([{ tier_id: 2, user_id: 6 }]);
mdl_UserTiers.count.mockResolvedValue(1); // still holds a different active plan
mdl_Users.findAll.mockResolvedValue([{ user_id: 6, email: 'c@d.com', personal_info: {} }]);
await revokePlanSubscriberAccess(makePlan(), 99);
expect(mdl_UserTiers.create).not.toHaveBeenCalled();
});
test('fires exactly one notification batch and one email per affected user', async () => {
mdl_UserTiers.findAll.mockResolvedValue([
{ tier_id: 1, user_id: 5 },
{ tier_id: 2, user_id: 6 },
]);
mdl_UserTiers.count.mockResolvedValue(1);
mdl_Users.findAll.mockResolvedValue([
{ user_id: 5, email: 'a@b.com', personal_info: {} },
{ user_id: 6, email: 'c@d.com', personal_info: {} },
]);
const result = await revokePlanSubscriberAccess(makePlan(), 99);
expect(UserNotification.bulkCreate).toHaveBeenCalledTimes(1);
expect(UserNotification.bulkCreate.mock.calls[0][0]).toHaveLength(2);
expect(sendEmail).toHaveBeenCalledTimes(2);
expect(sendEmail).toHaveBeenCalledWith(expect.objectContaining({ to: 'a@b.com', type: 'TIER_ACCESS_REVOKED' }));
expect(result).toEqual({ revoked_user_count: 2 });
});
});