1 import uniqueId from 'lodash/uniqueId';
3 import { itemBuilder } from '@proton/pass/lib/items/item.builder';
4 import type { ItemRevision } from '@proton/pass/types';
5 import { ContentFormatVersion, ItemState } from '@proton/pass/types';
6 import { prop } from '@proton/pass/utils/fp/lens';
8 import { getDuplicatePasswords } from './monitor.utils';
10 const createMockItem = (password: string): ItemRevision<'login'> => ({
12 contentFormatVersion: ContentFormatVersion.Item,
14 data: itemBuilder('login').set('content', (content) => content.set('password', password)).data,
23 state: ItemState.Active,
26 describe('getDuplicatePasswords', () => {
27 test('should correctly identify and return duplicate passwords', () => {
29 ...Array.from({ length: 5 }, () => createMockItem('AAA')),
30 ...Array.from({ length: 2 }, () => createMockItem('BBB')),
31 ...Array.from({ length: 5 }, () => createMockItem(uniqueId())),
32 ].sort(() => Math.random() - 0.5); /* shuffle the array */
34 const duplicates = getDuplicatePasswords(items).sort((a, b) => b.length - a.length);
35 expect(duplicates.length).toEqual(2);
36 expect(duplicates[0].length).toEqual(5);
37 expect(duplicates[1].length).toEqual(2);
38 expect(new Set(duplicates[0].map(prop('itemId'))).size).toEqual(5);
39 expect(new Set(duplicates[1].map(prop('itemId'))).size).toEqual(2);
42 test('should handle case where there are no duplicates', () => {
43 const items = Array.from({ length: 10 }, () => createMockItem(uniqueId()));
44 const duplicates = getDuplicatePasswords(items).sort((a, b) => b.length - a.length);
45 expect(duplicates.length).toEqual(0);
48 test('should handle case when there are no logins', () => {
49 expect(getDuplicatePasswords([])).toEqual([]);
52 test.each([100, 1000, 10_000])('Performance test for %i items', (count) => {
53 const items = Array.from({ length: count }, () => createMockItem('AAA'));
55 const startTime = process.hrtime();
56 const duplicates = getDuplicatePasswords(items);
57 const endTime = process.hrtime(startTime);
58 const executionTimeMs = (endTime[0] * 1e9 + endTime[1]) / 1e6;
60 /* We are fine as long as calculation is under 0.2s */
61 expect(executionTimeMs).toBeLessThanOrEqual(200);
62 expect(duplicates).toBeDefined();