Skip to content

Commit 2305576

Browse files
committed
chore: add delete reaction flow tests
1 parent 57dadda commit 2305576

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

test/unit/channel.test.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,3 +1569,157 @@ describe('send reaction flow', () => {
15691569
});
15701570
});
15711571
});
1572+
1573+
describe('delete reaction flow', () => {
1574+
const messageId = 'msg-123';
1575+
const reactionType = 'love';
1576+
const user_id = 'user-abc';
1577+
1578+
let client;
1579+
let channel;
1580+
let loggerSpy;
1581+
let queueTaskSpy;
1582+
let deleteReactionSpy;
1583+
let deleteSpy;
1584+
1585+
beforeEach(async () => {
1586+
client = await getClientWithUser({ id: user_id });
1587+
const offlineDb = new MockOfflineDB({ client });
1588+
1589+
client.setOfflineDBApi(offlineDb);
1590+
await client.offlineDb.init(client.userID);
1591+
1592+
channel = client.channel('messaging', 'test');
1593+
// trick the channel into being initialized
1594+
channel.initialized = true;
1595+
1596+
// Add a fake message to state for reaction deletion optimistic update in the db
1597+
channel.state.messages.push({ id: messageId });
1598+
1599+
loggerSpy = vi.spyOn(client, 'logger').mockImplementation(vi.fn());
1600+
queueTaskSpy = vi.spyOn(client.offlineDb, 'queueTask').mockResolvedValue({});
1601+
deleteReactionSpy = vi.spyOn(client.offlineDb, 'deleteReaction').mockResolvedValue();
1602+
deleteSpy = vi.spyOn(client, 'delete').mockResolvedValue({});
1603+
});
1604+
1605+
afterEach(() => {
1606+
vi.resetAllMocks();
1607+
});
1608+
1609+
describe('deleteReaction', () => {
1610+
beforeEach(() => {
1611+
vi.spyOn(channel, '_deleteReaction').mockResolvedValue({});
1612+
});
1613+
1614+
afterEach(() => {
1615+
vi.resetAllMocks();
1616+
});
1617+
1618+
it('throws if messageID or reactionType is missing', async () => {
1619+
await expect(channel.deleteReaction('', reactionType)).rejects.toThrow(
1620+
'Deleting a reaction requires specifying both the message and reaction type',
1621+
);
1622+
await expect(channel.deleteReaction(messageId, '')).rejects.toThrow(
1623+
'Deleting a reaction requires specifying both the message and reaction type',
1624+
);
1625+
});
1626+
1627+
it('calls offlineDb.deleteReaction and queues task if offlineDb exists', async () => {
1628+
await channel.deleteReaction(messageId, reactionType);
1629+
1630+
expect(deleteReactionSpy).toHaveBeenCalledTimes(1);
1631+
expect(queueTaskSpy).toHaveBeenCalledTimes(1);
1632+
1633+
const expectedReaction = {
1634+
created_at: '',
1635+
updated_at: '',
1636+
message_id: messageId,
1637+
type: reactionType,
1638+
user_id: user_id,
1639+
};
1640+
1641+
expect(deleteReactionSpy).toHaveBeenCalledWith({
1642+
message: { id: messageId },
1643+
reaction: expectedReaction,
1644+
});
1645+
1646+
expect(queueTaskSpy).toHaveBeenCalledWith({
1647+
task: {
1648+
channelId: 'test',
1649+
channelType: 'messaging',
1650+
messageId,
1651+
payload: [messageId, reactionType],
1652+
type: 'delete-reaction',
1653+
},
1654+
});
1655+
1656+
expect(channel._deleteReaction).not.toHaveBeenCalled();
1657+
});
1658+
1659+
it('falls back to _deleteReaction if offlineDb throws', async () => {
1660+
deleteReactionSpy.mockRejectedValue(new Error('Offline failure'));
1661+
1662+
await channel.deleteReaction(messageId, reactionType);
1663+
1664+
expect(loggerSpy).toHaveBeenCalledTimes(1);
1665+
expect(channel._deleteReaction).toHaveBeenCalledTimes(1);
1666+
expect(channel._deleteReaction).toHaveBeenCalledWith(
1667+
messageId,
1668+
reactionType,
1669+
undefined,
1670+
);
1671+
});
1672+
1673+
it('falls back to _deleteReaction if offlineDb is undefined', async () => {
1674+
client.offlineDb = undefined;
1675+
1676+
await channel.deleteReaction(messageId, reactionType);
1677+
1678+
expect(channel._deleteReaction).toHaveBeenCalledTimes(1);
1679+
expect(channel._deleteReaction).toHaveBeenCalledWith(
1680+
messageId,
1681+
reactionType,
1682+
undefined,
1683+
);
1684+
});
1685+
});
1686+
1687+
describe('_deleteReaction', () => {
1688+
it('throws if messageID or reactionType is missing', async () => {
1689+
await expect(channel._deleteReaction(undefined, reactionType)).rejects.toThrow(
1690+
'Deleting a reaction requires specifying both the message and reaction type',
1691+
);
1692+
await expect(channel._deleteReaction(messageId, undefined)).rejects.toThrow(
1693+
'Deleting a reaction requires specifying both the message and reaction type',
1694+
);
1695+
});
1696+
1697+
it('calls delete with user_id when provided', async () => {
1698+
await channel._deleteReaction(messageId, reactionType, user_id);
1699+
1700+
expect(deleteSpy).toHaveBeenCalledTimes(1);
1701+
expect(deleteSpy).toHaveBeenCalledWith(
1702+
`${client.baseURL}/messages/${encodeURIComponent(messageId)}/reaction/${encodeURIComponent(reactionType)}`,
1703+
{ user_id },
1704+
);
1705+
});
1706+
1707+
it('calls delete with empty body if user_id is not provided', async () => {
1708+
await channel._deleteReaction(messageId, reactionType);
1709+
1710+
expect(deleteSpy).toHaveBeenCalledTimes(1);
1711+
expect(deleteSpy).toHaveBeenCalledWith(
1712+
`${client.baseURL}/messages/${encodeURIComponent(messageId)}/reaction/${encodeURIComponent(reactionType)}`,
1713+
{},
1714+
);
1715+
});
1716+
1717+
it('returns the response from delete', async () => {
1718+
deleteSpy.mockResolvedValue({ success: true });
1719+
1720+
const result = await channel._deleteReaction(messageId, reactionType);
1721+
1722+
expect(result).toEqual({ success: true });
1723+
});
1724+
});
1725+
});

0 commit comments

Comments
 (0)