good forst commit
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import { handleCommand } from './command-handler';
|
||||
import type { NormalizedMessage } from '@tower/types';
|
||||
|
||||
function makeMsg(overrides: Partial<NormalizedMessage> = {}): NormalizedMessage {
|
||||
return {
|
||||
platformMsgId: 'WA_MSG_001',
|
||||
sourceGroupJid: '120363043312345678@g.us',
|
||||
senderJid: '919876543210@s.whatsapp.net',
|
||||
senderName: 'Alice',
|
||||
content: '',
|
||||
accountId: 'acc-1',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
const mockPrisma: any = {
|
||||
group: { findUnique: jest.fn() },
|
||||
towerUser: { upsert: jest.fn() },
|
||||
consentRecord: { findFirst: jest.fn(), create: jest.fn(), update: jest.fn(), updateMany: jest.fn() },
|
||||
memberOptOut: { create: jest.fn() },
|
||||
auditEvent: { create: jest.fn() },
|
||||
};
|
||||
|
||||
const mockPool: any = {
|
||||
sendMessage: jest.fn().mockResolvedValue(undefined),
|
||||
};
|
||||
|
||||
describe('handleCommand', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('returns false for non-command messages', async () => {
|
||||
const handled = await handleCommand(makeMsg({ content: 'hello world' }), 'acc-1', mockPrisma, mockPool);
|
||||
expect(handled).toBe(false);
|
||||
expect(mockPool.sendMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('STOP', () => {
|
||||
it('creates opt-out and revokes consent for claimed group', async () => {
|
||||
mockPrisma.group.findUnique.mockResolvedValue({ id: 'grp-1', tenantId: 'tnt-1', claimStatus: 'CLAIMED' });
|
||||
mockPrisma.towerUser.upsert.mockResolvedValue({ id: 'user-1' });
|
||||
mockPrisma.consentRecord.updateMany.mockResolvedValue({ count: 1 });
|
||||
mockPrisma.memberOptOut.create.mockResolvedValue({});
|
||||
mockPrisma.auditEvent.create.mockResolvedValue({});
|
||||
|
||||
const handled = await handleCommand(
|
||||
makeMsg({ content: 'STOP' }),
|
||||
'acc-1',
|
||||
mockPrisma,
|
||||
mockPool,
|
||||
);
|
||||
expect(handled).toBe(true);
|
||||
expect(mockPrisma.consentRecord.updateMany).toHaveBeenCalled();
|
||||
expect(mockPrisma.memberOptOut.create).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ data: expect.objectContaining({ reason: 'STOP_KEYWORD' }) }),
|
||||
);
|
||||
expect(mockPool.sendMessage).toHaveBeenCalledWith(
|
||||
'acc-1',
|
||||
'919876543210@s.whatsapp.net',
|
||||
expect.stringContaining("opted out"),
|
||||
);
|
||||
});
|
||||
|
||||
it('is a no-op for non-claimed groups', async () => {
|
||||
mockPrisma.group.findUnique.mockResolvedValue({ id: 'grp-1', claimStatus: 'PENDING_CLAIM' });
|
||||
const handled = await handleCommand(
|
||||
makeMsg({ content: 'STOP' }),
|
||||
'acc-1',
|
||||
mockPrisma,
|
||||
mockPool,
|
||||
);
|
||||
expect(handled).toBe(false);
|
||||
expect(mockPrisma.consentRecord.updateMany).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('START', () => {
|
||||
it('re-grants default scopes', async () => {
|
||||
mockPrisma.group.findUnique.mockResolvedValue({ id: 'grp-1', tenantId: 'tnt-1', claimStatus: 'CLAIMED' });
|
||||
mockPrisma.towerUser.upsert.mockResolvedValue({ id: 'user-1' });
|
||||
mockPrisma.consentRecord.findFirst.mockResolvedValue({
|
||||
id: 'c-1',
|
||||
scopes: ['INGEST'],
|
||||
retentionDays: 90,
|
||||
});
|
||||
mockPrisma.consentRecord.update.mockResolvedValue({});
|
||||
|
||||
const handled = await handleCommand(
|
||||
makeMsg({ content: 'start' }),
|
||||
'acc-1',
|
||||
mockPrisma,
|
||||
mockPool,
|
||||
);
|
||||
expect(handled).toBe(true);
|
||||
expect(mockPrisma.consentRecord.update).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
where: { id: 'c-1' },
|
||||
data: expect.objectContaining({ status: 'GRANTED' }),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PORTAL', () => {
|
||||
it('sends an onboarding link', async () => {
|
||||
mockPrisma.group.findUnique.mockResolvedValue({ id: 'grp-1', tenantId: 'tnt-1', claimStatus: 'CLAIMED' });
|
||||
mockPrisma.towerUser.upsert.mockResolvedValue({ id: 'user-1' });
|
||||
|
||||
const handled = await handleCommand(
|
||||
makeMsg({ content: 'portal' }),
|
||||
'acc-1',
|
||||
mockPrisma,
|
||||
mockPool,
|
||||
);
|
||||
expect(handled).toBe(true);
|
||||
expect(mockPool.sendMessage).toHaveBeenCalledWith(
|
||||
'acc-1',
|
||||
'919876543210@s.whatsapp.net',
|
||||
expect.stringContaining('/onboard?token='),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user