musora-content-services 2.158.2 → 2.159.0

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 (54) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/.github/workflows/automated-testing.yml +21 -1
  3. package/CHANGELOG.md +15 -0
  4. package/README.md +21 -2
  5. package/jest.config.js +1 -4
  6. package/jest.integration.config.js +6 -0
  7. package/jest.live.config.js +1 -5
  8. package/package.json +5 -2
  9. package/src/contentTypeConfig.js +8 -5
  10. package/src/index.d.ts +2 -6
  11. package/src/index.js +2 -6
  12. package/src/services/content-org/learning-paths.ts +44 -39
  13. package/src/services/contentAggregator.js +1 -1
  14. package/src/services/contentProgress.js +216 -207
  15. package/src/services/offline/progress.ts +107 -27
  16. package/src/services/sanity.js +55 -64
  17. package/src/services/sync/models/ContentProgress.ts +50 -34
  18. package/src/services/sync/repositories/content-progress.ts +105 -92
  19. package/test/{unit → integration}/awards/award-exclusion-handling.test.ts +2 -2
  20. package/test/integration/content-progress/__mocks__/mocks.ts +104 -0
  21. package/test/integration/content-progress/contentProgress.test.ts +335 -0
  22. package/test/integration/content-progress/e2eOfflineProgress.test.ts +352 -0
  23. package/test/integration/content-progress/e2eProgress.test.ts +612 -0
  24. package/test/integration/content-progress/getters.test.ts +334 -0
  25. package/test/integration/content-progress/helpers.test.ts +263 -0
  26. package/test/integration/content-progress/offlineContentProgress.test.ts +226 -0
  27. package/test/integration/forums.test.ts +209 -0
  28. package/test/integration/initializeTestDB.ts +80 -0
  29. package/test/{unit → integration}/sync/fetch.test.ts +1 -1
  30. package/test/{unit → integration}/sync/repositories/content-likes.test.ts +1 -1
  31. package/test/{unit → integration}/sync/repositories/practices.test.ts +1 -1
  32. package/test/{unit → integration}/sync/repositories/progress.test.ts +1 -1
  33. package/test/{unit → integration}/sync/repositories/user-award-progress.test.ts +1 -1
  34. package/test/{unit → integration}/sync/store/cross-user-protection.test.ts +2 -2
  35. package/test/{unit → integration}/sync/store/store-idb.test.ts +2 -2
  36. package/test/{unit → integration}/sync/store/store.test.ts +2 -2
  37. package/test/unit/content-progress/bubbleTrickle.test.ts +322 -0
  38. package/test/unit/content-progress/helpers.test.ts +329 -0
  39. package/test/unit/content-progress/navigateTo.test.ts +381 -0
  40. package/test/unit/contentMetaData.test.ts +58 -0
  41. package/tools/generate-index.cjs +6 -3
  42. package/test/SKIPPED_TESTS.md +0 -151
  43. package/test/integration/content.test.js +0 -107
  44. package/test/integration/contentProgress.test.js +0 -73
  45. package/test/integration/forum.test.js +0 -16
  46. package/test/integration/sanityQueryService.test.js +0 -681
  47. package/test/unit/contentProgress.test.ts +0 -81
  48. /package/test/{unit → integration}/awards/internal/image-utils.test.ts +0 -0
  49. /package/test/{unit → integration}/infrastructure/FetchRequestExecutor.test.ts +0 -0
  50. /package/test/{unit → integration}/notifications.test.ts +0 -0
  51. /package/test/{unit → integration}/sync/adapters/idb-errors.test.ts +0 -0
  52. /package/test/{unit → integration}/sync/adapters/sqlite-errors.test.ts +0 -0
  53. /package/test/{unit → integration}/sync/repositories/user-award-progress.static.test.ts +0 -0
  54. /package/test/{unit → integration}/userActivity.test.ts +0 -0
