Skip to content

Commit

Permalink
Merge pull request #1154 from dm3-org/1153-UI-Test
Browse files Browse the repository at this point in the history
1153 UI test
  • Loading branch information
AlexNi245 authored Aug 19, 2024
2 parents c0bcc51 + cfdbe67 commit 730297e
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 37 deletions.
8 changes: 8 additions & 0 deletions packages/messenger-widget/src/context/ConversationContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export type ConversationContextType = {
setSelectedContactName: (contactEnsName: string | undefined) => void;
initialized: boolean;
addConversation: (ensName: string) => Promise<ContactPreview | undefined>;
hydrateExistingContactAsync: (
contact: ContactPreview,
) => Promise<ContactPreview>;
loadMoreConversations: () => Promise<number>;
hideContact: (ensName: string) => void;
updateConversationList: (conversation: string, updatedAt: number) => void;
Expand All @@ -28,6 +31,9 @@ export const ConversationContext = React.createContext<ConversationContextType>(
addConversation: (ensName: string) => {
return Promise.resolve({} as ContactPreview);
},
hydrateExistingContactAsync: (contact: ContactPreview) => {
return Promise.resolve({} as ContactPreview);
},
loadMoreConversations: () => {
return new Promise((resolve, reject) => resolve(0));
},
Expand All @@ -45,6 +51,7 @@ export const ConversationContextProvider = ({
}) => {
const {
addConversation,
hydrateExistingContactAsync,
contacts,
conversationCount,
initialized,
Expand All @@ -60,6 +67,7 @@ export const ConversationContextProvider = ({
<ConversationContext.Provider
value={{
addConversation,
hydrateExistingContactAsync,
loadMoreConversations,
contacts,
conversationCount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export const getMockedConversationContext = (
addConversation: (ensName: string) => {
return Promise.resolve({} as ContactPreview);
},
hydrateExistingContactAsync: (contact: ContactPreview) =>
Promise.resolve({} as ContactPreview),
loadMoreConversations: () => {
return new Promise((resolve, reject) => resolve(0));
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ export const useConversation = (config: DM3Configuration) => {
return existingContact;
});
});
return hydratedContact;
};

const hideContact = (_ensName: string) => {
Expand Down Expand Up @@ -389,6 +390,7 @@ export const useConversation = (config: DM3Configuration) => {
contacts,
conversationCount,
addConversation,
hydrateExistingContactAsync,
loadMoreConversations,
initialized: conversationsInitialized,
setSelectedContactName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,14 @@ export class ReceiptDispatcher {

//We acknowledge that we've received the message by sending a READ_RECEIVED acknowledgement to the sender
if (msgIsNew) {
await this.sendOpendReceipt(contactAliasName, messageModel);
await this.sendReceivedReceipte(contactAliasName, messageModel);
console.log('sent received receipt to ', contactAliasName);
}

if (msgIsNew && selectedContactIsSender) {
// if contact is selected then send READ_OPENED acknowledgement to sender for new message received
await this.sendReceivedReceipte(contactAliasName, messageModel);
await this.sendOpendReceipt(contactAliasName, messageModel);
console.log('sent opend receipt to ', contactAliasName);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export const handleMessagesFromDeliveryService = async (
message.envelop.metadata?.encryptedMessageHash!,
}),
);
//sync acknowledgements with the delivery serviceƒƒ
await syncAcknowledgement(account.ensName, acks);

//acknowledge the messages for the sender
Expand All @@ -159,7 +160,7 @@ export const handleMessagesFromDeliveryService = async (
profileKeys,
addMessage,
);
receiptDispatcher.sendMultiple(
await receiptDispatcher.sendMultiple(
selectedContact,
conversation.aliasName,
messagesSortedASC,
Expand Down
55 changes: 54 additions & 1 deletion packages/messenger-widget/src/hooks/messages/useMessage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -628,13 +628,16 @@ describe('useMessage hook test cases', () => {
);

const storageContext = getMockedStorageContext({
getHaltedMessages: jest.fn().mockResolvedValue([]),
editMessageBatchAsync: jest.fn(),
storeMessageBatch: jest.fn(),
storeMessage: jest.fn(),
getMessages: jest.fn().mockResolvedValue([]),
getNumberOfMessages: jest.fn().mockResolvedValue(0),
initialized: true,
});
const conversationContext = getMockedConversationContext({
initialized: true,
selectedContact: getEmptyContact(
'max.eth',
undefined,
Expand All @@ -654,8 +657,22 @@ describe('useMessage hook test cases', () => {
]),
);
},
hydrateExistingContactAsync: () => {
return Promise.resolve({
...getEmptyContact('alice.eth', undefined, false, 0, [
'alice.eth',
]),
contactDetails: {
account: sender.account,
deliveryServiceProfiles: [
ds.deliveryServiceProfile,
],
},
});
},
});
const deliveryServiceContext = getMockedDeliveryServiceContext({
isInitialized: true,
onNewMessage: (cb: Function) => {
console.log('on new message');
},
Expand Down Expand Up @@ -708,6 +725,8 @@ describe('useMessage hook test cases', () => {
result.current.messages['alice.eth'].length > 0,
);

console.log(result.current.messages);

// Filter out the acknowledgement messages
const sentMsgs = result.current.messages['alice.eth'].filter(
(data) => data.envelop.message.metadata.type === 'NEW',
Expand Down Expand Up @@ -738,11 +757,13 @@ describe('useMessage hook test cases', () => {
const syncAcknowledgementMock = jest.fn();

const storageContext = getMockedStorageContext({
getHaltedMessages: jest.fn().mockResolvedValue([]),
editMessageBatchAsync: jest.fn(),
storeMessageBatch: jest.fn(),
storeMessage: jest.fn(),
getMessages: jest.fn().mockResolvedValue([]),
getNumberOfMessages: jest.fn().mockResolvedValue(0),
initialized: true,
});
const conversationContext = getMockedConversationContext({
selectedContact: getEmptyContact(
Expand All @@ -764,6 +785,20 @@ describe('useMessage hook test cases', () => {
]),
);
},
hydrateExistingContactAsync: () => {
return Promise.resolve({
...getEmptyContact('alice.eth', undefined, false, 0, [
'alice.eth',
]),
contactDetails: {
account: sender.account,
deliveryServiceProfiles: [
ds.deliveryServiceProfile,
],
},
});
},
initialized: true,
});
const deliveryServiceContext = getMockedDeliveryServiceContext({
onNewMessage: (cb: Function) => {
Expand All @@ -779,6 +814,7 @@ describe('useMessage hook test cases', () => {
]),
syncAcknowledgement: syncAcknowledgementMock,
removeOnNewMessageListener: jest.fn(),
isInitialized: true,
});
const authContext = getMockedAuthContext({
profileKeys: receiver.profileKeys,
Expand Down Expand Up @@ -969,6 +1005,8 @@ describe('useMessage hook test cases', () => {
const messageFactory = MockMessageFactory(sender, receiver, ds);
//const messages
const storageContext = getMockedStorageContext({
initialized: true,
getHaltedMessages: jest.fn().mockResolvedValue([]),
editMessageBatchAsync: jest.fn(),
storeMessageBatch: jest.fn(),
storeMessage: jest.fn(),
Expand All @@ -986,6 +1024,7 @@ describe('useMessage hook test cases', () => {
),
});
const conversationContext = getMockedConversationContext({
initialized: true,
selectedContact: getEmptyContact(
'max.eth',
undefined,
Expand All @@ -1005,8 +1044,22 @@ describe('useMessage hook test cases', () => {
]),
);
},
hydrateExistingContactAsync: () => {
return Promise.resolve({
...getEmptyContact('alice.eth', undefined, false, 0, [
'alice.eth',
]),
contactDetails: {
account: sender.account,
deliveryServiceProfiles: [
ds.deliveryServiceProfile,
],
},
});
},
});
const deliveryServiceContext = getMockedDeliveryServiceContext({
isInitialized: true,
onNewMessage: (cb: Function) => {
console.log('on new message');
},
Expand Down Expand Up @@ -1092,7 +1145,7 @@ describe('useMessage hook test cases', () => {
expect(moreSentMsgs.length).toBe(213);
//991 = 99 message 100(since pageSize starts from 0) = 1 offset
expect(
result.current.messages['alice.eth'][225].envelop.message
result.current.messages['alice.eth'][212].envelop.message
.message,
).toBe('hello dm3 991');
});
Expand Down
110 changes: 77 additions & 33 deletions packages/messenger-widget/src/hooks/messages/useMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import { ConversationContext } from '../../context/ConversationContext';
import { DeliveryServiceContext } from '../../context/DeliveryServiceContext';
import { StorageContext } from '../../context/StorageContext';
import { TLDContext } from '../../context/TLDContext';
import { ContactPreview } from '../../interfaces/utils';
import { submitEnvelopsToReceiversDs } from '../../utils/deliveryService/submitEnvelopsToReceiversDs';
import { useHaltDelivery } from '../haltDelivery/useHaltDelivery';
import { useMainnetProvider } from '../mainnetprovider/useMainnetProvider';
import { ReceiptDispatcher } from './receipt/ReceiptDispatcher';
import { renderMessage } from './renderer/renderMessage';
import { checkIfEnvelopAreInSizeLimit } from './sizeLimit/checkIfEnvelopIsInSizeLimit';
Expand Down Expand Up @@ -58,9 +60,11 @@ export type MessageStorage = {
export const useMessage = () => {
const {
contacts,
initialized: conversationsInitialized,
selectedContact,
addConversation,
updateConversationList,
hydrateExistingContactAsync,
} = useContext(ConversationContext);
const { account, profileKeys } = useContext(AuthContext);
const {
Expand Down Expand Up @@ -101,7 +105,13 @@ export const useMessage = () => {
}, [contacts]);

useEffect(() => {
if (!account) return;
if (
!account ||
!storageInitialized ||
!deliveryServiceInitialized ||
!conversationsInitialized
)
return;
const getMessagesFromDs = async () => {
const messagesFromDs = await handleMessagesFromDeliveryService(
selectedContact,
Expand All @@ -121,7 +131,12 @@ export const useMessage = () => {
);
};
getMessagesFromDs();
}, [storageInitialized, account, deliveryServiceInitialized]);
}, [
storageInitialized,
account,
deliveryServiceInitialized,
conversationsInitialized,
]);

//Effect to reset the messages when the storage is initialized, i.e on account change
useEffect(() => {
Expand Down Expand Up @@ -278,40 +293,69 @@ export const useMessage = () => {
const recipientIsDm3User =
!!recipient?.contactDetails.account.profile?.publicEncryptionKey;

//If the recipient is not a dm3 user we can store the message in the storage.
//Ideally the message will be submitted once the receiver has created a profile.
//https://github.com/orgs/dm3-org/projects/5?pane=issue&itemId=64716043 will refine this
if (!recipientIsDm3User) {
//StorageEnvelopContainerNew to store the message in the storage
const messageModel: MessageModel = {
envelop: {
message,
metadata: {
encryptionScheme: 'x25519-chacha20-poly1305',
//since we don't have a recipient we can't encrypt the deliveryInformation
deliveryInformation: '',
//Because storing a message is always an internal process we dont need to sign it. The signature is only needed for the delivery service
signature: '',
encryptedMessageHash: sha256(stringify(message)),
version: 'v1',
},
//If the recipient is a dm3 user we can send the message to the delivery service
if (recipientIsDm3User) {
return await _dispatchMessage(contact, recipient, message);
}

//There are cases were a messages is already to be send even though the contract hydration is not finished yet.
//This happens if a message has been picked up from the delivery service and the clients sends READ_RECEIVE or READ_OPENED acknowledgements
//In that case we've to check again to the if the user is a DM3 user, before we decide to keep the message
const potentialReceiver = contacts.find(
(c) => c.contactDetails.account.ensName === contact,
);

//This should normally not happen, since the contact should be already in the contact list
if (!potentialReceiver) {
return await haltMessage(contact, message);
}
const hydratedC = await hydrateExistingContactAsync(potentialReceiver);

//If the user is a DM3 user we can send the message to the delivery service
if (hydratedC.contactDetails.account.profile?.publicEncryptionKey) {
return await _dispatchMessage(contact, hydratedC, message);
}

//If neither the recipient nor the potential recipient is a DM3 user we store the message in the storage
return await haltMessage(contact, message);
};

const haltMessage = async (contact: string, message: Message) => {
//StorageEnvelopContainerNew to store the message in the storage
const messageModel: MessageModel = {
envelop: {
message,
metadata: {
encryptionScheme: 'x25519-chacha20-poly1305',
//since we don't have a recipient we can't encrypt the deliveryInformation
deliveryInformation: '',
//Because storing a message is always an internal process we dont need to sign it. The signature is only needed for the delivery service
signature: '',
encryptedMessageHash: sha256(stringify(message)),
version: 'v1',
},
messageState: MessageState.Created,
source: MessageSource.Client,
reactions: [],
},
messageState: MessageState.Created,
source: MessageSource.Client,
reactions: [],
};
setMessages((prev) => {
//Check message has been added previously
return {
...prev,
[contact]: [...(prev[contact] ?? []), messageModel],
};
setMessages((prev) => {
//Check message has been added previously
return {
...prev,
[contact]: [...(prev[contact] ?? []), messageModel],
};
});
//Store the message and mark it as halted
storeMessage(contact, messageModel, true);
return { isSuccess: true };
}
});
//Store the message and mark it as halted
storeMessage(contact, messageModel, true);
return { isSuccess: true };
};

const _dispatchMessage = async (
contact: string,
recipient: ContactPreview,
message: Message,
) => {
//Build the envelops based on the message and the users profileKeys.
//For each deliveryServiceProfile a envelop is created that will be sent to the delivery service
const envelops = await Promise.all(
Expand Down

0 comments on commit 730297e

Please sign in to comment.