musora-content-services 2.1.1 → 2.2.1
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.
- package/CHANGELOG.md +9 -0
- package/docs/Content-Organization.html +2 -2
- package/docs/Gamification.html +245 -0
- package/docs/api_types.js.html +97 -0
- package/docs/config.js.html +2 -2
- package/docs/content-org_playlists-types.js.html +3 -5
- package/docs/content-org_playlists.js.html +8 -9
- package/docs/content.js.html +2 -2
- package/docs/gamification_awards.js.html +664 -0
- package/docs/gamification_gamification.js.html +76 -0
- package/docs/gamification_types.js.html +98 -0
- package/docs/global.html +1441 -153
- package/docs/index.html +2 -2
- package/docs/module-Awards.html +354 -0
- package/docs/module-Config.html +2 -2
- package/docs/module-Content-Services-V2.html +2 -2
- package/docs/module-Playlists.html +6 -6
- package/docs/module-Railcontent-Services.html +33 -194
- package/docs/module-Sanity-Services.html +885 -90
- package/docs/module-Session-Management.html +2 -2
- package/docs/module-User-Permissions.html +2 -2
- package/docs/railcontent.js.html +13 -25
- package/docs/sanity.js.html +76 -5
- package/docs/user_permissions.js.html +3 -3
- package/docs/user_sessions.js.html +4 -4
- package/docs/user_types.js.html +2 -2
- package/jsdoc.json +4 -2
- package/package.json +1 -1
- package/src/contentTypeConfig.js +1 -0
- package/src/index.d.ts +40 -3
- package/src/index.js +40 -2
- package/src/services/api/types.js +25 -0
- package/src/services/dataContext.js +15 -2
- package/src/services/gamification/awards.js +592 -0
- package/src/services/gamification/gamification.js +4 -0
- package/src/services/gamification/types.js +26 -0
- package/src/services/railcontent.js +60 -0
- package/src/services/sanity.js +22 -21
- package/src/services/userActivity.js +377 -23
- package/test/contentLikes.test.js +2 -0
- package/test/mockData/mockData_fetchByRailContentIds_one_content.json +35 -0
- package/test/userActivity.test.js +118 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"permission_id": [
|
|
4
|
+
78,
|
|
5
|
+
89,
|
|
6
|
+
91,
|
|
7
|
+
92,
|
|
8
|
+
88,
|
|
9
|
+
90
|
|
10
|
+
],
|
|
11
|
+
"thumbnail": "https://cdn.sanity.io/images/4032r8py/staging/5f15b20b428c06263fd39599fc310ab00eb05fee-1920x1080.jpg",
|
|
12
|
+
"difficulty_string": "Beginner",
|
|
13
|
+
"url": "/drumeo/quick-tips/how-to-play-drums/415183",
|
|
14
|
+
"lesson_count": null,
|
|
15
|
+
"id": 415183,
|
|
16
|
+
"image": "https://cdn.sanity.io/images/4032r8py/staging/5f15b20b428c06263fd39599fc310ab00eb05fee-1920x1080.jpg",
|
|
17
|
+
"web_url_path": "/drumeo/quick-tips/how-to-play-drums/415183",
|
|
18
|
+
"type": "quick-tips",
|
|
19
|
+
"brand": "drumeo",
|
|
20
|
+
"genre": null,
|
|
21
|
+
"status": "published",
|
|
22
|
+
"xp": 100,
|
|
23
|
+
"railcontent_id": 415183,
|
|
24
|
+
"artist": null,
|
|
25
|
+
"progress_percent": null,
|
|
26
|
+
"child_count": null,
|
|
27
|
+
"sanity_id": "quick-tips_415183",
|
|
28
|
+
"artist_name": "Brandon Toews",
|
|
29
|
+
"title": "How To Play Drums",
|
|
30
|
+
"difficulty": 3,
|
|
31
|
+
"published_on": "2024-12-13T12:00:00.000000Z",
|
|
32
|
+
"length_in_seconds": 576,
|
|
33
|
+
"slug": "how-to-play-drums"
|
|
34
|
+
}
|
|
35
|
+
]
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { initializeTestService } from './initializeTests.js'
|
|
2
|
+
import {getUserMonthlyStats, getUserWeeklyStats, userActivityContext, recordUserPractice, getUserPractices} from '../src/services/userActivity.js'
|
|
3
|
+
import { logUserPractice } from '../src/services/railcontent.js'
|
|
4
|
+
import {fetchByRailContentIds} from "../src";
|
|
5
|
+
import mockData_fetchByRailContentIds_one_content from './mockData/mockData_fetchByRailContentIds_one_content.json';
|
|
6
|
+
|
|
7
|
+
global.fetch = jest.fn()
|
|
8
|
+
let mock = null
|
|
9
|
+
const testVersion = 1
|
|
10
|
+
const DEBUG = true
|
|
11
|
+
|
|
12
|
+
jest.mock('../src/services/railcontent', () => ({
|
|
13
|
+
...jest.requireActual('../src/services/railcontent'),
|
|
14
|
+
logUserPractice: jest.fn(() => Promise.resolve()),
|
|
15
|
+
fetchUserPermissionsData: jest.fn(() => ({ permissions: [78, 91, 92], isAdmin: false }))
|
|
16
|
+
}))
|
|
17
|
+
|
|
18
|
+
jest.mock('../src/services/sanity', () => ({
|
|
19
|
+
...jest.requireActual('../src/services/sanity'),
|
|
20
|
+
fetchByRailContentIds: jest.fn(() => Promise.resolve(mockData_fetchByRailContentIds_one_content)),
|
|
21
|
+
}))
|
|
22
|
+
describe('User Activity API Tests', function () {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
initializeTestService()
|
|
25
|
+
mock = jest.spyOn(userActivityContext, 'fetchData')
|
|
26
|
+
var json = JSON.parse(
|
|
27
|
+
`{
|
|
28
|
+
"version": ${testVersion},
|
|
29
|
+
"config": { "key": 1, "enabled": 1, "checkInterval": 1, "refreshInterval": 2 },
|
|
30
|
+
"data": {
|
|
31
|
+
"practices": {
|
|
32
|
+
"2025-02-10": [{ "duration_seconds": 190 }],
|
|
33
|
+
"2025-02-11": [{ "duration_seconds": 340 }],
|
|
34
|
+
"2025-02-19": [{ "duration_seconds": 340 }],
|
|
35
|
+
"2025-03-01": [{ "duration_seconds": 360 }],
|
|
36
|
+
"2025-03-03": [{ "duration_seconds": 360 }],
|
|
37
|
+
"2025-03-05": [{ "duration_seconds": 100 }],
|
|
38
|
+
"2025-03-11": [{ "duration_seconds": 190 }],
|
|
39
|
+
"2025-03-14": [{ "duration_seconds": 456 }],
|
|
40
|
+
"2025-03-15": [{ "duration_seconds": 124 }],
|
|
41
|
+
"2025-03-16": [{ "duration_seconds": 452 }, { "duration_seconds": 456 }],
|
|
42
|
+
"2025-03-17": [{ "duration_seconds": 122 }]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}`
|
|
46
|
+
)
|
|
47
|
+
mock.mockImplementation(() => json)
|
|
48
|
+
userActivityContext.ensureLocalContextLoaded()
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('fetches user practices successfully', async () => {
|
|
52
|
+
userActivityContext.clearCache()
|
|
53
|
+
const practices = await getUserMonthlyStats()
|
|
54
|
+
consoleLog(practices)
|
|
55
|
+
// Assert that dailyActiveStats contains correct data
|
|
56
|
+
const dailyStats = practices.dailyActiveStats
|
|
57
|
+
const currentDate = new Date()
|
|
58
|
+
const currentDateString = currentDate.toISOString().split('T')[0]
|
|
59
|
+
expect(dailyStats).toHaveLength(42)
|
|
60
|
+
|
|
61
|
+
// Verify current day's stats (e.g., March 17, 2025)
|
|
62
|
+
const current = dailyStats.find(stat => stat.label === currentDateString)
|
|
63
|
+
expect(current).toBeTruthy()
|
|
64
|
+
expect(current.isActive).toBe(true)
|
|
65
|
+
expect(current.type).toBe('active')
|
|
66
|
+
expect(current.inStreak).toBe(false)
|
|
67
|
+
|
|
68
|
+
// Ensure that mock was called as expected
|
|
69
|
+
expect(mock).toHaveBeenCalledTimes(1)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
test('fetches user practices from past', async () => {
|
|
73
|
+
userActivityContext.clearCache()
|
|
74
|
+
const practices = await getUserMonthlyStats( 2025, 1)
|
|
75
|
+
consoleLog(practices)
|
|
76
|
+
|
|
77
|
+
// Assert that dailyActiveStats contains correct data
|
|
78
|
+
const dailyStats = practices.dailyActiveStats
|
|
79
|
+
const feb10 = dailyStats.find(stat => stat.label === '2025-02-10')
|
|
80
|
+
expect(feb10.inStreak).toBe(true)
|
|
81
|
+
expect(feb10.type).toBe('tracked')
|
|
82
|
+
expect(feb10.isActive).toBe(false)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('fetches user practices for current week', async () => {
|
|
86
|
+
userActivityContext.clearCache()
|
|
87
|
+
const practices = await getUserWeeklyStats( )
|
|
88
|
+
consoleLog(practices)
|
|
89
|
+
|
|
90
|
+
const dailyStats = practices.dailyActiveStats
|
|
91
|
+
const monday = dailyStats.find(stat => stat.label === 'M')
|
|
92
|
+
expect(monday).toBeDefined
|
|
93
|
+
const tuesday = dailyStats.find(stat => stat.label === 'T')
|
|
94
|
+
expect(tuesday).toBeDefined
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
test('should add a new practice entry and call logUserPractice', async () => {
|
|
98
|
+
userActivityContext.clearCache()
|
|
99
|
+
const mockPractice = {
|
|
100
|
+
duration_seconds: 300,
|
|
101
|
+
content_id: 415183
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
jest.spyOn(userActivityContext, 'update').mockImplementation(async (callback) => {
|
|
105
|
+
await callback(userActivityContext)
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
await recordUserPractice(mockPractice)
|
|
109
|
+
|
|
110
|
+
expect(userActivityContext.update).toHaveBeenCalledTimes(1)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
function consoleLog(message, object=null, debug=false) {
|
|
114
|
+
if (debug || DEBUG) {
|
|
115
|
+
console.log(message, object);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
})
|