@@ -1,681 +0,0 @@
1
- import { getFieldsForContentType, SONG_TYPES } from '../../src/contentTypeConfig.js'
2
-
3
- const railContentModule = require('../../src/services/railcontent.js')
4
-
5
- jest.mock('../../src/services/contentProgress.js', () => ({
6
- ...jest.requireActual('../../src/services/contentProgress'),
7
- getAllStarted: jest.fn().mockResolvedValue([]),
8
- getAllCompleted: jest.fn().mockResolvedValue([]),
9
- getAllStartedOrCompleted: jest.fn().mockResolvedValue([]),
10
- }))
11
-
12
- const contentProgressModule = require('../../src/services/contentProgress.js')
13
-
14
- import { log } from '../log.js'
15
- import { initializeTestService } from '../initializeTests.js'
16
- import { getRecommendedForYou, globalConfig, recommendations } from '../../src/index.d.ts'
17
- import { fetchLessonsFeaturingThisContent } from '../../src/services/sanity.js'
18
-
19
- const {
20
- fetchSongById,
21
- fetchReturning,
22
- fetchLeaving,
23
- fetchComingSoon,
24
- fetchSongArtistCount,
25
- fetchNewReleases,
26
- fetchUpcomingEvents,
27
- fetchByRailContentId,
28
- fetchByRailContentIds,
29
- fetchAll,
30
- fetchAllFilterOptions,
31
- fetchRelatedLessons,
32
- fetchAllPacks,
33
- fetchPackAll,
34
- fetchLessonContent,
35
- fetchLiveEvent,
36
- fetchByReference,
37
- fetchScheduledReleases,
38
- getSortOrder,
39
- fetchShowsData,
40
- fetchMetadata,
41
- fetchHierarchy,
42
- fetchTopLevelParentId,
43
- fetchOtherSongVersions,
44
- fetchCommentModContentData,
45
- fetchSanity,
46
- } = require('../../src/services/sanity.js')
47
-
48
- const { FilterBuilder } = require('../../src/filterBuilder.js')
49
-
50
- const { processMetadata } = require('../../src/contentMetaData.js')
51
-
52
- jest.mock('../../src/services/permissions/index.ts', () => ({
53
- ...jest.requireActual('../../src/services/permissions/index.ts'),
54
- getPermissionsAdapter: jest.fn().mockReturnValue({
55
- fetchUserPermissions: jest.fn().mockResolvedValue({ permissions: [108, 91, 92], isAdmin: false }),
56
- isAdmin: jest.fn().mockReturnValue(false),
57
- generatePermissionsFilter: jest.fn().mockReturnValue(
58
- `(!defined(permission_v2) || array::intersects(permission_v2, [108,91,92]))`
59
- ),
60
- }),
61
- }))
62
-
63
- describe('Sanity Queries', function() {
64
- beforeEach(() => {
65
- initializeTestService()
66
- })
67
-
68
- test.skip('fetchSongById', async () => {
69
- const id = 380094
70
- const response = await fetchSongById(id)
71
- expect(response.id).toBe(id)
72
- })
73
-
74
- test.skip('fetchReturning', async () => {
75
- const brand = 'guitareo'
76
- const page = 1
77
- const response = await fetchReturning(brand, { pageNumber: 1 })
78
- expect(response).toBeDefined()
79
- })
80
-
81
- test.skip('fetchLeaving', async () => {
82
- const brand = 'guitareo'
83
- const response = await fetchLeaving(brand, { pageNumber: 1 })
84
- expect(response).toBeDefined()
85
- })
86
-
87
- test.skip('fetchComingSoon', async () => {
88
- const brand = 'guitareo'
89
- const response = await fetchComingSoon(brand, { pageNumber: 2, contentPerPage: 20 })
90
- expect(response).toBeDefined()
91
- })
92
-
93
- test.skip('fetchSongArtistCount', async () => {
94
- const response = await fetchSongArtistCount('drumeo')
95
- log(response)
96
- expect(response).toBeGreaterThan(700)
97
- }, 10000)
98
-
99
- test.skip('fetchSanity-WithPostProcess', async () => {
100
- const id = 380094
101
- const query = `*[railcontent_id == ${id}]{
102
- ${getFieldsForContentType('song')}
103
- }`
104
- const newSlug = 'keysmash1'
105
- const newField = 1
106
- const postProcess = (result) => {
107
- result['new_field'] = newField
108
- result['slug'] = newSlug
109
- return result
110
- }
111
- const response = await fetchSanity(query, false, { customPostProcess: postProcess })
112
- log(response)
113
- expect(response.id).toBe(id)
114
- expect(response.new_field).toBe(newField)
115
- expect(response.slug).toBe(newSlug)
116
- })
117
-
118
- test.skip('fetchSanityPostProcess', async () => {
119
- const id = 380094
120
- const response = await fetchByRailContentId(id, 'song')
121
- expect(response.id).toBe(id)
122
- })
123
-
124
- test.skip('fetchByRailContentIds', async () => {
125
- const id = 380094
126
- const id2 = 402204
127
- const response = await fetchByRailContentIds([id, id2])
128
- const returnedIds = response.map((x) => x.id)
129
- expect(returnedIds[0]).toBe(id)
130
- expect(returnedIds[1]).toBe(id2)
131
- expect(returnedIds.length).toBe(2)
132
- })
133
-
134
- test.skip('fetchByRailContentIds_Order', async () => {
135
- const id = 380094
136
- const id2 = 402204
137
- const response = await fetchByRailContentIds([id2, id])
138
- const returnedIds = response.map((x) => x.id)
139
- expect(returnedIds[0]).toBe(id2)
140
- expect(returnedIds[1]).toBe(id)
141
- expect(returnedIds.length).toBe(2)
142
- })
143
-
144
- test.skip('fetchUpcomingEvents', async () => {
145
- const response = await fetchUpcomingEvents('drumeo', {})
146
- expect(response.length).toBeGreaterThan(0)
147
- })
148
-
149
- test.skip('fetchUpcomingNewReleases', async () => {
150
- const response = await fetchNewReleases('drumeo')
151
- expect(response.length).toBeGreaterThan(0)
152
- })
153
-
154
- test.skip('fetchLessonContent', async () => {
155
- const id = 392820
156
- const response = await fetchLessonContent(id)
157
- expect(response.id).toBe(id)
158
- expect(response.video.type).toBeDefined()
159
- })
160
-
161
- test.skip('fetchLessonContent-PlayAlong-containts-array-of-videos', async () => {
162
- const id = 9184
163
- const response = await fetchLessonContent(id)
164
- expect(response.id).toBe(id)
165
- expect(response.video.length).toBeGreaterThanOrEqual(1)
166
- const firstElement = response.video.find(() => true)
167
- expect(firstElement.version_name).toBeDefined()
168
- })
169
-
170
- test.skip('fetchAllSongsInProgress', async () => {
171
- contentProgressModule.getAllStarted.mockResolvedValueOnce([412941])
172
- const response = await fetchAll('drumeo', 'song', { progress: 'in progress' })
173
- expect(response.entity[0].id).toBe(412941)
174
- expect(response.entity.length).toBe(1)
175
- })
176
-
177
- // test('fetchAllSongsCompleted', async () => {
178
- // var mock = jest.spyOn(dataContext, 'fetchData');
179
- // var json = JSON.parse(`{"version":1,"config":{"key":1,"enabled":1,"checkInterval":1,"refreshInterval":2},"data":{"232979":{"s":"completed","p":100,"t":20,"u":1731108082}}}`);
180
- // mock.mockImplementation(() =>
181
- // json);
182
- // const response = await fetchAll('drumeo', 'song', {progress:"completed"});
183
- // expect(response.entity[0].id).toBe(232979);
184
- // expect(response.entity.length).toBe(1);
185
- // });
186
- //
187
- // test('fetchAllSongsNotStarted', async () => {
188
- // var mock = jest.spyOn(dataContext, 'fetchData');
189
- // var json = JSON.parse(`{"version":1,"config":{"key":1,"enabled":1,"checkInterval":1,"refreshInterval":2},"data":{"198122":{"s":"started","p":100,"t":20,"u":1731108082},"231622":{"s":"completed","p":100,"t":20,"u":1731108082}}}`);
190
- // mock.mockImplementation(() =>
191
- // json); const response = await fetchAll('drumeo', 'song', {progress:"not started"});
192
- // expect(response.entity[0].id).not.toBe(198122);
193
- // expect(response.entity[0].id).not.toBe(231622);
194
- // });
195
-
196
- test.skip('fetchNewReleases', async () => {
197
- const response = await fetchNewReleases('drumeo')
198
- log(response)
199
- expect(response[0].id).toBeDefined()
200
- })
201
-
202
- test.skip('fetchAllWorkouts', async () => {
203
- const response = await fetchAll('drumeo', 'workout', {})
204
- log(response)
205
- expect(response.entity[0].id).toBeDefined()
206
- })
207
-
208
- test.skip('fetchAllInstructorField', async () => {
209
- const response = await fetchAll('drumeo', 'quick-tips', { searchTerm: 'Domino Santantonio' })
210
- log(response)
211
- expect(response.entity[0].id).toBeDefined()
212
- expect(response.entity[0].instructors).toBeTruthy()
213
- })
214
-
215
- test.skip('fetchAllInstructors', async () => {
216
- const response = await fetchAll('drumeo', 'instructor')
217
- log(response)
218
- expect(response.entity[0].name).toBeDefined()
219
- expect(response.entity[0].coach_card_image).toBeTruthy()
220
- })
221
-
222
- test.skip('fetchAllSortField', async () => {
223
- const response = await fetchAll('drumeo', 'rhythmic-adventures-of-captain-carson', {})
224
- log(response)
225
- expect(response.entity[0].id).toBeDefined()
226
- expect(response.entity[0].sort).toBeDefined()
227
- })
228
-
229
- test.skip('fetchAll-CustomFields', async () => {
230
- let response = await fetchAll('drumeo', 'course', { customFields: ['garbage'] })
231
- log(response)
232
- expect(response.entity[0].garbage).toBeDefined()
233
- expect(response.entity[0].id).toBeDefined()
234
-
235
- response = await fetchAll('drumeo', 'course', {
236
- useDefaultFields: false, customFields: ['garbage'],
237
- })
238
- log(response)
239
- expect(response.entity[0].garbage).toBeDefined()
240
- expect.not.objectContaining(response.entity[0].id)
241
- })
242
-
243
- test.skip('fetchRelatedLessons', async () => {
244
- const id = 380094
245
- const document = await fetchByRailContentId(id, 'song')
246
- let artist = document.artist.name
247
- const response = await fetchRelatedLessons(id, 'singeo')
248
- let relatedDoc = await fetchByRailContentId(response.related_lessons[0].id, 'song')
249
- // match on artist or any genre
250
- let isMatch = artist === relatedDoc.artist.name
251
- isMatch = isMatch || document.genre.some((genre) => {
252
- return relatedDoc.genre.some((relatedGenre) => {
253
- return genre._ref === relatedGenre._ref
254
- })
255
- })
256
- expect(isMatch).toBeTruthy()
257
- })
258
-
259
- test.skip('fetchRelatedLessons-quick-tips', async () => {
260
- const id = 406213
261
- const response = await fetchRelatedLessons(id, 'singeo')
262
- log(response)
263
- const relatedLessons = response.related_lessons
264
- expect(Array.isArray(relatedLessons)).toBe(true)
265
- relatedLessons.forEach((lesson) => {
266
- expect(lesson.type).toBe('quick-tips')
267
- })
268
- })
269
-
270
- test.skip('fetchRelatedLessons-in-rhythm', async () => {
271
- const id = 236677
272
- const response = await fetchRelatedLessons(id, 'drumeo')
273
- log(response)
274
- const relatedLessons = response.related_lessons
275
- let episode = 0
276
- expect(Array.isArray(relatedLessons)).toBe(true)
277
- relatedLessons.forEach((lesson) => {
278
- expect(lesson.type).toBe('course-lesson')
279
- })
280
- })
281
-
282
- test.skip('fetchRelatedLessons-child', async () => {
283
- const id = 362278
284
- const course = await fetchByRailContentId(362277, 'course')
285
- const lessonIds = course.lessons.map((doc) => doc.id)
286
- const response = await fetchRelatedLessons(id, 'drumeo')
287
- log(response.related_lessons)
288
- const relatedLessons = response.related_lessons
289
- expect(Array.isArray(relatedLessons)).toBe(true)
290
- expect(relatedLessons.some((lesson) => lessonIds.includes(lesson.id))).toBe(true)
291
- }, 10000)
292
-
293
- test.skip('fetchAll-WithProgress', async () => {
294
- const ids = [410213, 410215]
295
- let response = await fetchAll('drumeo', 'song', {
296
- sort: 'slug', progressIds: ids,
297
- })
298
- expect(response.entity.length).toBe(2)
299
- expect((response.entity[0].id = 410215))
300
- expect((response.entity[1].id = 410213))
301
- // change the type and we expect no results
302
- response = await fetchAll('drumeo', 'quick-tip', {
303
- sort: 'slug', progressIds: ids,
304
- })
305
- expect(response.entity.length).toBe(0)
306
- })
307
-
308
- test.skip('fetchAllFilterOptions-WithProgress', async () => {
309
- const ids = [410213, 413851]
310
- let response = await fetchAllFilterOptions('drumeo', '', '', '', 'song', '', ids)
311
- expect(response.meta.totalResults).toBe(2)
312
- // change the brand and we expect no results
313
- response = await fetchAllFilterOptions('singeo', '', '', '', 'song', '', ids)
314
- expect(response.meta.totalResults).toBe(0)
315
- })
316
-
317
- test.skip('fetchPackAll', async () => {
318
- const response = await fetchPackAll(212899) //https://web-staging-one.musora.com/admin/studio/publishing/structure/pack;pack_212899%2Cinspect%3Don
319
- log(response)
320
- expect(response.slug).toBe('creative-control')
321
- })
322
-
323
- test.skip('fetchAllPacks', async () => {
324
- let response = await fetchAllPacks('drumeo')
325
- response = await fetchAllPacks('drumeo', 'slug')
326
- const titles = response.map((doc) => doc.title)
327
-
328
- const sortedTitles = [...titles].sort((a, b) => (a === b ? 0 : a > b ? 1 : -1))
329
-
330
- expect(titles).toStrictEqual(sortedTitles)
331
- response = await fetchAllPacks('drumeo', 'slug', 'Creative Control')
332
- expect(response[0].id).toBe(212899)
333
- })
334
-
335
- test.skip('fetchAll-IncludedFields', async () => {
336
- let response = await fetchAll('drumeo', 'instructor', { includedFields: ['is_active'] })
337
- console.log(response)
338
- expect(response.entity.length).toBeGreaterThan(0)
339
- })
340
-
341
- test.skip('fetchAll-IncludedFields-multiple', async () => {
342
- let response = await fetchAll('drumeo', 'course', {
343
- includedFields: ['essential,Dynamics', 'essential,Timing', 'difficulty,Beginner'],
344
- })
345
- log(response)
346
- expect(response.entity.length).toBeGreaterThan(0)
347
- })
348
-
349
- test.skip('fetchAll-IncludedFields-playalong-multiple', async () => {
350
- let response = await fetchAll('drumeo', 'play-along', {
351
- includedFields: ['bpm,91-120', 'bpm,181+', 'genre,Blues'],
352
- })
353
- log(response)
354
- expect(response.entity.length).toBeGreaterThan(0)
355
- })
356
-
357
- test.skip('fetchAll-IncludedFields-rudiment-multiple-gear', async () => {
358
- let response = await fetchAll('drumeo', 'rudiment', {
359
- includedFields: ['gear,Drum-Set', 'gear,Practice Pad'],
360
- })
361
- log(response)
362
- expect(response.entity.length).toBeGreaterThan(0)
363
- })
364
-
365
- test.skip('fetchAll-IncludedFields-coaches-multiple-focus', async () => {
366
- let response = await fetchAll('drumeo', 'instructor', {
367
- includedFields: ['focus,Drumline', 'focus,Recording'],
368
- })
369
- log(response)
370
- expect(response.entity.length).toBeGreaterThan(0)
371
- })
372
-
373
- test.skip('fetchAll-IncludedFields-songs-multiple-instrumentless', async () => {
374
- let response = await fetchAll('drumeo', 'song', {
375
- includedFields: ['instrumentless,true', 'instrumentless,false'],
376
- })
377
- log(response)
378
- expect(response.entity.length).toBeGreaterThan(0)
379
- })
380
-
381
- test.skip('fetchByReference', async () => {
382
- const response = await fetchByReference('drumeo', { includedFields: ['is_featured'] })
383
- expect(response.entity.length).toBeGreaterThan(0)
384
- })
385
-
386
- test.skip('fetchScheduledReleases', async () => {
387
- const response = await fetchScheduledReleases('drumeo', {})
388
- expect(response.length).toBeGreaterThan(0)
389
- })
390
-
391
- test.skip('fetchAll-GroupBy-Genre', async () => {
392
- let response = await fetchAll('drumeo', 'solo', { groupBy: 'genre' })
393
- log(response)
394
- expect(response.entity[0].web_url_path).toContain('/drumeo/genres/')
395
- })
396
-
397
- test.skip('fetchAll-GroupBy-Artists', async () => {
398
- let response = await fetchAll('drumeo', 'song', { groupBy: 'artist' })
399
- log(response)
400
- expect(response.entity[0].web_url_path).toContain('/drumeo/artists/')
401
- })
402
-
403
- test.skip('fetchAll-GroupBy-Instructors', async () => {
404
- let response = await fetchAll('drumeo', 'course', { groupBy: 'instructor' })
405
- log(response)
406
- expect(response.entity[0].web_url_path).toContain('/drumeo/coaches/')
407
- })
408
-
409
- test.skip('fetchShowsData', async () => {
410
- const response = await fetchShowsData('drumeo')
411
- log(response)
412
- expect(response.length).toBeGreaterThan(0)
413
- const showTypes = response.map((x) => x.type)
414
- expect(showTypes).toContain('live')
415
- })
416
-
417
- test.skip('fetchMetadata', async () => {
418
- const response = await fetchMetadata('drumeo', 'songs')
419
- log(response)
420
- expect(response.tabs.length).toBeGreaterThan(0)
421
- })
422
-
423
- test.skip('fetchShowsData-OddTimes', async () => {
424
- const response = await fetchShowsData('drumeo')
425
- log(response)
426
- expect(response.length).toBeGreaterThan(0)
427
- const showTypes = response.map((x) => x.type)
428
- expect(showTypes).toContain('odd-times')
429
- })
430
-
431
- test.skip('fetchMetadata-Coach-Lessons', async () => {
432
- const response = await fetchMetadata('drumeo', 'coach-lessons')
433
- log(response)
434
- expect(response).toBeDefined()
435
- })
436
-
437
- test.skip('fetchTopLevelParentId', async () => {
438
- let contentId = await fetchTopLevelParentId(241250)
439
- expect(contentId).toBe(241247)
440
- contentId = await fetchTopLevelParentId(241249)
441
- expect(contentId).toBe(241247)
442
- contentId = await fetchTopLevelParentId(241248)
443
- expect(contentId).toBe(241247)
444
- contentId = await fetchTopLevelParentId(241247)
445
- expect(contentId).toBe(241247)
446
- contentId = await fetchTopLevelParentId(0)
447
- expect(contentId).toBe(null)
448
- })
449
-
450
- test.skip('fetchHierarchy', async () => {
451
- let hierarchy = await fetchHierarchy(241250)
452
- expect(hierarchy.parents[241250]).toBe(241249)
453
- expect(hierarchy.parents[241249]).toBe(241248)
454
- expect(hierarchy.parents[241248]).toBe(241247)
455
- expect(hierarchy.children[241250]).toStrictEqual([241676])
456
- expect(hierarchy.children[243085]).toStrictEqual([243170, 243171, 243172, 243174, 243176])
457
- })
458
-
459
- test.skip('fetchTopLeveldrafts', async () => {
460
- let id = await fetchTopLevelParentId(401999)
461
- expect(id).toBe(401999)
462
- })
463
-
464
- test.skip('fetchCommentData', async () => {
465
- let data = await fetchCommentModContentData([241251, 241252, 211153])
466
- expect(data[241251].title).toBe('Setting Up Your Space')
467
- expect(data[241251].type).toBe('course-lesson')
468
- expect(data[241251].parentTitle).toBe('Getting Started On The Drums')
469
- expect(data[241252].title).toBe('Setting Up Your Pedals & Throne')
470
- })
471
- })
472
-
473
- describe('MetaData', function() {
474
- test.skip('customBrandTypeExists', async () => {
475
- const metaData = processMetadata('guitareo', 'recording')
476
- expect(metaData.type).toBe('recording')
477
- expect(metaData.name).toBe('Archives')
478
- expect(metaData.description).toBeDefined()
479
- })
480
-
481
- test('withCommon', async () => {
482
- const guitareoMetaData = processMetadata('guitareo', 'instructor')
483
- const drumeoMetaData = processMetadata('drumeo', 'instructor')
484
- expect(guitareoMetaData.description).not.toBe(drumeoMetaData.description)
485
- guitareoMetaData.description = ''
486
- drumeoMetaData.description = ''
487
- guitareoMetaData.url = ''
488
- drumeoMetaData.url = ''
489
- expect(guitareoMetaData).toStrictEqual(drumeoMetaData)
490
- })
491
- })
492
-
493
- describe('api.v1', function() {
494
- jest.setTimeout(30000)
495
- beforeEach(() => {
496
- initializeTestService()
497
- })
498
- test('metaDataForLessons', async () => {
499
- const metaData = await fetchMetadata('drumeo', 'lessons')
500
- log(metaData)
501
- expect(metaData.filters).toBeDefined()
502
- expect(metaData.sort).toBeDefined()
503
- expect(metaData.tabs).toBeDefined()
504
- })
505
-
506
- test('metaDataForSongs', async () => {
507
- const metaData = await fetchMetadata('drumeo', 'songs')
508
- log(metaData)
509
- expect(metaData.filters).toBeDefined()
510
- expect(metaData.sort).toBeDefined()
511
- expect(metaData.tabs).toBeDefined()
512
- })
513
-
514
- test('fetchAllFilterOptionsLessons', async () => {
515
- const response = await fetchAllFilterOptions('pianote', [], null, null, 'lessons')
516
- log(response)
517
- expect(response.meta.filters).toBeDefined()
518
- })
519
-
520
- test('fetchAllFilterOptionsSongs', async () => {
521
- const response = await fetchAllFilterOptions('pianote', [], null, null, 'songs')
522
- log(response)
523
- expect(response.meta.filters).toBeDefined()
524
- })
525
-
526
- test('fetchLiveEvent', async () => {
527
- const liveEvent = await fetchLiveEvent('drumeo', 410881)
528
- log(liveEvent)
529
- //expect(metaData).toBeNull()
530
- })
531
-
532
-
533
-
534
- test('fetchRelatedLessons-pack-bundle-lessons', async () => {
535
- //https://www.musora.com/singeo/packs/sing-harmony-in-30-days/410537/sing-harmony-in-30-days/410538/day-2/410541
536
- const railContentId = 410541
537
- const relatedLessons = await fetchRelatedLessons(railContentId, 'singeo')
538
- log(relatedLessons)
539
- const expectedPath = ['', 'singeo', 'packs', 'sing-harmony-in-30-days', '410537', 'sing-harmony-in-30-days', '410538']
540
- expect(relatedLessons['related_lessons'].length).toBeGreaterThanOrEqual(1)
541
- relatedLessons['related_lessons'].forEach(document => {
542
- expect(document.type).toStrictEqual('course-lesson')
543
- // there are other ways to check that these all have the same parent, but I don't want to write it
544
- if (document.web_url_path) {
545
- let web_url_path = document.web_url_path.split('/')
546
- // remove id and slug
547
- web_url_path.pop()
548
- web_url_path.pop()
549
- expect(web_url_path).toEqual(expectedPath)
550
- }
551
- })
552
- })
553
-
554
- test('fetchRelatedLessons-course-parts', async () => {
555
- ///drumeo/courses/ultra-compact-drum-set-gear-guide/295177/gigpig-standard-and-extendable/297929
556
- const railContentId = 297929
557
- const relatedLessons = await fetchRelatedLessons(railContentId, 'drumeo')
558
- log(relatedLessons)
559
- const expectedPath = ['', 'drumeo', 'courses', 'ultra-compact-drum-set-gear-guide', '295177']
560
- expect(relatedLessons['related_lessons'].length).toBeGreaterThanOrEqual(1)
561
- relatedLessons['related_lessons'].forEach(document => {
562
- expect(document.type).toStrictEqual('course-lesson')
563
- // there are other ways to check that these all have the same parent, but I don't want to write it
564
- if (document.web_url_path) {
565
- let web_url_path = document.web_url_path.split('/')
566
- // remove id and slug
567
- web_url_path.pop()
568
- web_url_path.pop()
569
- expect(web_url_path).toEqual(expectedPath)
570
- }
571
- })
572
- })
573
- })
574
-
575
- describe('api.v1.admin', function() {
576
- beforeEach(() => {
577
- initializeTestService(false, true)
578
- })
579
-
580
- test('fetchOtherSongVersions', async () => {
581
- // much of the licensed content is currently drafted, so this must be run in the admin test-suite
582
- const railContentId = 386901
583
- const licenseQuery = `*[railcontent_id == ${railContentId}]{
584
- 'content_ids': *[_type == 'license' && references(^._id)].content[]->railcontent_id
585
- }[0]`
586
- const otherReferencedContent = (await fetchSanity(licenseQuery, true))['content_ids']
587
- log(otherReferencedContent)
588
- const relatedSongsTypes = await fetchOtherSongVersions(railContentId, 'drumeo', 100)
589
- log(relatedSongsTypes)
590
- expect(relatedSongsTypes.length).toBeGreaterThanOrEqual(1)
591
- relatedSongsTypes.forEach(document => {
592
- expect(SONG_TYPES).toContain(document.type)
593
- expect(document.id).not.toStrictEqual(railContentId)
594
- expect(otherReferencedContent).toContain(document.id)
595
- })
596
- })
597
-
598
- test('fetchLessonsFeaturingThisContent', async () => {
599
- // much of the licensed content is currently drafted, so this must be run in the admin test-suite
600
- const railContentId = 386901
601
- const licenseQuery = `*[railcontent_id == ${railContentId}]{
602
- 'content_ids': *[_type == 'license' && references(^._id)].content[]->railcontent_id
603
- }[0]`
604
- const otherReferencedContent = (await fetchSanity(licenseQuery, true))['content_ids']
605
- const relatedNotSongs = await fetchLessonsFeaturingThisContent(railContentId, 'drumeo', 100)
606
- log(relatedNotSongs)
607
- expect(relatedNotSongs.length).toBeGreaterThanOrEqual(1)
608
- relatedNotSongs.forEach(document => {
609
- expect(SONG_TYPES).not.toContain(document.type)
610
- expect(document.id).not.toStrictEqual(railContentId)
611
- expect(otherReferencedContent).toContain(document.id)
612
- })
613
- })
614
-
615
- test('fetchRelatedLessons-song-tutorial-children', async () => {
616
- // When I wrote this it didn't need admin, but something changed. Shrug
617
- const railContentId = 222633
618
- const relatedLessons = await fetchRelatedLessons(railContentId, 'pianote')
619
- log(relatedLessons)
620
- const expectedPath = ['', 'pianote', 'song-tutorials', 'hallelujah', '221831']
621
- expect(relatedLessons['related_lessons'].length).toBeGreaterThanOrEqual(1)
622
- relatedLessons['related_lessons'].forEach(document => {
623
- expect(document.type).toStrictEqual('song-tutorial-lesson')
624
- if (document.web_url_path) {
625
- let web_url_path = document.web_url_path.split('/')
626
- // remove id, slug
627
- web_url_path.pop()
628
- web_url_path.pop()
629
- expect(web_url_path).toEqual(expectedPath)
630
- }
631
- })
632
- })
633
- })
634
-
635
- describe('Filter Builder', function() {
636
- beforeEach(() => {
637
- initializeTestService()
638
- })
639
-
640
- test('fetchAllFilterOptions', async () => {
641
- let response = await fetchAllFilterOptions('drumeo', [], '', '', 'song', '')
642
- log(response)
643
- expect(response.meta.filterOptions.difficulty).toBeDefined()
644
- expect(response.meta.filterOptions.genre).toBeDefined()
645
- expect(response.meta.filterOptions.lifestyle).toBeDefined()
646
- expect(response.meta.filterOptions.instrumentless).toBeDefined()
647
- })
648
-
649
- test('fetchAllFilterOptions-Rudiment', async () => {
650
- let response = await fetchAllFilterOptions('drumeo', [], '', '', 'rudiment', '')
651
- log(response)
652
- expect(response.meta.filterOptions.gear).toBeDefined()
653
- expect(response.meta.filterOptions.genre).toBeDefined()
654
- expect(response.meta.filterOptions.topic).toBeDefined()
655
- })
656
-
657
- test('fetchAllFilterOptions-PlayAlong', async () => {
658
- let response = await fetchAllFilterOptions('drumeo', [], '', '', 'play-along', '')
659
- log(response)
660
- expect(response.meta.filterOptions.difficulty).toBeDefined()
661
- expect(response.meta.filterOptions.genre).toBeDefined()
662
- expect(response.meta.filterOptions.bpm).toBeDefined()
663
- })
664
-
665
- test('fetchAllFilterOptions-Coaches', async () => {
666
- let response = await fetchAllFilterOptions('drumeo', [], '', '', 'instructor', '')
667
- log(response)
668
- expect(response.meta.filterOptions.focus).toBeDefined()
669
- expect(response.meta.filterOptions.focus.length).toBeGreaterThan(0)
670
- expect(response.meta.filterOptions.genre).toBeDefined()
671
- expect(response.meta.filterOptions.genre.length).toBeGreaterThan(0)
672
- })
673
-
674
- test.skip('fetchAllFilterOptions-filter-selected', async () => {
675
- // SKIPPED: filter combination returns null — filter terms may no longer exist in schema
676
- let response = await fetchAllFilterOptions('drumeo', ['theory,notation', 'theory,time signatures', 'creativity,Grooves', 'creativity,Fills & Chops', 'difficulty,Beginner', 'difficulty,Intermediate', 'difficulty,Expert'], '', '', 'course', '')
677
- log(response)
678
- expect(response.meta.filterOptions).toBeDefined()
679
- })
680
- })
681
-