abmp-npm 2.0.55 → 2.0.57
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,129 @@
|
|
|
1
|
+
const { ensureUniqueUrlsInBatch } = require('../daily-pull/bulk-process-methods');
|
|
2
|
+
const membersDataMethods = require('../members-data-methods');
|
|
3
|
+
jest.mock('../members-data-methods');
|
|
4
|
+
|
|
5
|
+
describe('ensureUniqueUrlsInBatch', () => {
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
membersDataMethods.getMemberBySlug.mockReset();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
describe('case-insensitivity (regression: avoid creating John-12 AND john-12)', () => {
|
|
11
|
+
test('merges John-11 and john-11 into one group and assigns unique sequential URLs', async () => {
|
|
12
|
+
membersDataMethods.getMemberBySlug.mockResolvedValue({ url: 'John-11', memberId: 1 });
|
|
13
|
+
|
|
14
|
+
const members = [
|
|
15
|
+
{ memberId: 101, url: 'John-11', fullName: 'John Doe' },
|
|
16
|
+
{ memberId: 102, url: 'john-11', fullName: 'John Doe' },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const result = await ensureUniqueUrlsInBatch(members);
|
|
20
|
+
|
|
21
|
+
const urls = result.map(m => m.url);
|
|
22
|
+
|
|
23
|
+
expect(urls).toHaveLength(2);
|
|
24
|
+
expect(new Set(urls).size).toBe(2);
|
|
25
|
+
expect(urls.some(u => u.endsWith('-12'))).toBe(true);
|
|
26
|
+
expect(urls.some(u => u.endsWith('-13'))).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('does NOT create both John-12 and john-12 (case duplicate)', async () => {
|
|
30
|
+
membersDataMethods.getMemberBySlug.mockResolvedValue({ url: 'John-11', memberId: 1 });
|
|
31
|
+
|
|
32
|
+
const members = [
|
|
33
|
+
{ memberId: 101, url: 'John-11' },
|
|
34
|
+
{ memberId: 102, url: 'john-11' },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const result = await ensureUniqueUrlsInBatch(members);
|
|
38
|
+
const urls = result.map(m => m.url);
|
|
39
|
+
|
|
40
|
+
const hasJohn12 = urls.some(u => u === 'John-12');
|
|
41
|
+
const hasjohn12 = urls.some(u => u === 'john-12');
|
|
42
|
+
expect(hasJohn12 && hasjohn12).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('handles JOHN, John, john variants - all merge into single group', async () => {
|
|
46
|
+
membersDataMethods.getMemberBySlug.mockResolvedValue(null);
|
|
47
|
+
|
|
48
|
+
const members = [
|
|
49
|
+
{ memberId: 101, url: 'JOHN-5' },
|
|
50
|
+
{ memberId: 102, url: 'John-5' },
|
|
51
|
+
{ memberId: 103, url: 'john-5' },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const result = await ensureUniqueUrlsInBatch(members);
|
|
55
|
+
const urls = result.map(m => m.url);
|
|
56
|
+
|
|
57
|
+
expect(urls).toHaveLength(3);
|
|
58
|
+
expect(new Set(urls).size).toBe(3);
|
|
59
|
+
const bases = urls.map(u => u.replace(/-\d+$/, '').toLowerCase());
|
|
60
|
+
expect(new Set(bases).size).toBe(1);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('multiple members with same base URL', () => {
|
|
65
|
+
test('assigns sequential counters starting after batch max and DB max', async () => {
|
|
66
|
+
membersDataMethods.getMemberBySlug.mockResolvedValue({
|
|
67
|
+
url: 'firstNameLastName-11',
|
|
68
|
+
memberId: 1,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const members = [
|
|
72
|
+
{ memberId: 201, url: 'firstNameLastName-11' },
|
|
73
|
+
{ memberId: 202, url: 'firstNameLastName-11' },
|
|
74
|
+
{ memberId: 203, url: 'firstNameLastName-11' },
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
const result = await ensureUniqueUrlsInBatch(members);
|
|
78
|
+
const urls = result.map(m => m.url).sort();
|
|
79
|
+
|
|
80
|
+
expect(urls).toEqual([
|
|
81
|
+
'firstNameLastName-12',
|
|
82
|
+
'firstNameLastName-13',
|
|
83
|
+
'firstNameLastName-14',
|
|
84
|
+
]);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('uses batch max when DB has no matches', async () => {
|
|
88
|
+
membersDataMethods.getMemberBySlug.mockResolvedValue(null);
|
|
89
|
+
|
|
90
|
+
const members = [
|
|
91
|
+
{ memberId: 301, url: 'testUser-5' },
|
|
92
|
+
{ memberId: 302, url: 'testUser-5' },
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const result = await ensureUniqueUrlsInBatch(members);
|
|
96
|
+
const urls = result.map(m => m.url).sort();
|
|
97
|
+
|
|
98
|
+
expect(urls).toEqual(['testUser-6', 'testUser-7']);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('edge cases', () => {
|
|
103
|
+
test('returns empty array unchanged', async () => {
|
|
104
|
+
const result = await ensureUniqueUrlsInBatch([]);
|
|
105
|
+
expect(result).toEqual([]);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('returns non-array unchanged', async () => {
|
|
109
|
+
const input = { not: 'array' };
|
|
110
|
+
const result = await ensureUniqueUrlsInBatch(input);
|
|
111
|
+
expect(result).toBe(input);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('skips members without url', async () => {
|
|
115
|
+
membersDataMethods.getMemberBySlug.mockResolvedValue(null);
|
|
116
|
+
|
|
117
|
+
const members = [
|
|
118
|
+
{ memberId: 401, url: 'validUrl' },
|
|
119
|
+
{ memberId: 402, url: null },
|
|
120
|
+
{ memberId: 403 },
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
const result = await ensureUniqueUrlsInBatch(members);
|
|
124
|
+
expect(result).toHaveLength(3);
|
|
125
|
+
expect(result[0].url).toBe('validUrl');
|
|
126
|
+
expect(result[1].url).toBeNull();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -28,14 +28,13 @@ async function ensureUniqueUrlsInBatch(memberDataList) {
|
|
|
28
28
|
const baseUrl = extractBaseUrl(member.url);
|
|
29
29
|
const groupKey = baseUrl.toLowerCase();
|
|
30
30
|
if (!urlGroups.has(groupKey)) {
|
|
31
|
-
urlGroups.set(groupKey, []);
|
|
31
|
+
urlGroups.set(groupKey, { members: [], baseUrl });
|
|
32
32
|
}
|
|
33
|
-
urlGroups.get(groupKey).push(member);
|
|
33
|
+
urlGroups.get(groupKey).members.push(member);
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
// For each group, check database and assign unique URLs sequentially
|
|
37
|
-
for (const [
|
|
38
|
-
const baseUrl = groupKey; // lowercase for consistent slug assignment
|
|
37
|
+
for (const [, { members, baseUrl }] of urlGroups.entries()) {
|
|
39
38
|
if (members.length <= 1) {
|
|
40
39
|
// Single member - still check DB to ensure it doesn't conflict with other pages
|
|
41
40
|
const member = members[0];
|