mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-05-08 08:58:38 +01:00
Reorganize test cases
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,156 @@
|
||||
// Copyright 2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { assert } from 'chai';
|
||||
import {
|
||||
getAreWeASubscriber,
|
||||
getEmojiSkinToneDefault,
|
||||
getPinnedConversationIds,
|
||||
getPreferredLeftPaneWidth,
|
||||
getPreferredReactionEmoji,
|
||||
} from '../../../state/selectors/items';
|
||||
import type { StateType } from '../../../state/reducer';
|
||||
import type { ItemsStateType } from '../../../state/ducks/items';
|
||||
import {
|
||||
EMOJI_SKIN_TONE_ORDER,
|
||||
EmojiSkinTone,
|
||||
} from '../../../components/fun/data/emojis';
|
||||
|
||||
describe('both/state/selectors/items', () => {
|
||||
// Note: we would like to use the full reducer here, to get a real empty state object
|
||||
// but we cannot load the full reducer inside of electron-mocha.
|
||||
function getRootState(items: ItemsStateType): StateType {
|
||||
return {
|
||||
items,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any;
|
||||
}
|
||||
|
||||
describe('#getAreWeASubscriber', () => {
|
||||
it('returns false if the value is not in storage', () => {
|
||||
assert.isFalse(getAreWeASubscriber(getRootState({})));
|
||||
});
|
||||
|
||||
it('returns the value in storage', () => {
|
||||
assert.isFalse(
|
||||
getAreWeASubscriber(getRootState({ areWeASubscriber: false }))
|
||||
);
|
||||
assert.isTrue(
|
||||
getAreWeASubscriber(getRootState({ areWeASubscriber: true }))
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getEmojiSkinTone', () => {
|
||||
it('returns null if passed anything invalid', () => {
|
||||
[
|
||||
// Invalid types
|
||||
undefined,
|
||||
null,
|
||||
'2',
|
||||
[2],
|
||||
// Numbers out of range
|
||||
-1,
|
||||
6,
|
||||
Infinity,
|
||||
// Invalid numbers
|
||||
0.1,
|
||||
1.2,
|
||||
NaN,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- for testing
|
||||
].forEach((emojiSkinToneDefault: any) => {
|
||||
const state = getRootState({ emojiSkinToneDefault });
|
||||
assert.strictEqual(getEmojiSkinToneDefault(state), null);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns all valid skin tones', () => {
|
||||
EMOJI_SKIN_TONE_ORDER.forEach(skinTone => {
|
||||
const state = getRootState({ emojiSkinToneDefault: skinTone });
|
||||
assert.strictEqual(getEmojiSkinToneDefault(state), skinTone);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getPreferredLeftPaneWidth', () => {
|
||||
it('returns a default if no value is present', () => {
|
||||
const state = getRootState({});
|
||||
assert.strictEqual(getPreferredLeftPaneWidth(state), 320);
|
||||
});
|
||||
|
||||
it('returns a default value if passed something invalid', () => {
|
||||
[undefined, null, '250', [250], 250.123].forEach(
|
||||
preferredLeftPaneWidth => {
|
||||
const state = getRootState({
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
preferredLeftPaneWidth: preferredLeftPaneWidth as any,
|
||||
});
|
||||
assert.strictEqual(getPreferredLeftPaneWidth(state), 320);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the value in storage if it is valid', () => {
|
||||
const state = getRootState({
|
||||
preferredLeftPaneWidth: 345,
|
||||
});
|
||||
assert.strictEqual(getPreferredLeftPaneWidth(state), 345);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getPinnedConversationIds', () => {
|
||||
it('returns pinnedConversationIds key from items', () => {
|
||||
const expected = ['one', 'two'];
|
||||
const state: StateType = getRootState({
|
||||
pinnedConversationIds: expected,
|
||||
});
|
||||
|
||||
const actual = getPinnedConversationIds(state);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('returns empty array if no saved data', () => {
|
||||
const expected: Array<string> = [];
|
||||
const state = getRootState({});
|
||||
|
||||
const actual = getPinnedConversationIds(state);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getPreferredReactionEmoji', () => {
|
||||
// See also: the tests for the `getPreferredReactionEmoji` helper.
|
||||
|
||||
const expectedDefault = ['❤️', '👍🏿', '👎🏿', '😂', '😮', '😢'];
|
||||
|
||||
it('returns the default set if no value is stored', () => {
|
||||
const state = getRootState({
|
||||
emojiSkinToneDefault: EmojiSkinTone.Type5,
|
||||
});
|
||||
const actual = getPreferredReactionEmoji(state);
|
||||
|
||||
assert.deepStrictEqual(actual, expectedDefault);
|
||||
});
|
||||
|
||||
it('returns the default set if the stored value is invalid', () => {
|
||||
const state = getRootState({
|
||||
emojiSkinToneDefault: EmojiSkinTone.Type5,
|
||||
preferredReactionEmoji: ['garbage!!'],
|
||||
});
|
||||
const actual = getPreferredReactionEmoji(state);
|
||||
|
||||
assert.deepStrictEqual(actual, expectedDefault);
|
||||
});
|
||||
|
||||
it('returns a custom set of emoji', () => {
|
||||
const preferredReactionEmoji = ['✨', '❇️', '🤙🏻', '🦈', '💖', '🅿️'];
|
||||
const state = getRootState({
|
||||
emojiSkinToneDefault: EmojiSkinTone.Type5,
|
||||
preferredReactionEmoji,
|
||||
});
|
||||
const actual = getPreferredReactionEmoji(state);
|
||||
|
||||
assert.deepStrictEqual(actual, preferredReactionEmoji);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { assert } from 'chai';
|
||||
import { reducer as rootReducer } from '../../../state/reducer';
|
||||
import { noopAction } from '../../../state/ducks/noop';
|
||||
import type { StateType } from '../../../state/reducer';
|
||||
import type { PreferredReactionsStateType } from '../../../state/ducks/preferredReactions';
|
||||
|
||||
import { getIsCustomizingPreferredReactions } from '../../../state/selectors/preferredReactions';
|
||||
|
||||
describe('both/state/selectors/preferredReactions', () => {
|
||||
const getEmptyRootState = (): StateType =>
|
||||
rootReducer(undefined, noopAction());
|
||||
|
||||
const getRootState = (preferredReactions: PreferredReactionsStateType) => ({
|
||||
...getEmptyRootState(),
|
||||
preferredReactions,
|
||||
});
|
||||
|
||||
describe('getIsCustomizingPreferredReactions', () => {
|
||||
it('returns false if the modal is closed', () => {
|
||||
assert.isFalse(getIsCustomizingPreferredReactions(getEmptyRootState()));
|
||||
});
|
||||
|
||||
it('returns true if the modal is open', () => {
|
||||
assert.isTrue(
|
||||
getIsCustomizingPreferredReactions(
|
||||
getRootState({
|
||||
customizePreferredReactionsModal: {
|
||||
draftPreferredReactions: ['✨', '❇️', '🎇', '🦈', '💖', '🅿️'],
|
||||
originalPreferredReactions: ['💙', '👍', '👎', '😂', '😮', '😢'],
|
||||
selectedDraftEmojiIndex: undefined,
|
||||
isSaving: false as const,
|
||||
hadSaveError: false,
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,527 @@
|
||||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { assert } from 'chai';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import type {
|
||||
ConversationType,
|
||||
MessageType,
|
||||
} from '../../../state/ducks/conversations';
|
||||
import { getEmptyState as getEmptyConversationState } from '../../../state/ducks/conversations';
|
||||
import { noopAction } from '../../../state/ducks/noop';
|
||||
import type { MessageSearchResultType } from '../../../state/ducks/search';
|
||||
import { getEmptyState as getEmptySearchState } from '../../../state/ducks/search';
|
||||
import { getEmptyState as getEmptyUserState } from '../../../state/ducks/user';
|
||||
import {
|
||||
getIsSearching,
|
||||
getIsSearchingGlobally,
|
||||
getIsSearchingInAConversation,
|
||||
getMessageSearchResultSelector,
|
||||
getSearchResults,
|
||||
} from '../../../state/selectors/search';
|
||||
import { makeLookup } from '../../../util/makeLookup';
|
||||
import { generateAci } from '../../../types/ServiceId';
|
||||
import {
|
||||
getDefaultConversation,
|
||||
getDefaultConversationWithServiceId,
|
||||
} from '../../../test-helpers/getDefaultConversation';
|
||||
import { ReadStatus } from '../../../messages/MessageReadStatus';
|
||||
|
||||
import type { StateType } from '../../../state/reducer';
|
||||
import { reducer as rootReducer } from '../../../state/reducer';
|
||||
|
||||
describe('both/state/selectors/search', () => {
|
||||
const NOW = 1_000_000;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let clock: any;
|
||||
|
||||
beforeEach(() => {
|
||||
clock = sinon.useFakeTimers({
|
||||
now: NOW,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clock.restore();
|
||||
});
|
||||
|
||||
const getEmptyRootState = (): StateType => {
|
||||
return rootReducer(undefined, noopAction());
|
||||
};
|
||||
|
||||
function getDefaultMessage(id: string): MessageType {
|
||||
return {
|
||||
attachments: [],
|
||||
conversationId: 'conversationId',
|
||||
id,
|
||||
received_at: NOW,
|
||||
sent_at: NOW,
|
||||
source: 'source',
|
||||
sourceServiceId: generateAci(),
|
||||
timestamp: NOW,
|
||||
type: 'incoming' as const,
|
||||
readStatus: ReadStatus.Read,
|
||||
};
|
||||
}
|
||||
|
||||
function getDefaultSearchMessage(id: string): MessageSearchResultType {
|
||||
return {
|
||||
...getDefaultMessage(id),
|
||||
body: 'foo bar',
|
||||
bodyRanges: [],
|
||||
snippet: 'foo bar',
|
||||
};
|
||||
}
|
||||
|
||||
describe('#getIsSearchingInAConversation', () => {
|
||||
it('returns false if not searching in a conversation', () => {
|
||||
const state = getEmptyRootState();
|
||||
|
||||
assert.isFalse(getIsSearchingInAConversation(state));
|
||||
});
|
||||
|
||||
it('returns true if searching in a conversation', () => {
|
||||
const state = {
|
||||
...getEmptyRootState(),
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
searchConversationId: 'abc123',
|
||||
searchConversationName: 'Test Conversation',
|
||||
},
|
||||
};
|
||||
|
||||
assert.isTrue(getIsSearchingInAConversation(state));
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getIsSearchingGlobally', () => {
|
||||
it('returns false if not searching', () => {
|
||||
const state = getEmptyRootState();
|
||||
|
||||
assert.isFalse(getIsSearchingGlobally(state));
|
||||
});
|
||||
|
||||
it('returns true if searching globally', () => {
|
||||
const state = {
|
||||
...getEmptyRootState(),
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
globalSearch: true,
|
||||
},
|
||||
};
|
||||
|
||||
assert.isTrue(getIsSearchingGlobally(state));
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getIsSearching', () => {
|
||||
it('returns false if not searching in any manner', () => {
|
||||
const state = getEmptyRootState();
|
||||
|
||||
assert.isFalse(getIsSearching(state));
|
||||
});
|
||||
|
||||
it('returns true if searching in a conversation', () => {
|
||||
const state = {
|
||||
...getEmptyRootState(),
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
searchConversationId: 'abc123',
|
||||
searchConversationName: 'Test Conversation',
|
||||
globalSearch: false,
|
||||
},
|
||||
};
|
||||
|
||||
assert.isTrue(getIsSearching(state));
|
||||
});
|
||||
|
||||
it('returns true if searching globally', () => {
|
||||
const state = {
|
||||
...getEmptyRootState(),
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
searchConversationId: undefined,
|
||||
globalSearch: true,
|
||||
},
|
||||
};
|
||||
|
||||
assert.isTrue(getIsSearchingGlobally(state));
|
||||
});
|
||||
});
|
||||
|
||||
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',
|
||||
body: 'snippet',
|
||||
bodyRanges: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const selector = getMessageSearchResultSelector(state);
|
||||
|
||||
const actual = selector(id);
|
||||
|
||||
assert.strictEqual(actual, undefined);
|
||||
});
|
||||
|
||||
it('returns incoming message', () => {
|
||||
const searchId = 'search-id';
|
||||
const toId = 'to-id';
|
||||
|
||||
const from = getDefaultConversationWithServiceId();
|
||||
const to = getDefaultConversation({ id: toId });
|
||||
|
||||
const state = {
|
||||
...getEmptyRootState(),
|
||||
conversations: {
|
||||
...getEmptyConversationState(),
|
||||
conversationLookup: {
|
||||
[from.id]: from,
|
||||
[toId]: to,
|
||||
},
|
||||
conversationsByServiceId: {
|
||||
[from.serviceId]: from,
|
||||
},
|
||||
},
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
messageLookup: {
|
||||
[searchId]: {
|
||||
...getDefaultMessage(searchId),
|
||||
type: 'incoming' as const,
|
||||
sourceServiceId: from.serviceId,
|
||||
conversationId: toId,
|
||||
snippet: 'snippet',
|
||||
body: 'snippet',
|
||||
bodyRanges: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const selector = getMessageSearchResultSelector(state);
|
||||
|
||||
const actual = selector(searchId);
|
||||
const expected = {
|
||||
from,
|
||||
to,
|
||||
|
||||
id: searchId,
|
||||
conversationId: toId,
|
||||
sentAt: NOW,
|
||||
snippet: 'snippet',
|
||||
body: 'snippet',
|
||||
bodyRanges: [],
|
||||
|
||||
isSelected: false,
|
||||
isSearchingInConversation: false,
|
||||
};
|
||||
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
|
||||
it('returns the correct "from" and "to" when sent to me', () => {
|
||||
const searchId = 'search-id';
|
||||
const myId = 'my-id';
|
||||
|
||||
const from = getDefaultConversationWithServiceId();
|
||||
const toId = from.serviceId;
|
||||
const meAsRecipient = getDefaultConversation({ id: myId });
|
||||
|
||||
const state = {
|
||||
...getEmptyRootState(),
|
||||
conversations: {
|
||||
...getEmptyConversationState(),
|
||||
conversationLookup: {
|
||||
[from.id]: from,
|
||||
[myId]: meAsRecipient,
|
||||
},
|
||||
conversationsByServiceId: {
|
||||
[from.serviceId]: from,
|
||||
},
|
||||
},
|
||||
ourConversationId: myId,
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
messageLookup: {
|
||||
[searchId]: {
|
||||
...getDefaultMessage(searchId),
|
||||
type: 'incoming' as const,
|
||||
sourceServiceId: from.serviceId,
|
||||
conversationId: toId,
|
||||
snippet: 'snippet',
|
||||
body: 'snippet',
|
||||
bodyRanges: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
user: {
|
||||
...getEmptyUserState(),
|
||||
ourConversationId: myId,
|
||||
},
|
||||
};
|
||||
const selector = getMessageSearchResultSelector(state);
|
||||
|
||||
const actual = selector(searchId);
|
||||
assert.deepEqual(actual?.from, from);
|
||||
assert.deepEqual(actual?.to, meAsRecipient);
|
||||
});
|
||||
|
||||
it('returns outgoing message and caches appropriately', () => {
|
||||
const searchId = 'search-id';
|
||||
const toId = 'to-id';
|
||||
|
||||
const from = getDefaultConversationWithServiceId();
|
||||
const to = getDefaultConversation({ id: toId });
|
||||
|
||||
const state = {
|
||||
...getEmptyRootState(),
|
||||
user: {
|
||||
...getEmptyUserState(),
|
||||
ourConversationId: from.id,
|
||||
},
|
||||
conversations: {
|
||||
...getEmptyConversationState(),
|
||||
conversationLookup: {
|
||||
[from.id]: from,
|
||||
[toId]: to,
|
||||
},
|
||||
conversationsByServiceId: {
|
||||
[from.serviceId]: from,
|
||||
},
|
||||
},
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
messageLookup: {
|
||||
[searchId]: {
|
||||
...getDefaultMessage(searchId),
|
||||
type: 'outgoing' as const,
|
||||
conversationId: toId,
|
||||
snippet: 'snippet',
|
||||
body: 'snippet',
|
||||
bodyRanges: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const selector = getMessageSearchResultSelector(state);
|
||||
|
||||
const actual = selector(searchId);
|
||||
const expected = {
|
||||
from,
|
||||
to,
|
||||
|
||||
id: searchId,
|
||||
conversationId: toId,
|
||||
sentAt: NOW,
|
||||
snippet: 'snippet',
|
||||
body: 'snippet',
|
||||
bodyRanges: [],
|
||||
|
||||
isSelected: false,
|
||||
isSearchingInConversation: false,
|
||||
};
|
||||
|
||||
assert.deepEqual(actual, expected);
|
||||
|
||||
// Update the conversation lookup, but not the conversations in question
|
||||
const secondState = {
|
||||
...state,
|
||||
conversations: {
|
||||
...state.conversations,
|
||||
},
|
||||
};
|
||||
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,
|
||||
conversationsByServiceId: {
|
||||
...state.conversations.conversationsByServiceId,
|
||||
[from.serviceId]: {
|
||||
...from,
|
||||
name: 'new-name',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const thirdSelector = getMessageSearchResultSelector(thirdState);
|
||||
const thirdActual = thirdSelector(searchId);
|
||||
|
||||
assert.notStrictEqual(actual, thirdActual);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getSearchResults', () => {
|
||||
it("returns loading search results when they're loading", () => {
|
||||
const state = {
|
||||
...getEmptyRootState(),
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
query: 'foo bar',
|
||||
discussionsLoading: true,
|
||||
messagesLoading: true,
|
||||
},
|
||||
};
|
||||
|
||||
assert.deepEqual(getSearchResults(state), {
|
||||
conversationResults: { isLoading: true },
|
||||
contactResults: { isLoading: true },
|
||||
messageResults: { isLoading: true },
|
||||
searchConversationName: undefined,
|
||||
searchTerm: 'foo bar',
|
||||
filterByUnread: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns loaded search results', () => {
|
||||
const conversations: Array<ConversationType> = [
|
||||
getDefaultConversation({ id: '1' }),
|
||||
getDefaultConversation({ id: '2' }),
|
||||
];
|
||||
const contacts: Array<ConversationType> = [
|
||||
getDefaultConversation({ id: '3' }),
|
||||
getDefaultConversation({ id: '4' }),
|
||||
getDefaultConversation({ id: '5' }),
|
||||
];
|
||||
const messages: Array<MessageSearchResultType> = [
|
||||
getDefaultSearchMessage('a'),
|
||||
getDefaultSearchMessage('b'),
|
||||
getDefaultSearchMessage('c'),
|
||||
];
|
||||
|
||||
const getId = ({ id }: Readonly<{ id: string }>) => id;
|
||||
|
||||
const state: StateType = {
|
||||
...getEmptyRootState(),
|
||||
conversations: {
|
||||
// This test state is invalid, but is good enough for this test.
|
||||
...getEmptyConversationState(),
|
||||
conversationLookup: makeLookup([...conversations, ...contacts], 'id'),
|
||||
},
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
query: 'foo bar',
|
||||
conversationIds: conversations.map(getId),
|
||||
contactIds: contacts.map(getId),
|
||||
messageIds: messages.map(getId),
|
||||
messageLookup: makeLookup(messages, 'id'),
|
||||
discussionsLoading: false,
|
||||
messagesLoading: false,
|
||||
},
|
||||
};
|
||||
|
||||
assert.deepEqual(getSearchResults(state), {
|
||||
conversationResults: {
|
||||
isLoading: false,
|
||||
results: conversations,
|
||||
},
|
||||
contactResults: {
|
||||
isLoading: false,
|
||||
results: contacts,
|
||||
},
|
||||
messageResults: {
|
||||
isLoading: false,
|
||||
results: messages,
|
||||
},
|
||||
searchConversationName: undefined,
|
||||
searchTerm: 'foo bar',
|
||||
filterByUnread: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('adds isSelected flag to conversations when filterByUnread is true', () => {
|
||||
const conversations: Array<ConversationType> = [
|
||||
getDefaultConversation({ id: '1' }),
|
||||
getDefaultConversation({ id: 'selected-id' }),
|
||||
];
|
||||
|
||||
const state: StateType = {
|
||||
...getEmptyRootState(),
|
||||
conversations: {
|
||||
...getEmptyConversationState(),
|
||||
conversationLookup: makeLookup(conversations, 'id'),
|
||||
selectedConversationId: 'selected-id',
|
||||
},
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
query: 'foo bar',
|
||||
conversationIds: conversations.map(({ id }) => id),
|
||||
discussionsLoading: false,
|
||||
filterByUnread: true,
|
||||
},
|
||||
};
|
||||
|
||||
const searchResults = getSearchResults(state);
|
||||
|
||||
assert.deepEqual(searchResults.conversationResults, {
|
||||
isLoading: false,
|
||||
results: [
|
||||
{
|
||||
...conversations[0],
|
||||
isSelected: false,
|
||||
},
|
||||
{
|
||||
...conversations[1],
|
||||
isSelected: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('does not add isSelected flag to conversations when filterByUnread is false', () => {
|
||||
const conversations: Array<ConversationType> = [
|
||||
getDefaultConversation({ id: '1' }),
|
||||
getDefaultConversation({ id: '2' }),
|
||||
];
|
||||
|
||||
const state: StateType = {
|
||||
...getEmptyRootState(),
|
||||
conversations: {
|
||||
...getEmptyConversationState(),
|
||||
conversationLookup: makeLookup(conversations, 'id'),
|
||||
selectedConversationId: '2',
|
||||
},
|
||||
search: {
|
||||
...getEmptySearchState(),
|
||||
query: 'foo bar',
|
||||
conversationIds: conversations.map(({ id }) => id),
|
||||
discussionsLoading: false,
|
||||
filterByUnread: false,
|
||||
},
|
||||
};
|
||||
|
||||
const searchResults = getSearchResults(state);
|
||||
|
||||
assert.deepEqual(searchResults.conversationResults, {
|
||||
isLoading: false,
|
||||
results: conversations,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2022 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { assert } from 'chai';
|
||||
|
||||
import type { StateType } from '../../../state/reducer';
|
||||
import type { UserStateType } from '../../../state/ducks/user';
|
||||
import { getEmptyState } from '../../../state/ducks/user';
|
||||
|
||||
import { getIsNightly, getIsBeta } from '../../../state/selectors/user';
|
||||
|
||||
describe('both/state/selectors/user', () => {
|
||||
function getRootState(
|
||||
overrides: Readonly<Partial<UserStateType>>
|
||||
): StateType {
|
||||
return {
|
||||
user: {
|
||||
...getEmptyState(),
|
||||
...overrides,
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any;
|
||||
}
|
||||
|
||||
describe('#getIsNightly', () => {
|
||||
it('returns false for beta', () => {
|
||||
const state = getRootState({ version: '1.23.4-beta.5' });
|
||||
assert.isFalse(getIsNightly(state));
|
||||
});
|
||||
|
||||
it('returns false for production', () => {
|
||||
const state = getRootState({ version: '1.23.4' });
|
||||
assert.isFalse(getIsNightly(state));
|
||||
});
|
||||
|
||||
it('returns true for alpha', () => {
|
||||
const state = getRootState({ version: '1.23.4-alpha.987' });
|
||||
assert.isTrue(getIsNightly(state));
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getIsBeta', () => {
|
||||
it('returns false for alpha', () => {
|
||||
const state = getRootState({ version: '1.23.4-alpha.987' });
|
||||
assert.isFalse(getIsBeta(state));
|
||||
});
|
||||
|
||||
it('returns false for production', () => {
|
||||
const state = getRootState({ version: '1.23.4' });
|
||||
assert.isFalse(getIsBeta(state));
|
||||
});
|
||||
|
||||
it('returns true for beta', () => {
|
||||
const state = getRootState({ version: '1.23.4-beta.5' });
|
||||
assert.isTrue(getIsBeta(state));
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user