musora-content-services 2.7.1 → 2.7.3

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.
Files changed (53) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/docs/ContentOrganization.html +2 -2
  3. package/docs/Gamification.html +2 -2
  4. package/docs/UserManagementSystem.html +2 -2
  5. package/docs/api_types.js.html +2 -2
  6. package/docs/config.js.html +2 -2
  7. package/docs/content-org_content-org.js.html +2 -2
  8. package/docs/content-org_playlists-types.js.html +3 -5
  9. package/docs/content-org_playlists.js.html +23 -9
  10. package/docs/content.js.html +9 -2
  11. package/docs/gamification_awards.js.html +2 -2
  12. package/docs/gamification_gamification.js.html +2 -2
  13. package/docs/gamification_types.js.html +2 -2
  14. package/docs/global.html +5 -53
  15. package/docs/index.html +2 -2
  16. package/docs/module-Awards.html +2 -2
  17. package/docs/module-Config.html +2 -2
  18. package/docs/module-Content-Services-V2.html +8 -8
  19. package/docs/module-Interests.html +2 -2
  20. package/docs/module-Permissions.html +2 -2
  21. package/docs/module-Playlists.html +21 -20
  22. package/docs/module-Railcontent-Services.html +2 -2
  23. package/docs/module-Sanity-Services.html +30 -30
  24. package/docs/module-Sessions.html +2 -2
  25. package/docs/module-User-Activity.html +737 -58
  26. package/docs/module-UserManagement.html +2 -2
  27. package/docs/module-UserProfile.html +2 -2
  28. package/docs/railcontent.js.html +2 -2
  29. package/docs/sanity.js.html +24 -6
  30. package/docs/userActivity.js.html +360 -12
  31. package/docs/user_interests.js.html +2 -2
  32. package/docs/user_management.js.html +2 -2
  33. package/docs/user_permissions.js.html +2 -2
  34. package/docs/user_profile.js.html +4 -4
  35. package/docs/user_sessions.js.html +2 -2
  36. package/docs/user_types.js.html +2 -2
  37. package/docs/user_user-management-system.js.html +2 -2
  38. package/link_mcs.sh +8 -6
  39. package/package.json +1 -1
  40. package/src/contentMetaData.js +2 -1
  41. package/src/contentTypeConfig.js +19 -3
  42. package/src/index.d.ts +10 -2
  43. package/src/index.js +10 -2
  44. package/src/services/content.js +7 -0
  45. package/src/services/contentProgress.js +45 -15
  46. package/src/services/dateUtils.js +0 -0
  47. package/src/services/sanity.js +22 -4
  48. package/src/services/userActivity.js +348 -10
  49. package/test/mockData/mockData_progress_content.json +182 -0
  50. package/test/mockData/mockData_sanity_progress_content.json +1451 -0
  51. package/test/progressRows.test.js +215 -0
  52. package/test/sanityQueryService.test.js +0 -0
  53. package/test/userActivity.test.js +4 -4
