inboxd 1.0.8 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,141 @@
1
+ import { describe, it, expect } from 'vitest';
2
+
3
+ // Test the extractSenderDomain and groupEmailsBySender logic
4
+ // We duplicate the logic here to avoid importing the module which requires gmail-auth
5
+
6
+ /**
7
+ * Extract domain from From header
8
+ */
9
+ function extractSenderDomain(from) {
10
+ if (!from) return '';
11
+ const emailMatch = from.match(/<([^>]+)>/) || from.match(/([^\s]+@[^\s]+)/);
12
+ if (emailMatch) {
13
+ const email = emailMatch[1];
14
+ const domain = email.split('@')[1];
15
+ return domain ? domain.toLowerCase() : email.toLowerCase();
16
+ }
17
+ return from.toLowerCase();
18
+ }
19
+
20
+ /**
21
+ * Group emails by sender domain
22
+ */
23
+ function groupEmailsBySender(emails) {
24
+ const groups = {};
25
+
26
+ for (const email of emails) {
27
+ const domain = extractSenderDomain(email.from);
28
+ if (!groups[domain]) {
29
+ groups[domain] = {
30
+ sender: domain,
31
+ senderDisplay: email.from,
32
+ count: 0,
33
+ emails: [],
34
+ };
35
+ }
36
+ groups[domain].count++;
37
+ groups[domain].emails.push({
38
+ id: email.id,
39
+ subject: email.subject,
40
+ date: email.date,
41
+ account: email.account,
42
+ });
43
+ }
44
+
45
+ const groupArray = Object.values(groups).sort((a, b) => b.count - a.count);
46
+ return { groups: groupArray, totalCount: emails.length };
47
+ }
48
+
49
+ describe('extractSenderDomain', () => {
50
+ it('should extract domain from "Name <email>" format', () => {
51
+ expect(extractSenderDomain('LinkedIn Jobs <jobs@linkedin.com>')).toBe('linkedin.com');
52
+ });
53
+
54
+ it('should extract domain from bare email', () => {
55
+ expect(extractSenderDomain('newsletter@techcrunch.com')).toBe('techcrunch.com');
56
+ });
57
+
58
+ it('should extract domain from quoted name format', () => {
59
+ expect(extractSenderDomain('"John Doe" <john@example.com>')).toBe('example.com');
60
+ });
61
+
62
+ it('should handle malformed input gracefully', () => {
63
+ expect(extractSenderDomain('Unknown Sender')).toBe('unknown sender');
64
+ });
65
+
66
+ it('should lowercase domains', () => {
67
+ expect(extractSenderDomain('News <NEWS@EXAMPLE.COM>')).toBe('example.com');
68
+ });
69
+
70
+ it('should handle empty input', () => {
71
+ expect(extractSenderDomain('')).toBe('');
72
+ expect(extractSenderDomain(null)).toBe('');
73
+ expect(extractSenderDomain(undefined)).toBe('');
74
+ });
75
+
76
+ it('should handle email with plus addressing', () => {
77
+ expect(extractSenderDomain('Service <user+tag@domain.com>')).toBe('domain.com');
78
+ });
79
+ });
80
+
81
+ describe('groupEmailsBySender', () => {
82
+ const testEmails = [
83
+ { id: '1', from: 'LinkedIn Jobs <jobs@linkedin.com>', subject: 'New jobs', date: '2026-01-03', account: 'personal' },
84
+ { id: '2', from: 'LinkedIn <updates@linkedin.com>', subject: 'Weekly update', date: '2026-01-02', account: 'personal' },
85
+ { id: '3', from: 'GitHub <noreply@github.com>', subject: 'PR merged', date: '2026-01-03', account: 'work' },
86
+ { id: '4', from: 'newsletter@techcrunch.com', subject: 'Daily digest', date: '2026-01-03', account: 'personal' },
87
+ { id: '5', from: 'LinkedIn <messages@linkedin.com>', subject: 'New message', date: '2026-01-01', account: 'work' },
88
+ ];
89
+
90
+ it('should group emails by sender domain', () => {
91
+ const result = groupEmailsBySender(testEmails);
92
+ expect(result.groups).toHaveLength(3);
93
+ expect(result.totalCount).toBe(5);
94
+ });
95
+
96
+ it('should sort groups by count descending', () => {
97
+ const result = groupEmailsBySender(testEmails);
98
+ expect(result.groups[0].sender).toBe('linkedin.com');
99
+ expect(result.groups[0].count).toBe(3);
100
+ });
101
+
102
+ it('should preserve senderDisplay from first email', () => {
103
+ const result = groupEmailsBySender(testEmails);
104
+ const linkedInGroup = result.groups.find(g => g.sender === 'linkedin.com');
105
+ expect(linkedInGroup.senderDisplay).toBe('LinkedIn Jobs <jobs@linkedin.com>');
106
+ });
107
+
108
+ it('should include minimal email fields in group', () => {
109
+ const result = groupEmailsBySender(testEmails);
110
+ const email = result.groups[0].emails[0];
111
+ expect(email).toHaveProperty('id');
112
+ expect(email).toHaveProperty('subject');
113
+ expect(email).toHaveProperty('date');
114
+ expect(email).toHaveProperty('account');
115
+ expect(email).not.toHaveProperty('from'); // Redundant in group
116
+ expect(email).not.toHaveProperty('snippet'); // Not needed for overview
117
+ });
118
+
119
+ it('should handle empty input', () => {
120
+ const result = groupEmailsBySender([]);
121
+ expect(result.groups).toEqual([]);
122
+ expect(result.totalCount).toBe(0);
123
+ });
124
+
125
+ it('should handle single email', () => {
126
+ const result = groupEmailsBySender([testEmails[0]]);
127
+ expect(result.groups).toHaveLength(1);
128
+ expect(result.groups[0].count).toBe(1);
129
+ expect(result.totalCount).toBe(1);
130
+ });
131
+
132
+ it('should group all emails from same domain regardless of subdomain', () => {
133
+ const emails = [
134
+ { id: '1', from: 'noreply@mail.example.com', subject: 'A', date: '', account: 'test' },
135
+ { id: '2', from: 'alerts@example.com', subject: 'B', date: '', account: 'test' },
136
+ ];
137
+ const result = groupEmailsBySender(emails);
138
+ // These have different domains (mail.example.com vs example.com)
139
+ expect(result.groups).toHaveLength(2);
140
+ });
141
+ });