130 lines
5.2 KiB
TypeScript
130 lines
5.2 KiB
TypeScript
|
|
import { DisputeFlowService } from '../../backend/src/dispute-flow/dispute-flow.service';
|
||
|
|
import { db } from '../../backend/src/db';
|
||
|
|
|
||
|
|
// Mock the database connection for testing
|
||
|
|
jest.mock('../../backend/src/db', () => ({
|
||
|
|
db: {
|
||
|
|
query: jest.fn()
|
||
|
|
}
|
||
|
|
}));
|
||
|
|
|
||
|
|
describe('Dispute Flow Contract Tests', () => {
|
||
|
|
let service: DisputeFlowService;
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
service = new DisputeFlowService();
|
||
|
|
// Reset all mocks before each test
|
||
|
|
jest.clearAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should create a dispute with all required fields', async () => {
|
||
|
|
const mockDispute = {
|
||
|
|
id: 1,
|
||
|
|
dealId: 123,
|
||
|
|
openedByUserId: 456,
|
||
|
|
status: 'open',
|
||
|
|
reasonCode: 'NO_SHOW',
|
||
|
|
summary: 'Helper did not show up',
|
||
|
|
requestedOutcome: 'refund',
|
||
|
|
createdAt: new Date(),
|
||
|
|
updatedAt: new Date()
|
||
|
|
};
|
||
|
|
|
||
|
|
(db.query as jest.Mock).mockResolvedValue({ rows: [mockDispute] });
|
||
|
|
|
||
|
|
const result = await service.createDispute({
|
||
|
|
dealId: 123,
|
||
|
|
openedByUserId: 456,
|
||
|
|
reasonCode: 'NO_SHOW',
|
||
|
|
summary: 'Helper did not show up',
|
||
|
|
requestedOutcome: 'refund'
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(result).toHaveProperty('id');
|
||
|
|
expect(result).toHaveProperty('dealId');
|
||
|
|
expect(result).toHaveProperty('openedByUserId');
|
||
|
|
expect(result).toHaveProperty('status', 'open');
|
||
|
|
expect(result).toHaveProperty('reasonCode');
|
||
|
|
expect(result).toHaveProperty('summary');
|
||
|
|
expect(result).toHaveProperty('requestedOutcome');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should transition dispute status correctly through the flow', async () => {
|
||
|
|
// Mock initial creation
|
||
|
|
(db.query as jest.Mock)
|
||
|
|
.mockResolvedValueOnce({ rows: [{ id: 1, dealId: 123, openedByUserId: 456, status: 'open', reasonCode: 'NO_SHOW', summary: 'Helper did not show up', requestedOutcome: 'refund', createdAt: new Date(), updatedAt: new Date() }] })
|
||
|
|
.mockResolvedValueOnce({}) // updateDisputeStatus
|
||
|
|
.mockResolvedValueOnce({}) // addEvidence
|
||
|
|
.mockResolvedValueOnce({}) // updateDisputeStatus to mediation
|
||
|
|
.mockResolvedValueOnce({}) // resolveDispute
|
||
|
|
.mockResolvedValueOnce({ rows: [{ id: 1, disputeId: 1, eventType: 'resolved', actorUserId: 456, payloadJson: JSON.stringify({ decision: 'refund', reason: 'Helper did not show up' }), createdAt: new Date() }] }); // getDisputeEvents
|
||
|
|
|
||
|
|
const dispute = await service.createDispute({
|
||
|
|
dealId: 123,
|
||
|
|
openedByUserId: 456,
|
||
|
|
reasonCode: 'NO_SHOW',
|
||
|
|
summary: 'Helper did not show up',
|
||
|
|
requestedOutcome: 'refund'
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(dispute.status).toBe('open');
|
||
|
|
|
||
|
|
// Transition to evidence
|
||
|
|
await service.updateDisputeStatus(1, 'evidence', 456);
|
||
|
|
|
||
|
|
// Add evidence
|
||
|
|
await service.addEvidence(1, { file: 'test.jpg' }, 456);
|
||
|
|
|
||
|
|
// Transition to mediation
|
||
|
|
await service.updateDisputeStatus(1, 'mediation', 456);
|
||
|
|
|
||
|
|
// Resolve dispute
|
||
|
|
await service.resolveDispute(1, { decision: 'refund', decisionReason: 'Helper did not show up' }, 456);
|
||
|
|
|
||
|
|
const events = await service.getDisputeEvents(1);
|
||
|
|
expect(events).toHaveLength(4); // open, evidence, mediation, resolved
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should log all dispute events correctly', async () => {
|
||
|
|
(db.query as jest.Mock)
|
||
|
|
.mockResolvedValueOnce({ rows: [{ id: 1, dealId: 123, openedByUserId: 456, status: 'open', reasonCode: 'NO_SHOW', summary: 'Helper did not show up', requestedOutcome: 'refund', createdAt: new Date(), updatedAt: new Date() }] })
|
||
|
|
.mockResolvedValueOnce({}) // addEvidence
|
||
|
|
.mockResolvedValueOnce({ rows: [{ id: 1, disputeId: 1, eventType: 'evidence', actorUserId: 456, payloadJson: JSON.stringify({ file: 'test.jpg' }), createdAt: new Date() }] });
|
||
|
|
|
||
|
|
const dispute = await service.createDispute({
|
||
|
|
dealId: 123,
|
||
|
|
openedByUserId: 456,
|
||
|
|
reasonCode: 'NO_SHOW',
|
||
|
|
summary: 'Helper did not show up',
|
||
|
|
requestedOutcome: 'refund'
|
||
|
|
});
|
||
|
|
|
||
|
|
await service.addEvidence(1, { file: 'test.jpg' }, 456);
|
||
|
|
|
||
|
|
const events = await service.getDisputeEvents(1);
|
||
|
|
expect(events[0]).toHaveProperty('eventType', 'evidence');
|
||
|
|
expect(events[0].payloadJson).toContain('test.jpg');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should handle final decision with audit trail', async () => {
|
||
|
|
(db.query as jest.Mock)
|
||
|
|
.mockResolvedValueOnce({ rows: [{ id: 1, dealId: 123, openedByUserId: 456, status: 'open', reasonCode: 'NO_SHOW', summary: 'Helper did not show up', requestedOutcome: 'refund', createdAt: new Date(), updatedAt: new Date() }] })
|
||
|
|
.mockResolvedValueOnce({}) // resolveDispute
|
||
|
|
.mockResolvedValueOnce({ rows: [{ id: 1, disputeId: 1, eventType: 'resolved', actorUserId: 456, payloadJson: JSON.stringify({ decision: 'refund', reason: 'Helper did not show up' }), createdAt: new Date() }] });
|
||
|
|
|
||
|
|
const dispute = await service.createDispute({
|
||
|
|
dealId: 123,
|
||
|
|
openedByUserId: 456,
|
||
|
|
reasonCode: 'NO_SHOW',
|
||
|
|
summary: 'Helper did not show up',
|
||
|
|
requestedOutcome: 'refund'
|
||
|
|
});
|
||
|
|
|
||
|
|
await service.resolveDispute(1, { decision: 'refund', decisionReason: 'Helper did not show up' }, 456);
|
||
|
|
|
||
|
|
const events = await service.getDisputeEvents(1);
|
||
|
|
expect(events[events.length - 1]).toHaveProperty('eventType', 'resolved');
|
||
|
|
expect(events[events.length - 1].payloadJson).toContain('refund');
|
||
|
|
expect(events[events.length - 1].payloadJson).toContain('Helper did not show up');
|
||
|
|
});
|
||
|
|
});
|