@@ -0,0 +1,215 @@
1
+ import { getProgressRows } from '../src/services/userActivity';
2
+ import { fetchUserPlaylists } from '../src/services/content-org/playlists';
3
+ import { fetchByRailContentIds } from '../src/services/sanity';
4
+ import {getAllStartedOrCompleted, getProgressStateByIds} from '../src/services/contentProgress';
5
+ import mockData_progress_content from './mockData/mockData_progress_content.json';
6
+ import mockData_sanity_progress_content from "./mockData/mockData_sanity_progress_content.json";
7
+
8
+ jest.mock('../src/services/content-org/playlists');
9
+ jest.mock('../src/services/sanity');
10
+ jest.mock('../src/services/contentProgress');
11
+
12
+ describe('getProgressRows', () => {
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ });
16
+
17
+ it('returns progress rows successfully', async () => {
18
+ const mockPlaylists = [
19
+ {
20
+ id: 1,
21
+ name: 'Playlist 1',
22
+ last_progress: '2025-05-19 10:00:00',
23
+ last_engaged_on: 101,
24
+ items: [{ content_id: 201 }],
25
+ duration_formated: '10m',
26
+ total_items: 1,
27
+ likes: 100,
28
+ user: { display_name: 'User1' },
29
+ brand: 'brand1',
30
+ first_items_thumbnail_url: 'url1',
31
+ },
32
+ ];
33
+
34
+ const mockPlaylistContents = [
35
+ {
36
+ id: 201,
37
+ railcontent_id: 201,
38
+ parent_content_data: [],
39
+ type: 'lesson',
40
+ thumbnail: 'thumb1',
41
+ title: 'Lesson 1',
42
+ difficulty_string: 'Easy',
43
+ artist_name: 'Artist 1',
44
+ lesson_count: 1,
45
+ completed_children: 0,
46
+ brand: 'brand1',
47
+ slug: 'lesson-1',
48
+ },
49
+ ];
50
+
51
+ const mockProgressContents = {
52
+ '201': {
53
+ status: 'in_progress',
54
+ progress: 50,
55
+ last_update: 1621510400, // Unix timestamp
56
+ },
57
+ };
58
+
59
+ const mockProgressState = {
60
+ '201': 'in_progress',
61
+ };
62
+
63
+ fetchUserPlaylists.mockResolvedValue({ data: mockPlaylists });
64
+ fetchByRailContentIds.mockResolvedValue(mockPlaylistContents);
65
+ getAllStartedOrCompleted.mockResolvedValue(mockProgressContents);
66
+ getProgressStateByIds.mockResolvedValue(mockProgressState);
67
+
68
+ const result = await getProgressRows({ brand: 'brand1', limit: 8 });
69
+
70
+ expect(result).toHaveProperty('type', 'progress_rows');
71
+ expect(result).toHaveProperty('data');
72
+ expect(Array.isArray(result.data)).toBe(true);
73
+ expect(result.data.length).toBe(2);
74
+ expect(result.data[0]).toHaveProperty('id', 'progressType', 'header', 'body', 'cta');
75
+ expect(result.data[0].progressType).toBe('playlist');
76
+ expect(result.data[0].body).toHaveProperty('first_items_thumbnail_url', 'title', 'subtitle');
77
+ expect(result.data[0].cta).toHaveProperty('text');
78
+ expect(result.data[0].cta).toHaveProperty('action');
79
+
80
+ });
81
+
82
+ it('handles no progress', async () => {
83
+ fetchUserPlaylists.mockResolvedValue({ data: [] });
84
+ getAllStartedOrCompleted.mockResolvedValue({});
85
+ fetchByRailContentIds.mockResolvedValue([]);
86
+ getProgressStateByIds.mockResolvedValue({});
87
+
88
+ const result = await getProgressRows({ brand: 'brand1', limit: 8 });
89
+ expect(result).toHaveProperty('type', 'progress_rows');
90
+ expect(result.data).toEqual([]);
91
+ });
92
+
93
+ it('check progress rows logic', async () => {
94
+ fetchUserPlaylists.mockResolvedValue({ data: [] });
95
+ fetchByRailContentIds
96
+ .mockImplementationOnce(() => Promise.resolve([])) // playlists
97
+ .mockImplementationOnce(() => Promise.resolve(mockData_sanity_progress_content) // content progress
98
+ );
99
+
100
+ getAllStartedOrCompleted.mockResolvedValue(mockData_progress_content);
101
+ getProgressStateByIds
102
+ .mockImplementationOnce(() => Promise.resolve({
103
+ "287853": "completed",
104
+ "287854": "completed",
105
+ "287855": "completed",
106
+ "287858": "completed",
107
+ "287859": ""
108
+ })) // course lessons
109
+ .mockImplementationOnce(() => Promise.resolve({
110
+ "257243": "started",
111
+ "257245": "started",
112
+ "257246": "",
113
+ "257247": "",
114
+ "257248": "",
115
+ "257249": "completed",
116
+ "257250": "completed",
117
+ "257251": "",
118
+ "257252": "",
119
+ "257253": "",
120
+ "257254": "",
121
+ "257255": "",
122
+ "257256": "",
123
+ "257257": "",
124
+ "257258": "",
125
+ "257259": "",
126
+ "257260": "",
127
+ "259235": "",
128
+ "259236": ""
129
+ })) //pack
130
+ .mockImplementationOnce(() => Promise.resolve({
131
+ "410479": "",
132
+ "410480": "completed",
133
+ "410481": "completed",
134
+ "410482": "",
135
+ "410483": "",
136
+ "410484": "",
137
+ "410485": "",
138
+ "410486": "",
139
+ "410487": ""
140
+ }) // challenge
141
+ );
142
+
143
+
144
+ const result = await getProgressRows({ brand: 'brand1', limit: 8 });
145
+ console.log('result', result);
146
+ expect(fetchByRailContentIds).toHaveBeenCalledTimes(2);
147
+
148
+ expect(result).toHaveProperty('type', 'progress_rows');
149
+ expect(result.data.length).toBeGreaterThan(0);
150
+ expect(result.data.length).toBeLessThanOrEqual(8);
151
+ //course 280498
152
+ const lesson1Progress = result.data.find(row => row.id === 280498);
153
+ expect(lesson1Progress).toBeDefined();
154
+ expect(lesson1Progress.cta).toHaveProperty('text');
155
+ expect(lesson1Progress.cta.text.toLowerCase()).toContain('continue');
156
+ expect(lesson1Progress.cta.action).toHaveProperty('type');
157
+ expect(lesson1Progress.cta.action.type).toBe('course');
158
+ expect(lesson1Progress.cta.action.id).toBe(280498);
159
+ expect(lesson1Progress.cta.action.child).toBeDefined();
160
+ expect(lesson1Progress.cta.action.child.type).toBe('course-part');
161
+ expect(lesson1Progress.cta.action.child.id).toBe(287859);
162
+ //pack 257242
163
+ const lesson2Progress = result.data.find(row => row.id === 257242);
164
+ expect(lesson2Progress).toBeDefined();
165
+ expect(lesson2Progress.cta).toHaveProperty('text');
166
+ expect(lesson2Progress.cta.text.toLowerCase()).toContain('continue');
167
+ console.log(lesson2Progress.cta.action)
168
+ expect(lesson2Progress.cta.action).toHaveProperty('type');
169
+ expect(lesson2Progress.cta.action.type).toBe('pack');
170
+ expect(lesson2Progress.cta.action.id).toBe(257242);
171
+ expect(lesson2Progress.cta.action.child).toBeDefined();
172
+ expect(lesson2Progress.cta.action.child.type).toBe('pack-bundle');
173
+ expect(lesson2Progress.cta.action.child.child).toBeDefined();
174
+ expect(lesson2Progress.cta.action.child.child.type).toBe('pack-bundle-lesson');
175
+ expect(lesson2Progress.cta.action.child.child.id).toBe(257251);
176
+
177
+ //challenge 410478
178
+ const lesson3Progress = result.data.find(row => row.id === 410478);
179
+ expect(lesson3Progress).toBeDefined();
180
+ expect(lesson3Progress.cta).toHaveProperty('text');
181
+ expect(lesson3Progress.cta.text.toLowerCase()).toContain('continue');
182
+ expect(lesson3Progress.cta.action).toHaveProperty('type');
183
+ expect(lesson3Progress.cta.action.type).toBe('challenge');
184
+ expect(lesson3Progress.cta.action.id).toBe(410478);
185
+ expect(lesson3Progress.cta.action.child).toBeDefined();
186
+ expect(lesson3Progress.cta.action.child.type).toBe('challenge-part');
187
+ expect(lesson3Progress.cta.action.child.id).toBe(410479);
188
+
189
+ //completed play-along 316772
190
+ const lesson4Progress = result.data.find(row => row.id === 316772);
191
+ expect(lesson4Progress).toBeDefined();
192
+ expect(lesson4Progress.cta).toHaveProperty('text');
193
+ expect(lesson4Progress.cta.text).toContain('Replay Song');
194
+ expect(lesson4Progress.cta.action).toHaveProperty('type');
195
+ expect(lesson4Progress.cta.action.type).toBe('play-along');
196
+ expect(lesson4Progress.cta.action.id).toBe(316772);
197
+ expect(lesson4Progress.body.progressPercent).toBe(100);
198
+
199
+ //in progress quick-tips 325826
200
+ const lesson5Progress = result.data.find(row => row.id === 325826);
201
+ console.log(lesson5Progress)
202
+ expect(lesson5Progress).toBeDefined();
203
+ expect(lesson5Progress.cta).toHaveProperty('text');
204
+ expect(lesson5Progress.cta.text).toContain('Continue');
205
+ expect(lesson5Progress.cta.action).toHaveProperty('type');
206
+ expect(lesson5Progress.cta.action.type).toBe('quick-tips');
207
+ expect(lesson5Progress.cta.action.id).toBe(325826);
208
+ expect(lesson5Progress.body.progressPercent).toBeLessThan(100);
209
+ });
210
+
211
+
212
+
213
+ });
214
+
215
+
File without changes
@@ -69,15 +69,15 @@ describe('User Activity API Tests', function () {
69
69
 
70
70
  test('fetches user practices from past', async () => {
71
71
  userActivityContext.clearCache()
72
- const practices = await getUserMonthlyStats( 2025, 1)
73
- consoleLog(practices)
72
+ const practices = await getUserMonthlyStats( {year:2025, month: 1} )
73
+ consoleLog(practices.data.dailyActiveStats)
74
74
 
75
75
  // Assert that dailyActiveStats contains correct data
76
76
  const dailyStats = practices.data.dailyActiveStats
77
77
  const feb10 = dailyStats.find(stat => stat.label === '2025-02-10')
78
78
  expect(feb10.inStreak).toBe(true)
79
- expect(feb10.type).toBe('tracked')
80
- expect(feb10.isActive).toBe(false)
79
+ expect(feb10.type).toBe('tracked')
80
+ expect(feb10.isActive).toBe(false)
81
81
  })
82
82
 
83
83
  test('fetches user practices for current week', async () => {