signal-desktop/ts/test-electron/state/selectors/conversations-extra_test.ts

284 lines
8.6 KiB
TypeScript
Raw Normal View History

// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import type { StateType } from '../../../state/reducer';
import type { ConversationType } from '../../../state/ducks/conversations';
import type { StoryDistributionListDataType } from '../../../state/ducks/storyDistributionLists';
import type { StoryDistributionIdString } from '../../../types/StoryDistributionId';
import type { ServiceIdString } from '../../../types/ServiceId';
import type { ContactsByStory } from '../../../components/SafetyNumberChangeDialog';
import * as Bytes from '../../../Bytes';
import { reducer as rootReducer } from '../../../state/reducer';
import { getDefaultConversation } from '../../../test-both/helpers/getDefaultConversation';
import { getEmptyState } from '../../../state/ducks/conversations';
import { getByDistributionListConversationsStoppingSend } from '../../../state/selectors/conversations-extra';
import { generateAci } from '../../../types/ServiceId';
import { generateStoryDistributionId } from '../../../types/StoryDistributionId';
import { noopAction } from '../../../state/ducks/noop';
import { ID_LENGTH } from '../../../groups';
import { ConversationVerificationState } from '../../../state/ducks/conversationsEnums';
describe('both/state/selectors/conversations-extra', () => {
const SERVICE_ID_1 = generateAci();
const SERVICE_ID_2 = generateAci();
const LIST_1 = generateStoryDistributionId();
const LIST_2 = generateStoryDistributionId();
const GROUP_ID = Bytes.toBase64(new Uint8Array(ID_LENGTH));
const getEmptyRootState = (): StateType => {
return rootReducer(undefined, noopAction());
};
function makeConversation(
id: string,
serviceId?: ServiceIdString
): ConversationType {
const title = `${id} title`;
return getDefaultConversation({
id,
uuid: serviceId,
searchableTitle: title,
title,
titleNoDefault: title,
});
}
function makeDistributionList(
name: string,
id: StoryDistributionIdString
): StoryDistributionListDataType {
return {
id,
name: `distribution ${name}`,
allowsReplies: true,
isBlockList: false,
memberServiceIds: [],
};
}
describe('#getByDistributionListConversationsStoppingSend', () => {
const direct1 = makeConversation('direct1', SERVICE_ID_1);
const direct2 = makeConversation('direct2', SERVICE_ID_2);
const group1 = {
...makeConversation('group1'),
groupVersion: 2 as const,
groupId: GROUP_ID,
};
const state: StateType = {
...getEmptyRootState(),
conversations: {
...getEmptyState(),
conversationLookup: {
direct1,
direct2,
group1,
},
conversationsByUuid: {
[SERVICE_ID_1]: direct1,
[SERVICE_ID_2]: direct2,
},
verificationDataByConversation: {},
},
storyDistributionLists: {
distributionLists: [
makeDistributionList('list1', LIST_1),
makeDistributionList('list2', LIST_2),
],
},
};
it('returns empty array for no untrusted recipients', () => {
const actual = getByDistributionListConversationsStoppingSend(state);
assert.isEmpty(actual);
});
it('returns empty story field for 1:1 conversations', () => {
const starting: StateType = {
...state,
conversations: {
...state.conversations,
verificationDataByConversation: {
direct1: {
type: ConversationVerificationState.PendingVerification,
serviceIdsNeedingVerification: [SERVICE_ID_1, SERVICE_ID_2],
},
},
},
};
const expected: ContactsByStory = [
{
story: undefined,
contacts: [direct1, direct2],
},
];
const actual = getByDistributionListConversationsStoppingSend(starting);
assert.sameDeepMembers(actual, expected);
});
it('returns groups with name set', () => {
const starting: StateType = {
...state,
conversations: {
...state.conversations,
verificationDataByConversation: {
group1: {
type: ConversationVerificationState.PendingVerification,
serviceIdsNeedingVerification: [SERVICE_ID_1, SERVICE_ID_2],
},
},
},
};
const expected: ContactsByStory = [
{
story: {
name: 'group1 title',
conversationId: 'group1',
},
contacts: [direct1, direct2],
},
];
const actual = getByDistributionListConversationsStoppingSend(starting);
assert.sameDeepMembers(actual, expected);
});
it('returns distribution lists with distributionId set', () => {
const starting: StateType = {
...state,
conversations: {
...state.conversations,
verificationDataByConversation: {
direct1: {
type: ConversationVerificationState.PendingVerification,
serviceIdsNeedingVerification: [SERVICE_ID_1],
byDistributionId: {
[LIST_1]: {
serviceIdsNeedingVerification: [SERVICE_ID_2],
},
},
},
},
},
};
const expected: ContactsByStory = [
{
story: undefined,
contacts: [direct1],
},
{
story: {
name: 'distribution list1',
conversationId: 'direct1',
distributionId: LIST_1,
},
contacts: [direct2],
},
];
const actual = getByDistributionListConversationsStoppingSend(starting);
assert.sameDeepMembers(actual, expected);
});
it('returns distribution lists even if parent is empty', () => {
const starting: StateType = {
...state,
conversations: {
...state.conversations,
verificationDataByConversation: {
direct1: {
type: ConversationVerificationState.PendingVerification,
serviceIdsNeedingVerification: [],
byDistributionId: {
[LIST_1]: {
serviceIdsNeedingVerification: [SERVICE_ID_1],
},
[LIST_2]: {
serviceIdsNeedingVerification: [SERVICE_ID_2],
},
},
},
},
},
};
const expected: ContactsByStory = [
{
story: {
name: 'distribution list1',
conversationId: 'direct1',
distributionId: LIST_1,
},
contacts: [direct1],
},
{
story: {
name: 'distribution list2',
conversationId: 'direct1',
distributionId: LIST_2,
},
contacts: [direct2],
},
];
const actual = getByDistributionListConversationsStoppingSend(starting);
assert.sameDeepMembers(actual, expected);
});
it('drops items that are not pending verification', () => {
const starting: StateType = {
...state,
conversations: {
...state.conversations,
verificationDataByConversation: {
direct1: {
type: ConversationVerificationState.VerificationCancelled,
canceledAt: Date.now(),
},
direct2: {
type: ConversationVerificationState.VerificationCancelled,
canceledAt: Date.now(),
},
},
},
};
const expected: ContactsByStory = [];
const actual = getByDistributionListConversationsStoppingSend(starting);
assert.sameDeepMembers(actual, expected);
});
it('puts UUIDs from unknown distribution lists into their parent', () => {
const starting: StateType = {
...state,
conversations: {
...state.conversations,
verificationDataByConversation: {
direct1: {
type: ConversationVerificationState.PendingVerification,
serviceIdsNeedingVerification: [SERVICE_ID_1],
byDistributionId: {
// Not a list id!
[SERVICE_ID_1]: {
serviceIdsNeedingVerification: [SERVICE_ID_2],
},
},
},
},
},
};
const expected: ContactsByStory = [
{
story: undefined,
contacts: [direct1, direct2],
},
];
const actual = getByDistributionListConversationsStoppingSend(starting);
assert.sameDeepMembers(actual, expected);
});
});
});