213 lines
5.6 KiB
TypeScript
213 lines
5.6 KiB
TypeScript
|
// Copyright 2021 Signal Messenger, LLC
|
||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||
|
|
||
|
import { assert } from 'chai';
|
||
|
|
||
|
import {
|
||
|
ConversationType,
|
||
|
getEmptyState as getEmptyConversationState,
|
||
|
MessageType,
|
||
|
} from '../../../state/ducks/conversations';
|
||
|
import { noopAction } from '../../../state/ducks/noop';
|
||
|
import { getEmptyState as getEmptySearchState } from '../../../state/ducks/search';
|
||
|
import { getEmptyState as getEmptyUserState } from '../../../state/ducks/user';
|
||
|
import { getMessageSearchResultSelector } from '../../../state/selectors/search';
|
||
|
|
||
|
import { StateType, reducer as rootReducer } from '../../../state/reducer';
|
||
|
|
||
|
describe('both/state/selectors/search', () => {
|
||
|
const getEmptyRootState = (): StateType => {
|
||
|
return rootReducer(undefined, noopAction());
|
||
|
};
|
||
|
|
||
|
function getDefaultMessage(id: string): MessageType {
|
||
|
return {
|
||
|
id,
|
||
|
conversationId: 'conversationId',
|
||
|
source: 'source',
|
||
|
sourceUuid: 'sourceUuid',
|
||
|
type: 'incoming' as const,
|
||
|
received_at: Date.now(),
|
||
|
attachments: [],
|
||
|
sticker: {},
|
||
|
unread: false,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function getDefaultConversation(id: string): ConversationType {
|
||
|
return {
|
||
|
id,
|
||
|
type: 'direct',
|
||
|
title: `${id} title`,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
describe('#getMessageSearchResultSelector', () => {
|
||
|
it('returns undefined if message not found in lookup', () => {
|
||
|
const state = getEmptyRootState();
|
||
|
const selector = getMessageSearchResultSelector(state);
|
||
|
|
||
|
const actual = selector('random-id');
|
||
|
|
||
|
assert.strictEqual(actual, undefined);
|
||
|
});
|
||
|
|
||
|
it('returns undefined if type is unexpected', () => {
|
||
|
const id = 'message-id';
|
||
|
const state = {
|
||
|
...getEmptyRootState(),
|
||
|
search: {
|
||
|
...getEmptySearchState(),
|
||
|
messageLookup: {
|
||
|
[id]: {
|
||
|
...getDefaultMessage(id),
|
||
|
type: 'keychange' as const,
|
||
|
snippet: 'snippet',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const selector = getMessageSearchResultSelector(state);
|
||
|
|
||
|
const actual = selector(id);
|
||
|
|
||
|
assert.strictEqual(actual, undefined);
|
||
|
});
|
||
|
|
||
|
it('returns incoming message', () => {
|
||
|
const searchId = 'search-id';
|
||
|
const fromId = 'from-id';
|
||
|
const toId = 'to-id';
|
||
|
|
||
|
const from = getDefaultConversation(fromId);
|
||
|
const to = getDefaultConversation(toId);
|
||
|
|
||
|
const state = {
|
||
|
...getEmptyRootState(),
|
||
|
conversations: {
|
||
|
...getEmptyConversationState(),
|
||
|
conversationLookup: {
|
||
|
[fromId]: from,
|
||
|
[toId]: to,
|
||
|
},
|
||
|
},
|
||
|
search: {
|
||
|
...getEmptySearchState(),
|
||
|
messageLookup: {
|
||
|
[searchId]: {
|
||
|
...getDefaultMessage(searchId),
|
||
|
type: 'incoming' as const,
|
||
|
sourceUuid: fromId,
|
||
|
conversationId: toId,
|
||
|
snippet: 'snippet',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const selector = getMessageSearchResultSelector(state);
|
||
|
|
||
|
const actual = selector(searchId);
|
||
|
const expected = {
|
||
|
from,
|
||
|
to,
|
||
|
|
||
|
id: searchId,
|
||
|
conversationId: toId,
|
||
|
sentAt: undefined,
|
||
|
snippet: 'snippet',
|
||
|
|
||
|
isSelected: false,
|
||
|
isSearchingInConversation: false,
|
||
|
};
|
||
|
|
||
|
assert.deepEqual(actual, expected);
|
||
|
});
|
||
|
it('returns outgoing message and caches appropriately', () => {
|
||
|
const searchId = 'search-id';
|
||
|
const fromId = 'from-id';
|
||
|
const toId = 'to-id';
|
||
|
|
||
|
const from = getDefaultConversation(fromId);
|
||
|
const to = getDefaultConversation(toId);
|
||
|
|
||
|
const state = {
|
||
|
...getEmptyRootState(),
|
||
|
user: {
|
||
|
...getEmptyUserState(),
|
||
|
ourConversationId: fromId,
|
||
|
},
|
||
|
conversations: {
|
||
|
...getEmptyConversationState(),
|
||
|
conversationLookup: {
|
||
|
[fromId]: from,
|
||
|
[toId]: to,
|
||
|
},
|
||
|
},
|
||
|
search: {
|
||
|
...getEmptySearchState(),
|
||
|
messageLookup: {
|
||
|
[searchId]: {
|
||
|
...getDefaultMessage(searchId),
|
||
|
type: 'outgoing' as const,
|
||
|
conversationId: toId,
|
||
|
snippet: 'snippet',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const selector = getMessageSearchResultSelector(state);
|
||
|
|
||
|
const actual = selector(searchId);
|
||
|
const expected = {
|
||
|
from,
|
||
|
to,
|
||
|
|
||
|
id: searchId,
|
||
|
conversationId: toId,
|
||
|
sentAt: undefined,
|
||
|
snippet: 'snippet',
|
||
|
|
||
|
isSelected: false,
|
||
|
isSearchingInConversation: false,
|
||
|
};
|
||
|
|
||
|
assert.deepEqual(actual, expected);
|
||
|
|
||
|
// Update the conversation lookup, but not the conversations in question
|
||
|
const secondState = {
|
||
|
...state,
|
||
|
conversations: {
|
||
|
...state.conversations,
|
||
|
conversationLookup: {
|
||
|
...state.conversations.conversationLookup,
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const secondSelector = getMessageSearchResultSelector(secondState);
|
||
|
const secondActual = secondSelector(searchId);
|
||
|
|
||
|
assert.strictEqual(secondActual, actual);
|
||
|
|
||
|
// Update a conversation involved in rendering this search result
|
||
|
const thirdState = {
|
||
|
...state,
|
||
|
conversations: {
|
||
|
...state.conversations,
|
||
|
conversationLookup: {
|
||
|
...state.conversations.conversationLookup,
|
||
|
[fromId]: {
|
||
|
...from,
|
||
|
name: 'new-name',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
|
||
|
const thirdSelector = getMessageSearchResultSelector(thirdState);
|
||
|
const thirdActual = thirdSelector(searchId);
|
||
|
|
||
|
assert.notStrictEqual(actual, thirdActual);
|
||
|
});
|
||
|
});
|
||
|
});
|