mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-04-18 07:36:00 +01:00
CollapseSet: Size limit, some new message types added/excluded
Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
@@ -5,7 +5,10 @@ import { assert } from 'chai';
|
||||
import { v4 as generateUuid } from 'uuid';
|
||||
|
||||
import { getMidnight } from '../../types/NotificationProfile.std.ts';
|
||||
import { mapItemsIntoCollapseSets } from '../../util/CollapseSet.std.ts';
|
||||
import {
|
||||
mapItemsIntoCollapseSets,
|
||||
MAX_COLLAPSE_SET_SIZE,
|
||||
} from '../../util/CollapseSet.std.ts';
|
||||
import { generateAci } from '../../types/ServiceId.std.ts';
|
||||
import { ReadStatus } from '../../messages/MessageReadStatus.std.ts';
|
||||
import { SeenStatus } from '../../MessageSeenStatus.std.ts';
|
||||
@@ -24,6 +27,7 @@ import type {
|
||||
MessageType,
|
||||
} from '../../state/ducks/conversations.preload.ts';
|
||||
import type { CollapseSet } from '../../util/CollapseSet.std.ts';
|
||||
import type { MessageAttributesType } from '../../model-types.d.ts';
|
||||
|
||||
describe('util/CollapseSets', () => {
|
||||
describe('mapItemsIntoCollapseSets', () => {
|
||||
@@ -169,6 +173,346 @@ describe('util/CollapseSets', () => {
|
||||
);
|
||||
assert.isNull(resultUnseenIndex);
|
||||
});
|
||||
it('returns single set for all non-groupv2 items included in group sets', () => {
|
||||
const groupMessage = {
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'group-v2-change' as const,
|
||||
groupV2Change: {
|
||||
details: [{ type: 'create' as const }],
|
||||
},
|
||||
};
|
||||
// The best test is if these are all right next to group messages; otherwise
|
||||
// it's only testing whether they group against their neighbors...
|
||||
const itemsToMixIn = [
|
||||
// The first set is included
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'profile-change' as const,
|
||||
profileChange: {
|
||||
type: 'name' as const,
|
||||
oldName: 'Someone',
|
||||
newName: 'Sometwo',
|
||||
},
|
||||
changedId: generateAci(),
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'poll-terminate' as const,
|
||||
pollTerminateNotification: {
|
||||
question: 'What is the best?',
|
||||
pollTimestamp: yesterday,
|
||||
},
|
||||
changedId: generateAci(),
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'keychange' as const,
|
||||
key_changed: generateAci(),
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'change-number-notification' as const,
|
||||
changedId: generateAci(),
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'pinned-message-notification' as const,
|
||||
pinMessage: {
|
||||
targetAuthorAci: generateAci(),
|
||||
targetSentTimestamp: yesterday,
|
||||
},
|
||||
},
|
||||
// From here on, they should not be included
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'group-v2-change' as const,
|
||||
groupV2Change: {
|
||||
details: [{ type: 'terminated' as const }],
|
||||
},
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'chat-session-refreshed' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'conversation-merge' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'delivery-issue' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'group-v1-migration' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'group' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'joined-signal-notification' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'phone-number-discovery' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'universal-timer-notification' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'contact-removed-notification' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'title-transition-notification' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'verified-change' as const,
|
||||
},
|
||||
{
|
||||
...getDefaultMessage('unused'),
|
||||
type: 'message-request-response-event' as const,
|
||||
},
|
||||
];
|
||||
const items = [];
|
||||
const messages: Record<string, MessageAttributesType> = {};
|
||||
let i = 0;
|
||||
|
||||
for (const item of itemsToMixIn) {
|
||||
const firstId = `id${i}`;
|
||||
items.push(firstId);
|
||||
messages[firstId] = {
|
||||
...groupMessage,
|
||||
id: firstId,
|
||||
};
|
||||
|
||||
i += 1;
|
||||
|
||||
const secondId = `id${i}`;
|
||||
items.push(secondId);
|
||||
messages[secondId] = {
|
||||
...item,
|
||||
id: secondId,
|
||||
};
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
const expectedSets: Array<CollapseSet> = [
|
||||
{
|
||||
id: 'id0',
|
||||
type: 'group-updates',
|
||||
messages: [
|
||||
{
|
||||
id: 'id0',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id1',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
atDateBoundary: false,
|
||||
},
|
||||
{
|
||||
id: 'id2',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
atDateBoundary: false,
|
||||
},
|
||||
{
|
||||
id: 'id3',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
atDateBoundary: false,
|
||||
},
|
||||
{
|
||||
id: 'id4',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
atDateBoundary: false,
|
||||
},
|
||||
{
|
||||
id: 'id5',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
atDateBoundary: false,
|
||||
},
|
||||
{
|
||||
id: 'id6',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
atDateBoundary: false,
|
||||
},
|
||||
{
|
||||
id: 'id7',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
atDateBoundary: false,
|
||||
},
|
||||
{
|
||||
id: 'id8',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
atDateBoundary: false,
|
||||
},
|
||||
{
|
||||
id: 'id9',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
atDateBoundary: false,
|
||||
},
|
||||
{
|
||||
id: 'id10',
|
||||
isUnseen: false,
|
||||
extraItems: undefined,
|
||||
atDateBoundary: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'id11',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id12',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id13',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id14',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id15',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id16',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id17',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id18',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id19',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id20',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id21',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id22',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id23',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id24',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id25',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id26',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id27',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id28',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id29',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id30',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id31',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id32',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id33',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id34',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
{
|
||||
id: 'id35',
|
||||
type: 'none',
|
||||
messages: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
const { resultSets, resultScrollToIndex, resultUnseenIndex } =
|
||||
mapItemsIntoCollapseSets({
|
||||
...defaultParams,
|
||||
items,
|
||||
messages,
|
||||
});
|
||||
|
||||
assert.deepEqual(resultSets, expectedSets);
|
||||
assert.isNull(resultScrollToIndex);
|
||||
assert.isNull(resultUnseenIndex);
|
||||
});
|
||||
|
||||
it('returns single set for all timer change items', () => {
|
||||
const items = ['id0', 'id1', 'id2'];
|
||||
@@ -634,20 +978,20 @@ describe('util/CollapseSets', () => {
|
||||
},
|
||||
},
|
||||
id2: {
|
||||
...getDefaultMessage('id2', yesterday),
|
||||
...getDefaultMessage('id2'),
|
||||
type: 'timer-notification',
|
||||
expirationTimerUpdate: {
|
||||
expireTimer: DurationInSeconds.fromHours(3),
|
||||
},
|
||||
},
|
||||
id3: {
|
||||
...getDefaultMessage('id3', yesterday),
|
||||
...getDefaultMessage('id3'),
|
||||
type: 'timer-notification',
|
||||
expirationTimerUpdate: {
|
||||
expireTimer: DurationInSeconds.fromHours(4),
|
||||
},
|
||||
},
|
||||
id4: getDefaultMessage('id4', yesterday),
|
||||
id4: getDefaultMessage('id4'),
|
||||
};
|
||||
|
||||
const expectedSets: Array<CollapseSet> = [
|
||||
@@ -770,21 +1114,21 @@ describe('util/CollapseSets', () => {
|
||||
},
|
||||
},
|
||||
id8: {
|
||||
...getDefaultMessage('id8', yesterday),
|
||||
...getDefaultMessage('id8'),
|
||||
type: 'group-v2-change',
|
||||
groupV2Change: {
|
||||
details: [{ type: 'group-link-reset' }],
|
||||
},
|
||||
},
|
||||
id9: {
|
||||
...getDefaultMessage('id9', yesterday),
|
||||
...getDefaultMessage('id9'),
|
||||
type: 'group-v2-change',
|
||||
groupV2Change: {
|
||||
details: [{ type: 'group-link-reset' }],
|
||||
},
|
||||
},
|
||||
id10: {
|
||||
...getDefaultMessage('id10', yesterday),
|
||||
...getDefaultMessage('id10'),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -919,7 +1263,7 @@ describe('util/CollapseSets', () => {
|
||||
},
|
||||
},
|
||||
id5: {
|
||||
...getDefaultMessage('id5', yesterday),
|
||||
...getDefaultMessage('id5'),
|
||||
type: 'group-v2-change',
|
||||
groupV2Change: {
|
||||
details: [{ type: 'group-link-reset' }],
|
||||
@@ -1041,14 +1385,14 @@ describe('util/CollapseSets', () => {
|
||||
},
|
||||
},
|
||||
id7: {
|
||||
...getDefaultMessage('id7', yesterday),
|
||||
...getDefaultMessage('id7'),
|
||||
type: 'group-v2-change',
|
||||
groupV2Change: {
|
||||
details: [{ type: 'group-link-reset' }],
|
||||
},
|
||||
},
|
||||
id8: {
|
||||
...getDefaultMessage('id8', yesterday),
|
||||
...getDefaultMessage('id8'),
|
||||
type: 'group-v2-change',
|
||||
groupV2Change: {
|
||||
details: [{ type: 'group-link-reset' }],
|
||||
@@ -1145,14 +1489,14 @@ describe('util/CollapseSets', () => {
|
||||
];
|
||||
const messages: MessageLookupType = {
|
||||
id0: {
|
||||
...getDefaultMessage('id0', yesterday),
|
||||
...getDefaultMessage('id0'),
|
||||
type: 'group-v2-change',
|
||||
groupV2Change: {
|
||||
details: [{ type: 'group-link-reset' }],
|
||||
},
|
||||
},
|
||||
id1: {
|
||||
...getDefaultMessage('id1', yesterday),
|
||||
...getDefaultMessage('id1'),
|
||||
type: 'group-v2-change',
|
||||
groupV2Change: {
|
||||
details: [{ type: 'group-link-reset' }],
|
||||
@@ -1223,6 +1567,53 @@ describe('util/CollapseSets', () => {
|
||||
assert.isNull(resultUnseenIndex);
|
||||
});
|
||||
|
||||
it('limits collapse set size based on MAX_COLLAPSE_SET_SIZE', () => {
|
||||
const items = [];
|
||||
const messages: Record<string, MessageAttributesType> = {};
|
||||
|
||||
const max = MAX_COLLAPSE_SET_SIZE * 3 + 1;
|
||||
for (let i = 0; i < max; i += 1) {
|
||||
const id = `id${i}`;
|
||||
items.push(id);
|
||||
messages[id] = {
|
||||
...getDefaultMessage(id),
|
||||
type: 'group-v2-change',
|
||||
groupV2Change: {
|
||||
details: [{ type: 'group-link-reset' }],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const { resultSets, resultScrollToIndex, resultUnseenIndex } =
|
||||
mapItemsIntoCollapseSets({
|
||||
...defaultParams,
|
||||
items,
|
||||
messages,
|
||||
});
|
||||
|
||||
assert.strictEqual(resultSets.length, 4);
|
||||
|
||||
assert.strictEqual(
|
||||
resultSets[0]?.messages?.length,
|
||||
MAX_COLLAPSE_SET_SIZE,
|
||||
'first set'
|
||||
);
|
||||
assert.strictEqual(
|
||||
resultSets[1]?.messages?.length,
|
||||
MAX_COLLAPSE_SET_SIZE,
|
||||
'second set'
|
||||
);
|
||||
assert.strictEqual(
|
||||
resultSets[2]?.messages?.length,
|
||||
MAX_COLLAPSE_SET_SIZE,
|
||||
'third set'
|
||||
);
|
||||
assert.strictEqual(resultSets[3]?.type, 'none', 'fourth set');
|
||||
|
||||
assert.isNull(resultScrollToIndex);
|
||||
assert.isNull(resultUnseenIndex);
|
||||
});
|
||||
|
||||
it('if allowMultidaySets=false, generates a set for each day', () => {
|
||||
const items = [
|
||||
'id0', // Today - 4
|
||||
@@ -1294,21 +1685,21 @@ describe('util/CollapseSets', () => {
|
||||
},
|
||||
},
|
||||
id8: {
|
||||
...getDefaultMessage('id8', yesterday),
|
||||
...getDefaultMessage('id8'),
|
||||
type: 'group-v2-change',
|
||||
groupV2Change: {
|
||||
details: [{ type: 'group-link-reset' }],
|
||||
},
|
||||
},
|
||||
id9: {
|
||||
...getDefaultMessage('id9', yesterday),
|
||||
...getDefaultMessage('id9'),
|
||||
type: 'group-v2-change',
|
||||
groupV2Change: {
|
||||
details: [{ type: 'group-link-reset' }],
|
||||
},
|
||||
},
|
||||
id10: {
|
||||
...getDefaultMessage('id10', yesterday),
|
||||
...getDefaultMessage('id10'),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user