5 changed files with 398 additions and 330 deletions
@ -1,337 +1,372 @@ |
|||||
import { beforeEach, describe, expect, it, vi } from 'vitest'; |
import { describe, it, expect, beforeEach, vi } from 'vitest'; |
||||
import { useMessageStore, Message, MessageState, MessageType } from './messageStore.ts'; |
import { |
||||
import { Types } from '@meshtastic/core'; |
useMessageStore, |
||||
|
MessageType, |
||||
vi.mock('./storage/indexDB.ts', () => ({ |
MessageState, |
||||
zustandIndexDBStorage: { |
type Message, |
||||
getItem: vi.fn(), |
} from './messageStore.ts'; |
||||
setItem: vi.fn(), |
|
||||
removeItem: vi.fn(), |
let memoryStorage: Record<string, string> = {}; |
||||
}, |
|
||||
})); |
vi.mock('./storage/indexDB.ts', () => { |
||||
|
console.log("Mocking zustandIndexDBStorage..."); |
||||
beforeEach(() => { |
return { |
||||
useMessageStore.setState({ |
zustandIndexDBStorage: { |
||||
messages: { direct: {}, broadcast: {} }, |
getItem: vi.fn(async (name: string): Promise<string | null> => { |
||||
draft: new Map<Types.Destination, string>(), |
console.log(`Mock getItem: ${name}`, memoryStorage[name] ?? null); |
||||
nodeNum: 0, |
return memoryStorage[name] ?? null; |
||||
activeChat: 0, |
}), |
||||
chatType: MessageType.Broadcast, |
setItem: vi.fn(async (name: string, value: string): Promise<void> => { |
||||
}); |
console.log(`Mock setItem: ${name}`, value); |
||||
|
memoryStorage[name] = value; |
||||
|
}), |
||||
|
removeItem: vi.fn(async (name: string): Promise<void> => { |
||||
|
console.log(`Mock removeItem: ${name}`); |
||||
|
delete memoryStorage[name]; |
||||
|
}), |
||||
|
}, |
||||
|
}; |
||||
}); |
}); |
||||
|
|
||||
|
const myNodeNum = 111; |
||||
|
const otherNodeNum1 = 222; |
||||
|
const otherNodeNum2 = 333; |
||||
|
const broadcastChannel = 0; |
||||
|
|
||||
|
|
||||
|
|
||||
|
const directMessageToOther1: Message = { |
||||
|
type: MessageType.Direct, |
||||
|
from: myNodeNum, |
||||
|
to: otherNodeNum1, |
||||
|
channel: 0, |
||||
|
date: Date.now(), |
||||
|
messageId: 101, |
||||
|
state: MessageState.Waiting, |
||||
|
message: 'Hello other 1 from me', |
||||
|
}; |
||||
|
|
||||
|
const directMessageFromOther1: Message = { |
||||
|
type: MessageType.Direct, |
||||
|
from: otherNodeNum1, |
||||
|
to: myNodeNum, |
||||
|
channel: 0, |
||||
|
date: Date.now() + 1000, |
||||
|
messageId: 102, |
||||
|
state: MessageState.Waiting, |
||||
|
message: 'Hello me from other 1', |
||||
|
}; |
||||
|
|
||||
|
const directMessageToOther2: Message = { |
||||
|
type: MessageType.Direct, |
||||
|
from: myNodeNum, |
||||
|
to: otherNodeNum2, |
||||
|
channel: 0, |
||||
|
date: Date.now() + 2000, |
||||
|
messageId: 103, |
||||
|
state: MessageState.Waiting, |
||||
|
message: 'Hello other 2 from me', |
||||
|
}; |
||||
|
|
||||
|
const broadcastMessage1: Message = { |
||||
|
type: MessageType.Broadcast, |
||||
|
from: otherNodeNum1, |
||||
|
to: 0xffffffff, |
||||
|
channel: broadcastChannel, |
||||
|
date: Date.now() + 3000, |
||||
|
messageId: 201, |
||||
|
state: MessageState.Waiting, |
||||
|
message: 'Broadcast message 1', |
||||
|
}; |
||||
|
|
||||
|
const broadcastMessage2: Message = { |
||||
|
type: MessageType.Broadcast, |
||||
|
from: myNodeNum, |
||||
|
to: 0xffffffff, |
||||
|
channel: broadcastChannel, |
||||
|
date: Date.now() + 4000, |
||||
|
messageId: 202, |
||||
|
state: MessageState.Waiting, |
||||
|
message: 'Broadcast message 2', |
||||
|
}; |
||||
|
|
||||
describe('useMessageStore', () => { |
describe('useMessageStore', () => { |
||||
it('sets and gets nodeNum', () => { |
const initialState = useMessageStore.getState(); |
||||
useMessageStore.getState().setNodeNum(42); |
|
||||
expect(useMessageStore.getState().getNodeNum()).toBe(42); |
beforeEach(() => { |
||||
|
useMessageStore.setState(initialState, true); |
||||
}); |
}); |
||||
|
|
||||
it('sets activeChat', () => { |
it('should have correct initial state', () => { |
||||
useMessageStore.getState().setActiveChat(123); |
const state = useMessageStore.getState(); |
||||
expect(useMessageStore.getState().activeChat).toBe(123); |
expect(state.messages.direct).toEqual({}); |
||||
|
expect(state.messages.broadcast).toEqual({}); |
||||
|
expect(state.draft).toBeInstanceOf(Map); |
||||
|
expect(state.draft.size).toBe(0); |
||||
|
expect(state.nodeNum).toBe(0); |
||||
|
expect(state.activeChat).toBe(0); |
||||
|
expect(state.chatType).toBe(MessageType.Broadcast); |
||||
}); |
}); |
||||
|
|
||||
it('sets chatType', () => { |
it('should set nodeNum', () => { |
||||
|
useMessageStore.getState().setNodeNum(myNodeNum); |
||||
|
expect(useMessageStore.getState().nodeNum).toBe(myNodeNum); |
||||
|
}); |
||||
|
|
||||
|
it('should set activeChat and chatType', () => { |
||||
|
useMessageStore.getState().setActiveChat(otherNodeNum1); |
||||
useMessageStore.getState().setChatType(MessageType.Direct); |
useMessageStore.getState().setChatType(MessageType.Direct); |
||||
|
expect(useMessageStore.getState().activeChat).toBe(otherNodeNum1); |
||||
expect(useMessageStore.getState().chatType).toBe(MessageType.Direct); |
expect(useMessageStore.getState().chatType).toBe(MessageType.Direct); |
||||
}); |
}); |
||||
|
|
||||
describe('saveMessage', () => { |
describe('saveMessage', () => { |
||||
it('saves a direct message', () => { |
it('should save a direct message with correct structure', () => { |
||||
const message: Message = { |
useMessageStore.getState().saveMessage(directMessageToOther1); |
||||
type: MessageType.Direct, |
const state = useMessageStore.getState(); |
||||
channel: 0, |
expect(state.messages.direct[myNodeNum]).toBeDefined(); |
||||
to: 101, |
expect(state.messages.direct[myNodeNum][otherNodeNum1]).toBeDefined(); |
||||
from: 202, |
expect( |
||||
date: Date.now(), |
state.messages.direct[myNodeNum][otherNodeNum1][directMessageToOther1.messageId], |
||||
messageId: 1, |
).toEqual(directMessageToOther1); |
||||
state: MessageState.Waiting, |
|
||||
message: 'Hello Direct', |
|
||||
}; |
|
||||
useMessageStore.getState().saveMessage(message); |
|
||||
expect(useMessageStore.getState().messages.direct[101]?.[1]).toEqual(message); |
|
||||
}); |
}); |
||||
|
|
||||
it('saves a broadcast message', () => { |
it('should save a broadcast message with correct structure', () => { |
||||
const message: Message = { |
useMessageStore.getState().saveMessage(broadcastMessage1); |
||||
type: MessageType.Broadcast, |
const state = useMessageStore.getState(); |
||||
channel: 5, |
expect(state.messages.broadcast[broadcastChannel]).toBeDefined(); |
||||
to: 0, |
expect( |
||||
from: 303, |
state.messages.broadcast[broadcastChannel][broadcastMessage1.messageId], |
||||
date: Date.now(), |
).toEqual(broadcastMessage1); |
||||
messageId: 100, |
|
||||
state: MessageState.Waiting, |
|
||||
message: 'Broadcast Message', |
|
||||
}; |
|
||||
useMessageStore.getState().saveMessage(message); |
|
||||
expect(useMessageStore.getState().messages.broadcast[5]?.[100]).toEqual(message); |
|
||||
}); |
}); |
||||
|
|
||||
it('ensures date is stored as milliseconds', () => { |
it('should save multiple messages correctly', () => { |
||||
const now = Date.now(); |
useMessageStore.getState().saveMessage(directMessageToOther1); |
||||
const message: Message = { |
useMessageStore.getState().saveMessage(directMessageFromOther1); |
||||
type: MessageType.Direct, |
useMessageStore.getState().saveMessage(broadcastMessage1); |
||||
channel: 0, |
|
||||
to: 101, |
const state = useMessageStore.getState(); |
||||
from: 202, |
|
||||
date: now, |
// Direct msg 1 (me -> other1)
|
||||
messageId: 1, |
expect(state.messages.direct[myNodeNum]?.[otherNodeNum1]?.[directMessageToOther1.messageId]).toEqual(directMessageToOther1); |
||||
state: MessageState.Waiting, |
// Direct msg 2 (other1 -> me)
|
||||
message: 'Hello Direct', |
expect(state.messages.direct[otherNodeNum1]?.[myNodeNum]?.[directMessageFromOther1.messageId]).toEqual(directMessageFromOther1); |
||||
}; |
// Broadcast msg 1
|
||||
useMessageStore.getState().saveMessage(message); |
expect(state.messages.broadcast[broadcastChannel]?.[broadcastMessage1.messageId]).toEqual(broadcastMessage1); |
||||
expect(useMessageStore.getState().messages.direct[101]?.[1]?.date).toBe(new Date(now).getTime()); |
|
||||
}); |
}); |
||||
}); |
}); |
||||
|
|
||||
describe('setMessageState', () => { |
describe('getMessages', () => { |
||||
it('updates the state of an existing direct message', () => { |
beforeEach(() => { |
||||
const message: Message = { |
useMessageStore.getState().setNodeNum(myNodeNum); |
||||
type: MessageType.Direct, |
useMessageStore.getState().saveMessage(directMessageToOther1); |
||||
channel: 0, |
useMessageStore.getState().saveMessage(directMessageFromOther1); |
||||
to: 101, |
useMessageStore.getState().saveMessage(directMessageToOther2); |
||||
from: 202, |
useMessageStore.getState().saveMessage(broadcastMessage1); |
||||
date: Date.now(), |
useMessageStore.getState().saveMessage(broadcastMessage2); |
||||
messageId: 1, |
}); |
||||
state: MessageState.Waiting, |
|
||||
message: 'Change me', |
|
||||
}; |
|
||||
useMessageStore.getState().saveMessage(message); |
|
||||
|
|
||||
useMessageStore.getState().setMessageState({ |
it('should return broadcast messages for a channel, sorted by date', () => { |
||||
type: MessageType.Direct, |
const messages = useMessageStore.getState().getMessages(MessageType.Broadcast, { |
||||
key: 101, |
myNodeNum: myNodeNum, // Not strictly needed for broadcast, but good practice
|
||||
messageId: 1, |
channel: broadcastChannel |
||||
newState: MessageState.Ack, |
|
||||
}); |
}); |
||||
|
expect(messages).toHaveLength(2); |
||||
|
expect(messages[0]).toEqual(broadcastMessage1); |
||||
|
expect(messages[1]).toEqual(broadcastMessage2); |
||||
|
}); |
||||
|
|
||||
expect(useMessageStore.getState().messages.direct[101]?.[1]?.state).toBe(MessageState.Ack); |
it('should return empty array for broadcast if channel has no messages', () => { |
||||
|
const messages = useMessageStore.getState().getMessages(MessageType.Broadcast, { |
||||
|
myNodeNum: myNodeNum, |
||||
|
channel: 99 |
||||
|
}); |
||||
|
expect(messages).toEqual([]); |
||||
}); |
}); |
||||
|
|
||||
it('updates the state of an existing broadcast message', () => { |
it('should return combined direct messages for a specific chat (pair), sorted by date', () => { |
||||
const message: Message = { |
const messages = useMessageStore.getState().getMessages(MessageType.Direct, { |
||||
type: MessageType.Broadcast, |
myNodeNum: myNodeNum, |
||||
channel: 5, |
otherNodeNum: otherNodeNum1 |
||||
to: 0, |
}); |
||||
from: 303, |
expect(messages).toHaveLength(2); |
||||
date: Date.now(), |
expect(messages[0]).toEqual(directMessageToOther1); |
||||
messageId: 100, |
expect(messages[1]).toEqual(directMessageFromOther1); |
||||
state: MessageState.Waiting, |
}); |
||||
message: 'Broadcast Message', |
|
||||
}; |
|
||||
useMessageStore.getState().saveMessage(message); |
|
||||
|
|
||||
useMessageStore.getState().setMessageState({ |
it('should return only relevant direct messages for a different chat pair', () => { |
||||
type: MessageType.Broadcast, |
const messages = useMessageStore.getState().getMessages(MessageType.Direct, { |
||||
key: 5, |
myNodeNum: myNodeNum, |
||||
messageId: 100, |
otherNodeNum: otherNodeNum2 |
||||
newState: MessageState.Failed, |
}); |
||||
|
expect(messages).toHaveLength(1); |
||||
|
expect(messages[0]).toEqual(directMessageToOther2); |
||||
|
}); |
||||
|
|
||||
|
it('should return empty array for direct chat if no messages exist', () => { |
||||
|
const messages = useMessageStore.getState().getMessages(MessageType.Direct, { |
||||
|
myNodeNum: myNodeNum, |
||||
|
otherNodeNum: 999 |
||||
}); |
}); |
||||
|
expect(messages).toEqual([]); |
||||
|
}); |
||||
|
|
||||
expect(useMessageStore.getState().messages.broadcast[5]?.[100]?.state).toBe(MessageState.Failed); |
it('should return empty array if myNodeNum is not provided for direct messages', () => { |
||||
|
const messages = useMessageStore.getState().getMessages(MessageType.Direct, { |
||||
|
otherNodeNum: otherNodeNum1 |
||||
|
}); |
||||
|
expect(messages).toEqual([]); |
||||
}); |
}); |
||||
|
}); |
||||
|
|
||||
it('does not update if the message is not found and logs a warning', () => { |
describe('setMessageState', () => { |
||||
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { }); |
beforeEach(() => { |
||||
|
useMessageStore.getState().setNodeNum(myNodeNum); |
||||
|
useMessageStore.getState().saveMessage(directMessageToOther1); |
||||
|
useMessageStore.getState().saveMessage(directMessageFromOther1); |
||||
|
useMessageStore.getState().saveMessage(broadcastMessage1); |
||||
|
}); |
||||
|
|
||||
|
it('should update state for a direct message sent BY ME', () => { |
||||
useMessageStore.getState().setMessageState({ |
useMessageStore.getState().setMessageState({ |
||||
type: MessageType.Direct, |
type: MessageType.Direct, |
||||
key: 999, |
key: otherNodeNum1, |
||||
messageId: 99, |
messageId: directMessageToOther1.messageId, |
||||
newState: MessageState.Ack, |
newState: MessageState.Ack, |
||||
}); |
}); |
||||
|
const message = useMessageStore.getState().messages.direct[myNodeNum]?.[otherNodeNum1]?.[directMessageToOther1.messageId]; |
||||
expect(consoleWarnSpy).toHaveBeenCalledWith( |
expect(message?.state).toBe(MessageState.Ack); |
||||
'Message not found - type: direct, key: 999, messageId: 99', |
|
||||
); |
|
||||
|
|
||||
consoleWarnSpy.mockRestore(); |
|
||||
}); |
}); |
||||
}); |
|
||||
|
|
||||
it('clears all messages', () => { |
it('should update state for a direct message received FROM OTHER', () => { |
||||
useMessageStore.getState().saveMessage({ |
useMessageStore.getState().setMessageState({ |
||||
type: MessageType.Broadcast, |
type: MessageType.Direct, |
||||
channel: 5, |
key: otherNodeNum1, |
||||
to: 0, |
messageId: directMessageFromOther1.messageId, |
||||
from: 303, |
newState: MessageState.Failed, |
||||
date: Date.now(), |
}); |
||||
messageId: 100, |
const message = useMessageStore.getState().messages.direct[otherNodeNum1]?.[myNodeNum]?.[directMessageFromOther1.messageId]; |
||||
state: MessageState.Waiting, |
expect(message?.state).toBe(MessageState.Failed); |
||||
message: 'Broadcast Message', |
|
||||
}); |
|
||||
useMessageStore.getState().saveMessage({ |
|
||||
type: MessageType.Direct, |
|
||||
channel: 0, |
|
||||
to: 101, |
|
||||
from: 202, |
|
||||
date: Date.now(), |
|
||||
messageId: 1, |
|
||||
state: MessageState.Waiting, |
|
||||
message: 'Hello Direct', |
|
||||
}); |
}); |
||||
useMessageStore.getState().clearAllMessages(); |
|
||||
expect(useMessageStore.getState().messages.direct).toEqual({}); |
|
||||
expect(useMessageStore.getState().messages.broadcast).toEqual({}); |
|
||||
}); |
|
||||
|
|
||||
describe('getMessages', () => { |
it('should update state for a broadcast message', () => { |
||||
it('retrieves sorted broadcast messages for a channel', () => { |
useMessageStore.getState().setMessageState({ |
||||
const now = Date.now(); |
|
||||
const earlier = now - 10000; |
|
||||
const later = now; |
|
||||
|
|
||||
useMessageStore.getState().saveMessage({ |
|
||||
type: MessageType.Broadcast, |
|
||||
channel: 4, |
|
||||
to: 0, |
|
||||
from: 404, |
|
||||
date: later, |
|
||||
messageId: 2, |
|
||||
state: MessageState.Waiting, |
|
||||
message: 'Second', |
|
||||
}); |
|
||||
useMessageStore.getState().saveMessage({ |
|
||||
type: MessageType.Broadcast, |
type: MessageType.Broadcast, |
||||
channel: 4, |
key: broadcastChannel, |
||||
to: 0, |
messageId: broadcastMessage1.messageId, |
||||
from: 404, |
newState: MessageState.Ack, |
||||
date: earlier, |
|
||||
messageId: 1, |
|
||||
state: MessageState.Waiting, |
|
||||
message: 'First', |
|
||||
}); |
}); |
||||
|
const message = useMessageStore.getState().messages.broadcast[broadcastChannel]?.[broadcastMessage1.messageId]; |
||||
const messages = useMessageStore.getState().getMessages(MessageType.Broadcast, { channel: 4 }); |
expect(message?.state).toBe(MessageState.Ack); |
||||
expect(messages.map((m) => m.message)).toEqual(['First', 'Second']); |
|
||||
expect(messages[0]?.date).toBe(earlier); |
|
||||
expect(messages[1]?.date).toBe(later); |
|
||||
}); |
}); |
||||
|
|
||||
it('returns an empty array for broadcast messages if channel does not exist', () => { |
it('should warn if message is not found', () => { |
||||
const messages = useMessageStore.getState().getMessages(MessageType.Broadcast, { channel: 99 }); |
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { }); |
||||
expect(messages).toEqual([]); |
useMessageStore.getState().setMessageState({ |
||||
|
type: MessageType.Direct, |
||||
|
key: otherNodeNum1, |
||||
|
messageId: 999, |
||||
|
newState: MessageState.Ack, |
||||
|
}); |
||||
|
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Message not found for state update')); |
||||
|
warnSpy.mockRestore(); |
||||
}); |
}); |
||||
|
}); |
||||
|
|
||||
it('merges and sorts direct messages by date', () => { |
|
||||
const myNodeNum = 1; |
|
||||
const otherNodeNum = 2; |
|
||||
const now = Date.now(); |
|
||||
const earlier = now - 10000; |
|
||||
const later = now + 10000; |
|
||||
|
|
||||
const incomingMessage: Message = { |
describe('clearMessageByMessageId', () => { |
||||
type: MessageType.Direct, |
beforeEach(() => { |
||||
channel: 0, |
useMessageStore.getState().setNodeNum(myNodeNum); |
||||
to: myNodeNum, |
useMessageStore.getState().saveMessage(directMessageToOther1); |
||||
from: otherNodeNum, |
useMessageStore.getState().saveMessage(directMessageFromOther1); |
||||
date: earlier, |
useMessageStore.getState().saveMessage(broadcastMessage1); |
||||
messageId: 1, |
useMessageStore.getState().saveMessage({ ...directMessageToOther1, messageId: 1011, date: Date.now() + 50 }); |
||||
state: MessageState.Ack, |
}); |
||||
message: 'Incoming from 2', |
|
||||
}; |
it('should delete a specific direct message (sent by me)', () => { |
||||
useMessageStore.getState().saveMessage(incomingMessage); |
const messageIdToDelete = directMessageToOther1.messageId; |
||||
|
useMessageStore.getState().clearMessageByMessageId({ |
||||
const outgoingMessage: Message = { |
|
||||
type: MessageType.Direct, |
type: MessageType.Direct, |
||||
channel: 0, |
sender: myNodeNum, |
||||
to: otherNodeNum, |
recipient: otherNodeNum1, |
||||
from: myNodeNum, |
messageId: messageIdToDelete |
||||
date: later, |
|
||||
messageId: 2, |
|
||||
state: MessageState.Waiting, |
|
||||
message: 'Outgoing from 1', |
|
||||
}; |
|
||||
useMessageStore.getState().saveMessage(outgoingMessage); |
|
||||
|
|
||||
const merged = useMessageStore.getState().getMessages(MessageType.Direct, { |
|
||||
myNodeNum: myNodeNum, |
|
||||
otherNodeNum: otherNodeNum, |
|
||||
}); |
}); |
||||
|
const state = useMessageStore.getState(); |
||||
|
expect(state.messages.direct[myNodeNum]?.[otherNodeNum1]?.[messageIdToDelete]).toBeUndefined(); |
||||
|
expect(state.messages.direct[myNodeNum]?.[otherNodeNum1]?.[1011]).toBeDefined(); |
||||
|
expect(state.messages.direct[otherNodeNum1]?.[myNodeNum]?.[directMessageFromOther1.messageId]).toBeDefined(); |
||||
|
}); |
||||
|
|
||||
expect(merged.length).toBe(2); |
it('should delete a specific direct message (sent by other)', () => { |
||||
expect(merged.map((m) => m.message)).toEqual(['Incoming from 2', 'Outgoing from 1']); |
const messageIdToDelete = directMessageFromOther1.messageId; |
||||
expect(merged[0]?.date).toBe(earlier); |
useMessageStore.getState().clearMessageByMessageId({ |
||||
expect(merged[1]?.date).toBe(later); |
type: MessageType.Direct, |
||||
|
sender: otherNodeNum1, |
||||
|
recipient: myNodeNum, |
||||
|
messageId: messageIdToDelete |
||||
|
}); |
||||
|
const state = useMessageStore.getState(); |
||||
|
expect(state.messages.direct[otherNodeNum1]?.[myNodeNum]?.[messageIdToDelete]).toBeUndefined(); |
||||
|
expect(state.messages.direct[myNodeNum]?.[otherNodeNum1]?.[directMessageToOther1.messageId]).toBeDefined(); |
||||
|
expect(state.messages.direct[myNodeNum]?.[otherNodeNum1]?.[1011]).toBeDefined(); |
||||
}); |
}); |
||||
|
|
||||
it('returns an empty array for direct messages if no messages exist between nodes', () => { |
it('should delete a specific broadcast message', () => { |
||||
const myNodeNum = 1; |
const messageIdToDelete = broadcastMessage1.messageId; |
||||
const otherNodeNum = 2; |
useMessageStore.getState().clearMessageByMessageId({ |
||||
const messages = useMessageStore.getState().getMessages(MessageType.Direct, { |
type: MessageType.Broadcast, |
||||
myNodeNum: myNodeNum, |
channel: broadcastChannel, |
||||
otherNodeNum: otherNodeNum, |
messageId: messageIdToDelete |
||||
}); |
}); |
||||
expect(messages).toEqual([]); |
const state = useMessageStore.getState(); |
||||
|
expect(state.messages.broadcast[broadcastChannel]?.[messageIdToDelete]).toBeUndefined(); |
||||
|
}); |
||||
|
|
||||
|
it('should clean up empty recipient/sender/channel objects', () => { |
||||
|
useMessageStore.getState().clearMessageByMessageId({ type: MessageType.Direct, sender: otherNodeNum1, recipient: myNodeNum, messageId: directMessageFromOther1.messageId }); |
||||
|
expect(useMessageStore.getState().messages.direct[otherNodeNum1]?.[myNodeNum]).toBeUndefined(); // Recipient level removed
|
||||
|
expect(useMessageStore.getState().messages.direct[otherNodeNum1]).toBeUndefined(); // Sender level removed
|
||||
|
|
||||
|
useMessageStore.getState().clearMessageByMessageId({ type: MessageType.Broadcast, channel: broadcastChannel, messageId: broadcastMessage1.messageId }); |
||||
|
expect(useMessageStore.getState().messages.broadcast[broadcastChannel]).toBeUndefined(); // Channel level removed
|
||||
}); |
}); |
||||
}); |
}); |
||||
|
|
||||
describe('draft functionality', () => { |
describe('Drafts', () => { |
||||
it('sets and gets a draft message', () => { |
const draftKey = otherNodeNum1; |
||||
const key: Types.Destination = 123; |
const draftMessage = 'This is a draft'; |
||||
useMessageStore.getState().setDraft(key, 'Draft text'); |
|
||||
expect(useMessageStore.getState().getDraft(key)).toBe('Draft text'); |
it('should set and get a draft', () => { |
||||
|
useMessageStore.getState().setDraft(draftKey, draftMessage); |
||||
|
expect(useMessageStore.getState().draft.get(draftKey)).toBe(draftMessage); |
||||
|
expect(useMessageStore.getState().getDraft(draftKey)).toBe(draftMessage); |
||||
}); |
}); |
||||
|
|
||||
it('gets an empty string if no draft exists for a key', () => { |
it('should return empty string for non-existent draft', () => { |
||||
const key: Types.Destination = 456; |
expect(useMessageStore.getState().getDraft(999)).toBe(''); |
||||
expect(useMessageStore.getState().getDraft(key)).toBe(''); |
|
||||
}); |
}); |
||||
|
|
||||
it('clears a draft message', () => { |
it('should clear a draft', () => { |
||||
const key: Types.Destination = 123; |
useMessageStore.getState().setDraft(draftKey, draftMessage); |
||||
useMessageStore.getState().setDraft(key, 'Draft to clear'); |
expect(useMessageStore.getState().draft.has(draftKey)).toBe(true); |
||||
useMessageStore.getState().clearDraft(key); |
useMessageStore.getState().clearDraft(draftKey); |
||||
expect(useMessageStore.getState().getDraft(key)).toBe(''); |
expect(useMessageStore.getState().draft.has(draftKey)).toBe(false); |
||||
|
expect(useMessageStore.getState().getDraft(draftKey)).toBe(''); |
||||
}); |
}); |
||||
}); |
}); |
||||
|
|
||||
describe('clearMessageByMessageId', () => { |
describe('clearAllMessages', () => { |
||||
it('clears a direct message by messageId', () => { |
it('should clear all direct and broadcast messages', () => { |
||||
const message: Message = { |
useMessageStore.getState().saveMessage(directMessageToOther1); |
||||
type: MessageType.Direct, |
useMessageStore.getState().saveMessage(broadcastMessage1); |
||||
channel: 0, |
expect(Object.keys(useMessageStore.getState().messages.direct).length).toBeGreaterThan(0); |
||||
to: 111, |
expect(Object.keys(useMessageStore.getState().messages.broadcast).length).toBeGreaterThan(0); |
||||
from: 222, |
|
||||
date: Date.now(), |
|
||||
messageId: 42, |
|
||||
state: MessageState.Waiting, |
|
||||
message: 'To be deleted', |
|
||||
}; |
|
||||
useMessageStore.getState().saveMessage(message); |
|
||||
expect(useMessageStore.getState().messages.direct[111]?.[42]).toBeDefined(); |
|
||||
|
|
||||
useMessageStore.getState().clearMessageByMessageId(MessageType.Direct, 42); |
|
||||
|
|
||||
expect(useMessageStore.getState().messages.direct[111]?.[42]).toBeUndefined(); |
|
||||
expect(useMessageStore.getState().messages.direct[111]).toBeUndefined(); |
|
||||
}); |
|
||||
|
|
||||
it('clears a broadcast message by messageId', () => { |
useMessageStore.getState().clearAllMessages(); |
||||
const message: Message = { |
|
||||
type: MessageType.Broadcast, |
|
||||
channel: 2, |
|
||||
to: 0, |
|
||||
from: 333, |
|
||||
date: Date.now(), |
|
||||
messageId: 77, |
|
||||
state: MessageState.Waiting, |
|
||||
message: 'Broadcast to delete', |
|
||||
}; |
|
||||
useMessageStore.getState().saveMessage(message); |
|
||||
expect(useMessageStore.getState().messages.broadcast[2]?.[77]).toBeDefined(); |
|
||||
|
|
||||
useMessageStore.getState().clearMessageByMessageId(MessageType.Broadcast, 77); |
|
||||
|
|
||||
expect(useMessageStore.getState().messages.broadcast[2]?.[77]).toBeUndefined(); |
|
||||
expect(useMessageStore.getState().messages.broadcast[2]).toBeUndefined(); |
|
||||
}); |
|
||||
|
|
||||
it('does not throw error if trying to clear a non-existent message', () => { |
expect(useMessageStore.getState().messages.direct).toEqual({}); |
||||
expect(() => { |
expect(useMessageStore.getState().messages.broadcast).toEqual({}); |
||||
useMessageStore.getState().clearMessageByMessageId(MessageType.Direct, 999); |
|
||||
useMessageStore.getState().clearMessageByMessageId(MessageType.Broadcast, 999); |
|
||||
}).not.toThrow(); |
|
||||
}); |
}); |
||||
}); |
}); |
||||
}); |
|
||||
|
}); |
||||
|
|||||
Loading…
Reference in new issue