Revert "Refactor outbound delivery state"
This reverts commit 9c48a95eb5
.
This commit is contained in:
parent
77668c3247
commit
ad217c808d
29 changed files with 694 additions and 3197 deletions
|
@ -2,7 +2,6 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { assert } from 'chai';
|
||||
import { SendStatus } from '../../messages/MessageSendState';
|
||||
|
||||
describe('Conversations', () => {
|
||||
async function resetConversationController(): Promise<void> {
|
||||
|
@ -20,9 +19,9 @@ describe('Conversations', () => {
|
|||
|
||||
// Creating a fake conversation
|
||||
const conversation = new window.Whisper.Conversation({
|
||||
id: window.getGuid(),
|
||||
id: '8c45efca-67a4-4026-b990-9537d5d1a08f',
|
||||
e164: '+15551234567',
|
||||
uuid: window.getGuid(),
|
||||
uuid: '2f2734aa-f69d-4c1c-98eb-50eb0fc512d7',
|
||||
type: 'private',
|
||||
inbox_position: 0,
|
||||
isPinned: false,
|
||||
|
@ -34,6 +33,7 @@ describe('Conversations', () => {
|
|||
version: 0,
|
||||
});
|
||||
|
||||
const destinationE164 = '+15557654321';
|
||||
window.textsecure.storage.user.setNumberAndDeviceId(
|
||||
ourNumber,
|
||||
2,
|
||||
|
@ -42,29 +42,27 @@ describe('Conversations', () => {
|
|||
window.textsecure.storage.user.setUuidAndDeviceId(ourUuid, 2);
|
||||
await window.ConversationController.loadPromise();
|
||||
|
||||
await window.Signal.Data.saveConversation(conversation.attributes);
|
||||
|
||||
// Creating a fake message
|
||||
const now = Date.now();
|
||||
let message = new window.Whisper.Message({
|
||||
attachments: [],
|
||||
body: 'bananas',
|
||||
conversationId: conversation.id,
|
||||
delivered: 1,
|
||||
delivered_to: [destinationE164],
|
||||
destination: destinationE164,
|
||||
expirationStartTimestamp: now,
|
||||
hasAttachments: false,
|
||||
hasFileAttachments: false,
|
||||
hasVisualMediaAttachments: false,
|
||||
id: window.getGuid(),
|
||||
id: 'd8f2b435-e2ef-46e0-8481-07e68af251c6',
|
||||
received_at: now,
|
||||
recipients: [destinationE164],
|
||||
sent: true,
|
||||
sent_at: now,
|
||||
sent_to: [destinationE164],
|
||||
timestamp: now,
|
||||
type: 'outgoing',
|
||||
sendStateByConversationId: {
|
||||
[conversation.id]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: now,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Saving to db and updating the convo's last message
|
||||
|
@ -73,7 +71,7 @@ describe('Conversations', () => {
|
|||
Message: window.Whisper.Message,
|
||||
});
|
||||
message = window.MessageController.register(message.id, message);
|
||||
await window.Signal.Data.updateConversation(conversation.attributes);
|
||||
await window.Signal.Data.saveConversation(conversation.attributes);
|
||||
await conversation.updateLastMessage();
|
||||
|
||||
// Should be set to bananas because that's the last message sent.
|
||||
|
|
|
@ -5,19 +5,9 @@ import { assert } from 'chai';
|
|||
import * as sinon from 'sinon';
|
||||
import { setup as setupI18n } from '../../../js/modules/i18n';
|
||||
import enMessages from '../../../_locales/en/messages.json';
|
||||
import { SendStatus } from '../../messages/MessageSendState';
|
||||
import MessageSender from '../../textsecure/SendMessage';
|
||||
import type { StorageAccessType } from '../../types/Storage.d';
|
||||
import { SignalService as Proto } from '../../protobuf';
|
||||
|
||||
describe('Message', () => {
|
||||
const STORAGE_KEYS_TO_RESTORE: Array<keyof StorageAccessType> = [
|
||||
'number_id',
|
||||
'uuid_id',
|
||||
];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const oldStorageValues = new Map<keyof StorageAccessType, any>();
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
const attributes = {
|
||||
|
@ -43,25 +33,16 @@ describe('Message', () => {
|
|||
before(async () => {
|
||||
window.ConversationController.reset();
|
||||
await window.ConversationController.load();
|
||||
|
||||
STORAGE_KEYS_TO_RESTORE.forEach(key => {
|
||||
oldStorageValues.set(key, window.textsecure.storage.get(key));
|
||||
});
|
||||
window.textsecure.storage.put('number_id', `${me}.2`);
|
||||
window.textsecure.storage.put('uuid_id', `${ourUuid}.2`);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
window.textsecure.storage.remove('number_id');
|
||||
window.textsecure.storage.remove('uuid_id');
|
||||
|
||||
await window.Signal.Data.removeAll();
|
||||
await window.storage.fetch();
|
||||
|
||||
oldStorageValues.forEach((oldValue, key) => {
|
||||
if (oldValue) {
|
||||
window.textsecure.storage.put(key, oldValue);
|
||||
} else {
|
||||
window.textsecure.storage.remove(key);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function beforeEach() {
|
||||
|
@ -74,92 +55,25 @@ describe('Message', () => {
|
|||
|
||||
// NOTE: These tests are incomplete.
|
||||
describe('send', () => {
|
||||
let oldMessageSender: undefined | MessageSender;
|
||||
|
||||
beforeEach(function beforeEach() {
|
||||
oldMessageSender = window.textsecure.messaging;
|
||||
|
||||
window.textsecure.messaging =
|
||||
oldMessageSender ?? new MessageSender('username', 'password');
|
||||
this.sandbox
|
||||
.stub(window.textsecure.messaging, 'sendSyncMessage')
|
||||
.resolves();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (oldMessageSender) {
|
||||
window.textsecure.messaging = oldMessageSender;
|
||||
} else {
|
||||
// `window.textsecure.messaging` can be undefined in tests. Instead of updating
|
||||
// the real type, I just ignore it.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
delete (window.textsecure as any).messaging;
|
||||
}
|
||||
});
|
||||
|
||||
it('updates `sendStateByConversationId`', async function test() {
|
||||
this.sandbox.useFakeTimers(1234);
|
||||
|
||||
const ourConversationId = window.ConversationController.getOurConversationIdOrThrow();
|
||||
const conversation1 = await window.ConversationController.getOrCreateAndWait(
|
||||
'a072df1d-7cee-43e2-9e6b-109710a2131c',
|
||||
'private'
|
||||
);
|
||||
const conversation2 = await window.ConversationController.getOrCreateAndWait(
|
||||
'62bd8ef1-68da-4cfd-ac1f-3ea85db7473e',
|
||||
'private'
|
||||
);
|
||||
|
||||
const message = createMessage({
|
||||
type: 'outgoing',
|
||||
conversationId: (
|
||||
await window.ConversationController.getOrCreateAndWait(
|
||||
'71cc190f-97ba-4c61-9d41-0b9444d721f9',
|
||||
'group'
|
||||
)
|
||||
).id,
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: 123,
|
||||
},
|
||||
[conversation1.id]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: 123,
|
||||
},
|
||||
[conversation2.id]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: 456,
|
||||
},
|
||||
},
|
||||
});
|
||||
it("saves the result's dataMessage", async () => {
|
||||
const message = createMessage({ type: 'outgoing', source });
|
||||
|
||||
const fakeDataMessage = new ArrayBuffer(0);
|
||||
const ignoredUuid = window.getGuid();
|
||||
|
||||
const promise = Promise.resolve({
|
||||
successfulIdentifiers: [conversation1.get('uuid'), ignoredUuid],
|
||||
errors: [
|
||||
Object.assign(new Error('failed'), {
|
||||
identifier: conversation2.get('uuid'),
|
||||
}),
|
||||
],
|
||||
const result = {
|
||||
dataMessage: fakeDataMessage,
|
||||
});
|
||||
};
|
||||
const promise = Promise.resolve(result);
|
||||
await message.send(promise);
|
||||
|
||||
const result = message.get('sendStateByConversationId') || {};
|
||||
assert.hasAllKeys(result, [
|
||||
ourConversationId,
|
||||
conversation1.id,
|
||||
conversation2.id,
|
||||
]);
|
||||
assert.strictEqual(result[ourConversationId]?.status, SendStatus.Sent);
|
||||
assert.strictEqual(result[ourConversationId]?.updatedAt, 1234);
|
||||
assert.strictEqual(result[conversation1.id]?.status, SendStatus.Sent);
|
||||
assert.strictEqual(result[conversation1.id]?.updatedAt, 1234);
|
||||
assert.strictEqual(result[conversation2.id]?.status, SendStatus.Failed);
|
||||
assert.strictEqual(result[conversation2.id]?.updatedAt, 1234);
|
||||
assert.strictEqual(message.get('dataMessage'), fakeDataMessage);
|
||||
});
|
||||
|
||||
it('updates the `sent` attribute', async () => {
|
||||
const message = createMessage({ type: 'outgoing', source, sent: false });
|
||||
|
||||
await message.send(Promise.resolve({}));
|
||||
|
||||
assert.isTrue(message.get('sent'));
|
||||
});
|
||||
|
||||
it('saves errors from promise rejections with errors', async () => {
|
||||
|
|
|
@ -1,231 +0,0 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { assert } from 'chai';
|
||||
import { omit } from 'lodash';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { MessageModel } from '../../models/messages';
|
||||
import { SendStatus } from '../../messages/MessageSendState';
|
||||
import type { StorageAccessType } from '../../types/Storage.d';
|
||||
import type { MessageAttributesType } from '../../model-types.d';
|
||||
import type { WhatIsThis } from '../../window.d';
|
||||
import dataInterface from '../../sql/Client';
|
||||
|
||||
const {
|
||||
getMessageById,
|
||||
saveMessage,
|
||||
saveConversation,
|
||||
_getSendStates,
|
||||
} = dataInterface;
|
||||
|
||||
describe('saveMessage', () => {
|
||||
const STORAGE_KEYS_TO_RESTORE: Array<keyof StorageAccessType> = [
|
||||
'number_id',
|
||||
'uuid_id',
|
||||
];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const oldStorageValues = new Map<keyof StorageAccessType, any>();
|
||||
|
||||
before(async () => {
|
||||
window.ConversationController.reset();
|
||||
await window.ConversationController.load();
|
||||
|
||||
STORAGE_KEYS_TO_RESTORE.forEach(key => {
|
||||
oldStorageValues.set(key, window.textsecure.storage.get(key));
|
||||
});
|
||||
window.textsecure.storage.put('number_id', '+14155555556.2');
|
||||
window.textsecure.storage.put('uuid_id', `${uuid()}.2`);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await window.Signal.Data.removeAll();
|
||||
await window.storage.fetch();
|
||||
|
||||
oldStorageValues.forEach((oldValue, key) => {
|
||||
if (oldValue) {
|
||||
window.textsecure.storage.put(key, oldValue);
|
||||
} else {
|
||||
window.textsecure.storage.remove(key);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// NOTE: These tests are incomplete, and were only added to test new functionality.
|
||||
it('inserts a new message if passed an object with no ID', async () => {
|
||||
const messageId = await saveMessage(
|
||||
({
|
||||
type: 'incoming',
|
||||
sent_at: Date.now(),
|
||||
conversationId: uuid(),
|
||||
received_at: Date.now(),
|
||||
timestamp: Date.now(),
|
||||
// TODO: DESKTOP-722
|
||||
} as Partial<MessageAttributesType>) as WhatIsThis,
|
||||
{ Message: MessageModel }
|
||||
);
|
||||
|
||||
assert.exists(await getMessageById(messageId, { Message: MessageModel }));
|
||||
});
|
||||
|
||||
it('when inserting a message, saves send states', async () => {
|
||||
const ourConversationId = window.ConversationController.getOurConversationIdOrThrow();
|
||||
const conversation1Id = uuid();
|
||||
const conversation2Id = uuid();
|
||||
|
||||
await Promise.all(
|
||||
[conversation1Id, conversation2Id].map(id =>
|
||||
saveConversation({
|
||||
id,
|
||||
inbox_position: 0,
|
||||
isPinned: false,
|
||||
lastMessageDeletedForEveryone: false,
|
||||
markedUnread: false,
|
||||
messageCount: 0,
|
||||
sentMessageCount: 0,
|
||||
type: 'private',
|
||||
profileSharing: true,
|
||||
version: 1,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const messageId = await saveMessage(
|
||||
{
|
||||
id: uuid(),
|
||||
type: 'outgoing',
|
||||
sent_at: Date.now(),
|
||||
conversationId: uuid(),
|
||||
received_at: Date.now(),
|
||||
timestamp: Date.now(),
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: 1,
|
||||
},
|
||||
[conversation1Id]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: 2,
|
||||
},
|
||||
[conversation2Id]: {
|
||||
status: SendStatus.Delivered,
|
||||
updatedAt: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
{ forceSave: true, Message: MessageModel }
|
||||
);
|
||||
|
||||
const assertSendState = async (
|
||||
destinationConversationId: string,
|
||||
expectedStatusString: string,
|
||||
expectedUpdatedAt: number
|
||||
): Promise<void> => {
|
||||
assert.deepEqual(
|
||||
await _getSendStates({ messageId, destinationConversationId }),
|
||||
[{ status: expectedStatusString, updatedAt: expectedUpdatedAt }]
|
||||
);
|
||||
};
|
||||
|
||||
await Promise.all([
|
||||
assertSendState(ourConversationId, 'Sent', 1),
|
||||
assertSendState(conversation1Id, 'Pending', 2),
|
||||
assertSendState(conversation2Id, 'Delivered', 3),
|
||||
]);
|
||||
});
|
||||
|
||||
it('when updating a message, updates and inserts send states', async () => {
|
||||
const ourConversationId = window.ConversationController.getOurConversationIdOrThrow();
|
||||
const conversation1Id = uuid();
|
||||
const conversation2Id = uuid();
|
||||
const conversation3Id = uuid();
|
||||
|
||||
await Promise.all(
|
||||
[conversation1Id, conversation2Id, conversation3Id].map(id =>
|
||||
saveConversation({
|
||||
id,
|
||||
inbox_position: 0,
|
||||
isPinned: false,
|
||||
lastMessageDeletedForEveryone: false,
|
||||
markedUnread: false,
|
||||
messageCount: 0,
|
||||
sentMessageCount: 0,
|
||||
type: 'private',
|
||||
profileSharing: true,
|
||||
version: 1,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const messageAttributes: MessageAttributesType = {
|
||||
id: 'to be replaced',
|
||||
type: 'outgoing',
|
||||
sent_at: Date.now(),
|
||||
conversationId: uuid(),
|
||||
received_at: Date.now(),
|
||||
timestamp: Date.now(),
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: 1,
|
||||
},
|
||||
[conversation1Id]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: 2,
|
||||
},
|
||||
[conversation2Id]: {
|
||||
status: SendStatus.Delivered,
|
||||
updatedAt: 3,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const messageId = await saveMessage(
|
||||
// TODO: DESKTOP-722
|
||||
(omit(
|
||||
messageAttributes,
|
||||
'id'
|
||||
) as Partial<MessageAttributesType>) as WhatIsThis,
|
||||
{ Message: MessageModel }
|
||||
);
|
||||
|
||||
messageAttributes.id = messageId;
|
||||
messageAttributes.sendStateByConversationId = {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Delivered,
|
||||
updatedAt: 4,
|
||||
},
|
||||
[conversation1Id]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: 5,
|
||||
},
|
||||
[conversation2Id]: {
|
||||
status: SendStatus.Read,
|
||||
updatedAt: 6,
|
||||
},
|
||||
[conversation3Id]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: 7,
|
||||
},
|
||||
};
|
||||
|
||||
await saveMessage(messageAttributes, { Message: MessageModel });
|
||||
|
||||
const assertSendState = async (
|
||||
destinationConversationId: string,
|
||||
expectedStatusString: string,
|
||||
expectedUpdatedAt: number
|
||||
): Promise<void> => {
|
||||
assert.deepEqual(
|
||||
await _getSendStates({ messageId, destinationConversationId }),
|
||||
[{ status: expectedStatusString, updatedAt: expectedUpdatedAt }]
|
||||
);
|
||||
};
|
||||
|
||||
await Promise.all([
|
||||
assertSendState(ourConversationId, 'Delivered', 4),
|
||||
assertSendState(conversation1Id, 'Sent', 5),
|
||||
assertSendState(conversation2Id, 'Read', 6),
|
||||
assertSendState(conversation3Id, 'Pending', 7),
|
||||
]);
|
||||
});
|
||||
});
|
|
@ -3,16 +3,10 @@
|
|||
|
||||
import { assert } from 'chai';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { SendStatus } from '../../../messages/MessageSendState';
|
||||
import {
|
||||
MessageAttributesType,
|
||||
ShallowChallengeError,
|
||||
} from '../../../model-types.d';
|
||||
import { ConversationType } from '../../../state/ducks/conversations';
|
||||
|
||||
import {
|
||||
canReply,
|
||||
getMessagePropStatus,
|
||||
isEndSession,
|
||||
isGroupUpdate,
|
||||
isIncoming,
|
||||
|
@ -20,12 +14,6 @@ import {
|
|||
} from '../../../state/selectors/message';
|
||||
|
||||
describe('state/selectors/messages', () => {
|
||||
let ourConversationId: string;
|
||||
|
||||
beforeEach(() => {
|
||||
ourConversationId = uuid();
|
||||
});
|
||||
|
||||
describe('canReply', () => {
|
||||
const defaultConversation: ConversationType = {
|
||||
id: uuid(),
|
||||
|
@ -47,7 +35,7 @@ describe('state/selectors/messages', () => {
|
|||
isGroupV1AndDisabled: true,
|
||||
});
|
||||
|
||||
assert.isFalse(canReply(message, ourConversationId, getConversationById));
|
||||
assert.isFalse(canReply(message, getConversationById));
|
||||
});
|
||||
|
||||
// NOTE: This is missing a test for mandatory profile sharing.
|
||||
|
@ -60,70 +48,33 @@ describe('state/selectors/messages', () => {
|
|||
};
|
||||
const getConversationById = () => defaultConversation;
|
||||
|
||||
assert.isFalse(canReply(message, ourConversationId, getConversationById));
|
||||
assert.isFalse(canReply(message, getConversationById));
|
||||
});
|
||||
|
||||
it('returns false for outgoing messages that have not been sent', () => {
|
||||
const message = {
|
||||
conversationId: 'fake-conversation-id',
|
||||
type: 'outgoing' as const,
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
sent_to: [],
|
||||
};
|
||||
const getConversationById = () => defaultConversation;
|
||||
|
||||
assert.isFalse(canReply(message, ourConversationId, getConversationById));
|
||||
assert.isFalse(canReply(message, getConversationById));
|
||||
});
|
||||
|
||||
it('returns true for outgoing messages that are only sent to yourself', () => {
|
||||
it('returns true for outgoing messages that have been delivered to at least one person', () => {
|
||||
const message = {
|
||||
conversationId: 'fake-conversation-id',
|
||||
type: 'outgoing' as const,
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
};
|
||||
const getConversationById = () => defaultConversation;
|
||||
|
||||
assert.isTrue(canReply(message, ourConversationId, getConversationById));
|
||||
});
|
||||
|
||||
it('returns true for outgoing messages that have been sent to at least one person', () => {
|
||||
const message = {
|
||||
conversationId: 'fake-conversation-id',
|
||||
type: 'outgoing' as const,
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
receipients: [uuid(), uuid()],
|
||||
sent_to: [uuid()],
|
||||
};
|
||||
const getConversationById = () => ({
|
||||
...defaultConversation,
|
||||
type: 'group' as const,
|
||||
});
|
||||
|
||||
assert.isTrue(canReply(message, ourConversationId, getConversationById));
|
||||
assert.isTrue(canReply(message, getConversationById));
|
||||
});
|
||||
|
||||
it('returns true for incoming messages', () => {
|
||||
|
@ -133,247 +84,7 @@ describe('state/selectors/messages', () => {
|
|||
};
|
||||
const getConversationById = () => defaultConversation;
|
||||
|
||||
assert.isTrue(canReply(message, ourConversationId, getConversationById));
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMessagePropStatus', () => {
|
||||
const createMessage = (overrides: Partial<MessageAttributesType>) => ({
|
||||
type: 'outgoing' as const,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
it('returns undefined for incoming messages', () => {
|
||||
const message = createMessage({ type: 'incoming' });
|
||||
|
||||
assert.isUndefined(
|
||||
getMessagePropStatus(message, ourConversationId, true)
|
||||
);
|
||||
});
|
||||
|
||||
it('returns "paused" for messages with challenges', () => {
|
||||
const challengeError: ShallowChallengeError = Object.assign(
|
||||
new Error('a challenge'),
|
||||
{
|
||||
name: 'SendMessageChallengeError',
|
||||
retryAfter: 123,
|
||||
data: {},
|
||||
}
|
||||
);
|
||||
const message = createMessage({ errors: [challengeError] });
|
||||
|
||||
assert.strictEqual(
|
||||
getMessagePropStatus(message, ourConversationId, true),
|
||||
'paused'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns "partial-sent" if the message has errors but was sent to at least one person', () => {
|
||||
const message = createMessage({
|
||||
errors: [new Error('whoopsie')],
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Delivered,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
getMessagePropStatus(message, ourConversationId, true),
|
||||
'partial-sent'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns "error" if the message has errors and has not been sent', () => {
|
||||
const message = createMessage({
|
||||
errors: [new Error('whoopsie')],
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
getMessagePropStatus(message, ourConversationId, true),
|
||||
'error'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns "read" if the message is just for you and has been sent', () => {
|
||||
const message = createMessage({
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
[true, false].forEach(readReceiptSetting => {
|
||||
assert.strictEqual(
|
||||
getMessagePropStatus(message, ourConversationId, readReceiptSetting),
|
||||
'read'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns "read" if the message was read by at least one person and you have read receipts enabled', () => {
|
||||
const readMessage = createMessage({
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Delivered,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Read,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.strictEqual(
|
||||
getMessagePropStatus(readMessage, ourConversationId, true),
|
||||
'read'
|
||||
);
|
||||
|
||||
const viewedMessage = createMessage({
|
||||
sendStateByConversationId: {
|
||||
[uuid()]: {
|
||||
status: SendStatus.Viewed,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.strictEqual(
|
||||
getMessagePropStatus(viewedMessage, ourConversationId, true),
|
||||
'read'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns "delivered" if the message was read by at least one person and you have read receipts disabled', () => {
|
||||
const message = createMessage({
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Read,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
getMessagePropStatus(message, ourConversationId, false),
|
||||
'delivered'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns "delivered" if the message was delivered to at least one person, but no "higher"', () => {
|
||||
const message = createMessage({
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Delivered,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
getMessagePropStatus(message, ourConversationId, true),
|
||||
'delivered'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns "sent" if the message was sent to at least one person, but no "higher"', () => {
|
||||
const message = createMessage({
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
getMessagePropStatus(message, ourConversationId, true),
|
||||
'sent'
|
||||
);
|
||||
});
|
||||
|
||||
it('returns "sending" if the message has not been sent yet, even if it has been synced to yourself', () => {
|
||||
const message = createMessage({
|
||||
sendStateByConversationId: {
|
||||
[ourConversationId]: {
|
||||
status: SendStatus.Sent,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
[uuid()]: {
|
||||
status: SendStatus.Pending,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
getMessagePropStatus(message, ourConversationId, true),
|
||||
'sending'
|
||||
);
|
||||
assert.isTrue(canReply(message, getConversationById));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue