Remove client-side isLoggedIn value
[ProtonMail-WebClient.git] / packages / shared / test / contacts / merge.spec.ts
blobac9bd48f6bbdf4f4a227af74dcee8be188dbc390
1 import { extractMergeable } from '@proton/shared/lib/contacts/helpers/merge';
2 import type { FormattedContact } from '@proton/shared/lib/interfaces/contacts/FormattedContact';
4 type TestContact = Pick<FormattedContact, 'Name' | 'emails'>;
6 /**
7  * Check if two contacts match
8  * @dev For this test, for contact equality it's enough to check that the 'Name' and 'emails' properties match
9  */
10 const doContactsMatch = (contactLeft: TestContact, contactRight: TestContact) => {
11     const { Name: nameLeft, emails: emailsLeft } = contactLeft;
12     const { Name: nameRight, emails: emailsRight } = contactRight;
14     if (nameLeft !== nameRight) {
15         return false;
16     }
17     return emailsLeft.length === emailsRight.length && emailsLeft.every((email, i) => email === emailsRight[i]);
20 /**
21  * Check if two arrays of contacts contain the same list of contacts, possibly in a different order
22  */
23 const doContactListsMatch = (contactsLeft: TestContact[], contactsRight: TestContact[]) => {
24     const differentContactsRight = [...contactsRight];
26     for (const contactLeft of contactsLeft) {
27         const index = differentContactsRight.findIndex((contact) => doContactsMatch(contact, contactLeft));
29         if (index === -1) {
30             return false;
31         }
32         differentContactsRight.splice(index, 1);
33     }
35     return !differentContactsRight.length;
38 /**
39  * Check if two arrays of contacts lists match, possibly in a different order
40  */
41 const doContactListArraysMatch = (contactListsLeft: TestContact[][], contactListsRight: TestContact[][]) => {
42     const differentContactListsRight = [...contactListsRight];
44     for (const contactListLeft of contactListsLeft) {
45         const index = differentContactListsRight.findIndex((contactList) =>
46             doContactListsMatch(contactList, contactListLeft)
47         );
49         if (index === -1) {
50             return false;
51         }
52         differentContactListsRight.splice(index, 1);
53     }
55     return !differentContactListsRight.length;
58 describe('merge', () => {
59     describe('extractMergeable', () => {
60         it('should detect as mergeable multiple contacts with the same normalized name and same normalized email', () => {
61             // only names and emails are relevant for the logic of extractMergeable
62             const contacts = [
63                 { Name: 'TestName', emails: ['testname@pm.me', 'TestName@protonmail.com'] },
64                 { Name: 'Someone else', emails: ['else@proton.me'] },
65                 { Name: 'TESTNAME', emails: ['TESTNAME@proton.me'] },
66                 { Name: 'testname', emails: ['testname@pm.me'] },
67                 { Name: 'Party crasher', emails: ['party_crasher@proton.me'] },
68                 { Name: 'TestEmail', emails: ['testemail@pm.me', 'TestEmail@protonmail.com'] },
69                 { Name: 'Another one', emails: ['another@proton.me'] },
70                 { Name: 'I am testing email', emails: ['TESTEMAIL@pm.me'] },
71                 { Name: 'Party crasher friend 1', emails: ['party_crasher_friend_1@proton.me'] },
72                 { Name: 'Party crasher friend 2', emails: ['party_crasher_friend_2@proton.me'] },
73                 { Name: 'A final email test', emails: ['Testemail@protonmail.com', 'another@pm.me'] },
74             ] as FormattedContact[];
75             const mergeableContacts = extractMergeable(contacts);
76             const expectedMergeableContacts = [
77                 // mergeable by name
78                 [contacts[0], contacts[2], contacts[3]],
79                 // mergeable by email
80                 [contacts[5], contacts[7], contacts[10]],
81             ];
83             expect(doContactListArraysMatch(mergeableContacts, expectedMergeableContacts)).toEqual(true);
84         });
86         it('should detect as mergeable two contacts with different names and emails, but which share a name and an email with a third one', () => {
87             // only names and emails are relevant for the logic of extractMergeable
88             const contacts = [
89                 { Name: 'First', emails: ['first@pm.me'] },
90                 { Name: 'Second', emails: ['second@proton.me', 'first@pm.me'] },
91                 { Name: 'second', emails: ['third@proton.me'] },
92             ] as FormattedContact[];
93             const mergeableContacts = extractMergeable(contacts);
95             expect(doContactListArraysMatch(mergeableContacts, [contacts])).toEqual(true);
96         });
98         it('should not detect as mergeable two contacts with unknown names added by Proton', () => {
99             // only names and emails are relevant for the logic of extractMergeable
100             const contacts = [
101                 { Name: 'Unknown', emails: ['first@pm.me'] },
102                 { Name: 'Unknown', emails: ['second@proton.me', 'another@pm.me'] },
103                 { Name: '<Unknown>', emails: ['third@proton.me'] },
104                 { Name: '<Unknown>', emails: ['fourth@proton.me'] },
105             ] as FormattedContact[];
106             const mergeableContacts = extractMergeable(contacts);
108             expect(doContactListArraysMatch(mergeableContacts, [])).toEqual(true);
109         });
110     });