musora-content-services 1.0.171 → 1.0.173

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 CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.0.173](https://github.com/railroadmedia/musora-content-services/compare/v1.0.172...v1.0.173) (2024-11-14)
6
+
7
+ ### [1.0.172](https://github.com/railroadmedia/musora-content-services/compare/v1.0.171...v1.0.172) (2024-11-13)
8
+
5
9
  ### [1.0.171](https://github.com/railroadmedia/musora-content-services/compare/v1.0.170...v1.0.171) (2024-11-12)
6
10
 
7
11
  ### [1.0.170](https://github.com/railroadmedia/musora-content-services/compare/v1.0.169...v1.0.170) (2024-11-12)
package/README.md CHANGED
File without changes
File without changes
package/docs/index.html CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/jest.config.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "1.0.171",
3
+ "version": "1.0.173",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
File without changes
File without changes
package/src/index.d.ts CHANGED
@@ -12,6 +12,8 @@ import {
12
12
  } from './services/contentLikes.js';
13
13
 
14
14
  import {
15
+ assignmentStatusCompleted,
16
+ assignmentStatusReset,
15
17
  contentStatusCompleted,
16
18
  contentStatusReset,
17
19
  getAllCompleted,
@@ -77,6 +79,7 @@ import {
77
79
  fetchAllSongs,
78
80
  fetchArtistLessons,
79
81
  fetchArtists,
82
+ fetchAssignments,
80
83
  fetchByRailContentId,
81
84
  fetchByRailContentIds,
82
85
  fetchByReference,
@@ -129,6 +132,8 @@ import {
129
132
  declare module 'musora-content-services' {
130
133
  export {
131
134
  addItemToPlaylist,
135
+ assignmentStatusCompleted,
136
+ assignmentStatusReset,
132
137
  contentStatusCompleted,
133
138
  contentStatusReset,
134
139
  countAssignmentsAndLessons,
@@ -144,6 +149,7 @@ declare module 'musora-content-services' {
144
149
  fetchAllSongs,
145
150
  fetchArtistLessons,
146
151
  fetchArtists,
152
+ fetchAssignments,
147
153
  fetchByRailContentId,
148
154
  fetchByRailContentIds,
149
155
  fetchByReference,
package/src/index.js CHANGED
@@ -12,6 +12,8 @@ import {
12
12
  } from './services/contentLikes.js';
13
13
 
14
14
  import {
15
+ assignmentStatusCompleted,
16
+ assignmentStatusReset,
15
17
  contentStatusCompleted,
16
18
  contentStatusReset,
17
19
  getAllCompleted,
@@ -77,6 +79,7 @@ import {
77
79
  fetchAllSongs,
78
80
  fetchArtistLessons,
79
81
  fetchArtists,
82
+ fetchAssignments,
80
83
  fetchByRailContentId,
81
84
  fetchByRailContentIds,
82
85
  fetchByReference,
@@ -128,6 +131,8 @@ import {
128
131
 
129
132
  export {
130
133
  addItemToPlaylist,
134
+ assignmentStatusCompleted,
135
+ assignmentStatusReset,
131
136
  contentStatusCompleted,
132
137
  contentStatusReset,
133
138
  countAssignmentsAndLessons,
@@ -143,6 +148,7 @@ export {
143
148
  fetchAllSongs,
144
149
  fetchArtistLessons,
145
150
  fetchArtists,
151
+ fetchAssignments,
146
152
  fetchByRailContentId,
147
153
  fetchByRailContentIds,
148
154
  fetchByReference,
File without changes
File without changes
@@ -5,7 +5,7 @@ import {
5
5
  postRecordWatchSession
6
6
  } from "./railcontent";
7
7
  import {DataContext, ContentProgressVersionKey} from "./dataContext";
8
- import {fetchHierarchy} from "./sanity";
8
+ import {fetchAssignments, fetchHierarchy} from "./sanity";
9
9
 
10
10
  const STATE_STARTED = 'started';
11
11
  const STATE_COMPLETED = 'completed';
@@ -86,44 +86,105 @@ export async function getResumeTimeSeconds(contentId) {
86
86
  return data[contentId]?.[DATA_KEY_RESUME_TIME] ?? 0;
87
87
  }
88
88
 
89
+ export async function assignmentStatusCompleted(assignmentId, parentContentId) {
90
+ await dataContext.update(
91
+ async function (localContext) {
92
+ let hierarchy = await fetchHierarchy(parentContentId);
93
+ completeStatusInLocalContext(localContext, assignmentId, hierarchy);
94
+ },
95
+ async function () {
96
+ return postContentCompleted(assignmentId);
97
+ });
98
+ }
99
+
89
100
  export async function contentStatusCompleted(contentId) {
90
101
  await dataContext.update(
91
102
  async function (localContext) {
92
103
  let hierarchy = await fetchHierarchy(contentId);
93
- completeStatusInLocalContext(contentId, localContext, hierarchy);
104
+ completeStatusInLocalContext(localContext, contentId, hierarchy);
94
105
  },
95
106
  async function () {
96
107
  return postContentCompleted(contentId);
97
108
  });
98
109
  }
99
110
 
100
- function completeStatusInLocalContext(contentId, localContext, hierarchy) {
111
+
112
+ function saveContentProgress(localContext, contentId, progress, currentSeconds, hierarchy) {
113
+ if (progress === 100) {
114
+ completeStatusInLocalContext(localContext, contentId, hierarchy);
115
+ return;
116
+ }
117
+
118
+ let data = localContext.data[contentId] ?? {};
119
+ data[DATA_KEY_PROGRESS] = progress;
120
+ data[DATA_KEY_STATUS] = STATE_STARTED;
121
+ data[DATA_KEY_RESUME_TIME] = currentSeconds;
122
+ data[DATA_KEY_LAST_UPDATED_TIME] = Math.round(new Date().getTime() / 1000);
123
+ localContext.data[contentId] = data;
124
+
125
+ bubbleProgress(hierarchy, contentId, localContext);
126
+ }
127
+
128
+ function completeStatusInLocalContext(localContext, contentId, hierarchy) {
101
129
  let data = localContext.data[contentId] ?? {};
102
- data[DATA_KEY_STATUS] = STATE_COMPLETED;
103
130
  data[DATA_KEY_PROGRESS] = 100;
131
+ data[DATA_KEY_STATUS] = STATE_COMPLETED;
104
132
  data[DATA_KEY_LAST_UPDATED_TIME] = Math.round(new Date().getTime() / 1000);
105
133
  localContext.data[contentId] = data;
106
134
 
135
+ if (!hierarchy) return;
107
136
  let children = hierarchy.children[contentId] ?? [];
108
137
  for (let i = 0; i < children.length; i++) {
109
138
  let childId = children[i];
110
- completeStatusInLocalContext(childId, localContext, hierarchy);
139
+ completeStatusInLocalContext(localContext, childId, hierarchy);
111
140
  }
141
+ bubbleProgress(hierarchy, contentId, localContext);
142
+ }
143
+
144
+ function getChildrenToDepth(parentId, hierarchy, depth = 1) {
145
+ let childIds = hierarchy.children[parentId] ?? [];
146
+ let allChildrenIds = childIds;
147
+ childIds.forEach(id => {
148
+ allChildrenIds = allChildrenIds.concat(getChildrenToDepth(id, hierarchy, depth - 1));
149
+ })
150
+ return allChildrenIds;
151
+ }
152
+
153
+
154
+ export async function assignmentStatusReset(assignmentId, contentId) {
155
+ await dataContext.update(
156
+ async function (localContext) {
157
+ let hierarchy = await fetchHierarchy(contentId);
158
+ resetStatusInLocalContext(localContext, assignmentId, hierarchy);
159
+ },
160
+ async function () {
161
+ return postContentReset(contentId);
162
+ });
112
163
  }
113
164
 
114
165
  export async function contentStatusReset(contentId) {
115
166
  await dataContext.update(
116
- function (localContext) {
117
- const index = Object.keys(localContext.data).indexOf(contentId.toString());
118
- if (index > -1) { // only splice array when item is found
119
- delete localContext.data[contentId];
120
- }
167
+ async function (localContext) {
168
+ let hierarchy = await fetchHierarchy(contentId);
169
+ resetStatusInLocalContext(localContext, contentId, hierarchy);
121
170
  },
122
171
  async function () {
123
172
  return postContentReset(contentId);
124
173
  });
125
174
  }
126
175
 
176
+ function resetStatusInLocalContext(localContext, contentId, hierarchy) {
177
+ let allChildIds = getChildrenToDepth(contentId, hierarchy, 5);
178
+ allChildIds.push(contentId);
179
+ allChildIds.forEach(id => {
180
+ const index = Object.keys(localContext.data).indexOf(id.toString());
181
+ if (index > -1) { // only splice array when item is found
182
+ delete localContext.data[id];
183
+ }
184
+ });
185
+ bubbleProgress(hierarchy, contentId, localContext);
186
+ }
187
+
127
188
  /**
128
189
  * Record watch session
129
190
  * @return {string} sessionId - provide in future calls to update progress
@@ -144,23 +205,12 @@ export async function recordWatchSession(contentId, mediaType, mediaCategory, me
144
205
  await dataContext.update(
145
206
  async function (localContext) {
146
207
  if (contentId && updateLocalProgress) {
147
- let data = localContext.data[contentId] ?? {};
148
- let progress = data?.[DATA_KEY_PROGRESS] ?? 0;
149
- let status = data?.[DATA_KEY_STATUS] ?? 0;
150
-
151
- if (status !== STATE_COMPLETED && progress !== 100) {
152
- status = STATE_STARTED;
153
- progress = Math.min(99, Math.round(currentSeconds ?? 0 / Math.max(1, mediaLengthSeconds ?? 0) * 100));
208
+ if (mediaLengthSeconds <= 0) {
209
+ return;
154
210
  }
155
-
156
- data[DATA_KEY_PROGRESS] = progress;
157
- data[DATA_KEY_STATUS] = status;
158
- data[DATA_KEY_RESUME_TIME] = currentSeconds;
159
- data[DATA_KEY_LAST_UPDATED_TIME] = Math.round(new Date().getTime() / 1000);
160
- localContext.data[contentId] = data;
161
-
211
+ let progress = Math.min(99, Math.round(currentSeconds ?? 0 / Math.max(1, mediaLengthSeconds ?? 0) * 100));
162
212
  let hierarchy = await fetchHierarchy(contentId);
163
- bubbleProgress(hierarchy, contentId, localContext);
213
+ saveContentProgress(localContext, contentId, progress, currentSeconds, hierarchy);
164
214
  }
165
215
  },
166
216
  async function () {
@@ -196,16 +246,13 @@ function bubbleProgress(hierarchy, contentId, localContext) {
196
246
  let parentId = hierarchy.parents[contentId];
197
247
  if (!parentId) return;
198
248
  let data = localContext.data[parentId] ?? {};
199
- let progress = data[DATA_KEY_PROGRESS];
200
- let status = data[DATA_KEY_STATUS];
201
- if (status !== STATE_COMPLETED && progress !== 100) {
202
- let childProgress = hierarchy.children[parentId].map(function (childId) {
203
- return localContext.data[childId]?.[DATA_KEY_PROGRESS] ?? 0;
204
- });
205
- progress = Math.round(childProgress.reduce((a, b) => a + b, 0) / childProgress.length);
206
- data[DATA_KEY_PROGRESS] = progress;
207
- localContext.data[parentId] = data;
208
- }
249
+ let childProgress = hierarchy.children[parentId].map(function (childId) {
250
+ return localContext.data[childId]?.[DATA_KEY_PROGRESS] ?? 0;
251
+ });
252
+ let progress = Math.round(childProgress.reduce((a, b) => a + b, 0) / childProgress.length);
253
+ data[DATA_KEY_PROGRESS] = progress;
254
+ data[DATA_KEY_STATUS] = progress === 100 ? STATE_COMPLETED : STATE_STARTED;
255
+ localContext.data[parentId] = data;
209
256
  bubbleProgress(hierarchy, parentId, localContext);
210
257
  }
211
258
 
@@ -46,7 +46,7 @@ export class DataContext {
46
46
  async ensureLocalContextLoaded() {
47
47
  if (this.context) return;
48
48
  this.verifyConfig();
49
- let localData = globalConfig.isMA ? await cache.getItem(this.localStorageKey): cache.getItem(this.localStorageKey) ;
49
+ let localData = globalConfig.isMA ? await cache.getItem(this.localStorageKey) : cache.getItem(this.localStorageKey);
50
50
  if (localData) {
51
51
  this.context = JSON.parse(localData);
52
52
  }
@@ -85,10 +85,13 @@ export class DataContext {
85
85
  cache.setItem(this.localStorageKey, data);
86
86
  cache.setItem(this.localStorageLastUpdatedKey, new Date().getTime().toString());
87
87
  }
88
- let response = await serverUpdateFunction();
89
- if (response?.version !== this.version()) {
90
- this.clearCache();
91
- }
88
+ const updatePromise = serverUpdateFunction();
89
+ updatePromise.then((response) => {
90
+ if (response?.version !== this.version()) {
91
+ this.clearCache();
92
+ }
93
+ });
94
+ return updatePromise;
92
95
  }
93
96
 
94
97
  version() {
File without changes
@@ -1399,18 +1399,22 @@ export async function fetchHierarchy(railcontentId) {
1399
1399
  let topLevelId = await fetchTopLevelParentId(railcontentId);
1400
1400
  const query = `*[railcontent_id == ${topLevelId}]{
1401
1401
  railcontent_id,
1402
+ 'assignments': assignment[]{railcontent_id},
1402
1403
  'children': child[]->{
1403
1404
  railcontent_id,
1405
+ 'assignments': assignment[]{railcontent_id},
1404
1406
  'children': child[]->{
1405
1407
  railcontent_id,
1408
+ 'assignments': assignment[]{railcontent_id},
1406
1409
  'children': child[]->{
1407
1410
  railcontent_id,
1411
+ 'assignments': assignment[]{railcontent_id},
1408
1412
  'children': child[]->{
1409
- railcontent_id,
1413
+ railcontent_id,
1410
1414
  }
1411
1415
  }
1412
1416
  }
1413
- }
1417
+ },
1414
1418
  }`;
1415
1419
  let response = await fetchSanity(query, false, {processNeedAccess: false});
1416
1420
  if (!response) return null;
@@ -1422,9 +1426,11 @@ export async function fetchHierarchy(railcontentId) {
1422
1426
  return data;
1423
1427
  }
1424
1428
 
1429
+
1425
1430
  function populateHierarchyLookups(currentLevel, data, parentId) {
1426
1431
  let contentId = currentLevel['railcontent_id'];
1427
1432
  let children = currentLevel['children'];
1433
+
1428
1434
  data.parents[contentId] = parentId;
1429
1435
  if (children) {
1430
1436
  data.children[contentId] = children.map(child => child['railcontent_id']);
@@ -1434,6 +1440,36 @@ function populateHierarchyLookups(currentLevel, data, parentId) {
1434
1440
  } else {
1435
1441
  data.children[contentId] = [];
1436
1442
  }
1443
+
1444
+ let assignments = currentLevel['assignments'];
1445
+ if (assignments) {
1446
+ let assignmentIds = assignments.map(assignment => assignment['railcontent_id']);
1447
+ data.children[contentId] = (data.children[contentId] ?? []).concat(assignmentIds);
1448
+ assignmentIds.forEach(assignmentId => {
1449
+ data.parents[assignmentId] = contentId;
1450
+ });
1451
+ }
1452
+
1453
+ }
1454
+
1455
+ /**
1456
+ * Fetch assignments for content
1457
+ *
1458
+ * @param {integer} contentId - List of ids get data for
1459
+ * @returns {Promise<array|null>} - A promise that resolves to an array containing the data
1460
+ */
1461
+ export async function fetchAssignments(contentId) {
1462
+ const fields = `"id": railcontent_id,"assignments":assignment[]{"id": railcontent_id}`;
1463
+ const query = await buildQuery(`railcontent_id == ${contentId}`,
1464
+ {bypassPermissions: true},
1465
+ fields,
1466
+ {end: 100});
1467
+ let data = await fetchSanity(query, false);
1468
+ let mapped = [];
1469
+ data.assignments.forEach(function (content) {
1470
+ mapped.push(content.id);
1471
+ });
1472
+ return mapped;
1437
1473
  }
1438
1474
 
1439
1475
  /**
@@ -1448,7 +1484,7 @@ export async function fetchCommentModContentData(ids) {
1448
1484
  const query = await buildQuery(`railcontent_id in [${idsString}]`,
1449
1485
  {bypassPermissions: true},
1450
1486
  fields,
1451
- {end:50});
1487
+ {end: 50});
1452
1488
  let data = await fetchSanity(query, true);
1453
1489
  let mapped = {};
1454
1490
  data.forEach(function (content) {
File without changes
File without changes
@@ -7,7 +7,7 @@ import {
7
7
  getProgressStateByIds,
8
8
  getAllStarted,
9
9
  getAllCompleted,
10
- contentStatusCompleted
10
+ contentStatusCompleted, assignmentStatusCompleted, contentStatusReset, assignmentStatusReset
11
11
  } from "../src/services/contentProgress";
12
12
  import {initializeTestService} from "./initializeTests";
13
13
  import {postContentCompleted} from "../src";
@@ -17,12 +17,23 @@ const railContentModule = require('../src/services/railcontent.js')
17
17
  describe('contentProgressDataContext', function () {
18
18
  let mock = null;
19
19
  const testVersion = 1;
20
+ let serverVersion = 2;
20
21
 
21
22
  beforeEach(() => {
22
23
  initializeTestService();
23
24
  mock = jest.spyOn(dataContext, 'fetchData');
24
25
  var json = JSON.parse(`{"version":${testVersion},"config":{"key":1,"enabled":1,"checkInterval":1,"refreshInterval":2},"data":{"234191":{"s":"started","p":6,"t":20,"u":1731108082},"233955":{"s":"started","p":1,"u":1731108083},"259426":{"s":"completed","p":100,"u":1731108085}}}`);
25
- mock.mockImplementation(() => json);
26
+ mock.mockImplementation(() =>
27
+ json);
28
+
29
+ let mock2 = jest.spyOn(railContentModule, 'postRecordWatchSession');
30
+ mock2.mockImplementation(() => JSON.parse(`{"version": ${serverVersion}}`));
31
+
32
+ let mock3 = jest.spyOn(railContentModule, 'postContentCompleted');
33
+ mock3.mockImplementation(() => JSON.parse(`{"version": ${serverVersion}}`));
34
+
35
+ let mock4 = jest.spyOn(railContentModule, 'postContentReset');
36
+ mock4.mockImplementation(() => JSON.parse(`{"version": ${serverVersion}}`));
26
37
  });
27
38
 
28
39
  test('getProgressPercentage', async () => {
@@ -72,11 +83,6 @@ describe('contentProgressDataContext', function () {
72
83
  // expect(result2).toStrictEqual([111111, 233955, 234191]);
73
84
  // });
74
85
 
75
- test('getAllCompleted', async () => {
76
- let result = await getAllCompleted();
77
- expect(result).toStrictEqual([259426]);
78
- });
79
-
80
86
  // test('getAllCompletedWithUpdate', async () => {
81
87
  // let mock2 = jest.spyOn(railContentModule, 'postContentCompleted');
82
88
  // let serverVersion = 2;
@@ -90,9 +96,7 @@ describe('contentProgressDataContext', function () {
90
96
  // });
91
97
 
92
98
  test('progressBubbling', async () => {
93
- let mock2 = jest.spyOn(railContentModule, 'postRecordWatchSession');
94
- let serverVersion = 2;
95
- mock2.mockImplementation(() => JSON.parse(`{"version": ${serverVersion}}`));
99
+
96
100
  let progress = await getProgressPercentage(241250); //force load context
97
101
 
98
102
  await recordWatchSession(241250, "video", "vimeo", 100, 50, 50);
@@ -117,4 +121,91 @@ describe('contentProgressDataContext', function () {
117
121
 
118
122
  });
119
123
 
124
+ test('assignmentCompleteBubbling', async () => {
125
+ let assignmentId = 286048;
126
+ let contentId = 286047;
127
+
128
+ let state = await getProgressState(contentId);
129
+ expect(state).toBe("");
130
+ let result = await assignmentStatusCompleted(assignmentId, contentId);
131
+
132
+ state = await getProgressState(assignmentId);
133
+ expect(state).toBe("completed");
134
+ state = await getProgressState(contentId); //assignment
135
+ expect(state).toBe("started");
136
+ });
137
+
138
+ // test('assignmentCompleteBubblingToCompleted', async () => {
139
+ // let assignmentId = 241685;
140
+ // let contentId = 241257;
141
+ //
142
+ // let state = await getProgressState(contentId);
143
+ // expect(state).toBe("");
144
+ // let result = await assignmentStatusCompleted(assignmentId, contentId);
145
+ //
146
+ // state = await getProgressState(assignmentId);
147
+ // expect(state).toBe("completed");
148
+ // state = await getProgressState(contentId); //assignment
149
+ // expect(state).toBe("completed");
150
+ // });
151
+ //
152
+ // test('assignmentCompleteResetBubblingMultiple', async () => {
153
+ // let contentId = 281709;
154
+ //
155
+ // let state = await getProgressState(contentId);
156
+ // expect(state).toBe("");
157
+ //
158
+ // let assignmentIds = [281710, 281711, 281712, 281713, 281714, 281715];
159
+ // for (const assignmentId of assignmentIds) {
160
+ // await assignmentStatusCompleted(assignmentId, contentId);
161
+ // state = await getProgressState(assignmentId);
162
+ // expect(state).toBe("completed");
163
+ // }
164
+ //
165
+ // state = await getProgressState(contentId);
166
+ // expect(state).toBe("completed");
167
+ //
168
+ // await assignmentStatusReset(assignmentIds[0], contentId);
169
+ // state = await getProgressState(assignmentIds[0]);
170
+ // expect(state).toBe("");
171
+ // state = await getProgressState(contentId);
172
+ // expect(state).toBe("started");
173
+ // let percentage = await getProgressPercentage(contentId);
174
+ // expect(percentage).toBe(83);
175
+ // });
176
+
177
+
178
+ //
179
+ // test('completeBubbling', async () => {
180
+ // let state = await getProgressState(276698);
181
+ // expect(state).toBe("");
182
+ // let result = await contentStatusCompleted(276698);
183
+ //
184
+ // state = await getProgressState(276698);
185
+ // expect(state).toBe("completed");
186
+ // state = await getProgressState(276699); //assignment
187
+ // expect(state).toBe("completed");
188
+ // });
189
+ //
190
+ // test('resetBubbling', async () => {
191
+ // let assignmentId = 241686;
192
+ // let contentId = 241258;
193
+ //
194
+ // let state = await getProgressState(contentId);
195
+ // expect(state).toBe("");
196
+ // let result = await contentStatusCompleted(contentId);
197
+ // state = await getProgressState(contentId);
198
+ // expect(state).toBe("completed");
199
+ // state = await getProgressState(assignmentId); //assignment
200
+ // expect(state).toBe("completed");
201
+ //
202
+ // result = await contentStatusReset(contentId);
203
+ // state = await getProgressState(contentId);
204
+ // expect(state).toBe("");
205
+ // state = await getProgressState(assignmentId); //assignment
206
+ // expect(state).toBe("");
207
+ //
208
+ // });
209
+
210
+
120
211
  });
File without changes
File without changes
@@ -2,7 +2,7 @@ import {
2
2
  recordWatchSession,
3
3
  getProgressPercentage,
4
4
  dataContext,
5
- getProgressState, contentStatusCompleted, contentStatusReset
5
+ getProgressState, contentStatusCompleted, contentStatusReset, assignmentStatusCompleted
6
6
  } from "../../src/services/contentProgress";
7
7
  import {initializeTestService} from "../initializeTests";
8
8
 
@@ -38,6 +38,7 @@ describe('contentProgressDataContextLocal', function () {
38
38
  result = await getProgressState(contentId);
39
39
  expect(result).toBe("started");
40
40
  dataContext.clearCache();
41
+ await new Promise(resolve => setTimeout(resolve, 3000)); // 3 sec
41
42
 
42
43
  result = await getProgressState(contentId);
43
44
  expect(result).toBe("started");
@@ -79,6 +80,35 @@ describe('contentProgressDataContextLocal', function () {
79
80
  expect(result).toBe("");
80
81
  }, 100000);
81
82
 
83
+ test('assignmentCompleteBubblingToCompletedMultiple', async () => {
84
+ let contentId = 281709;
85
+ await contentStatusReset(contentId);
86
+
87
+ let state = await getProgressState(contentId);
88
+ expect(state).toBe("");
89
+
90
+ let assignmentIds = [281710, 281711, 281712, 281713, 281714, 281715];
91
+ for (const assignmentId of assignmentIds) {
92
+ await assignmentStatusCompleted(assignmentId, contentId);
93
+ state = await getProgressState(assignmentId);
94
+ expect(state).toBe("completed");
95
+ }
96
+
97
+ state = await getProgressState(contentId); //assignment
98
+ expect(state).toBe("completed");
99
+
100
+ dataContext.clearCache();
101
+
102
+ state = await getProgressState(contentId); //assignment
103
+ expect(state).toBe("completed");
104
+
105
+ for (const assignmentId of assignmentIds) {
106
+ state = await getProgressState(assignmentId);
107
+ expect(state).toBe("completed");
108
+ }
109
+
110
+ }, 100000);
111
+
82
112
 
83
113
  //
84
114
  // test('progressBubbling', async () => {
File without changes
package/test/log.js CHANGED
File without changes
@@ -1,5 +1,5 @@
1
1
  import {getFieldsForContentType} from "../src/contentTypeConfig";
2
- import {fetchCommentModContentData, fetchSanity} from "../src/services/sanity";
2
+ import {fetchAssignments, fetchCommentModContentData, fetchSanity} from "../src/services/sanity";
3
3
  import {log} from './log.js';
4
4
  import {initializeTestService} from "./initializeTests";
5
5
 
@@ -568,7 +568,7 @@ describe('Sanity Queries', function () {
568
568
  expect(hierarchy.parents[241250]).toBe(241249);
569
569
  expect(hierarchy.parents[241249]).toBe(241248);
570
570
  expect(hierarchy.parents[241248]).toBe(241247);
571
- expect(hierarchy.children[241250]).toStrictEqual([]);
571
+ expect(hierarchy.children[241250]).toStrictEqual([241676]);
572
572
  expect(hierarchy.children[243085]).toStrictEqual([243170, 243171, 243172, 243174, 243176]);
573
573
  });
574
574
 
@@ -581,6 +581,11 @@ describe('Sanity Queries', function () {
581
581
  expect(data[241252].title).toBe("Setting Up Your Pedals & Throne");
582
582
  });
583
583
 
584
+ test('fetchAssignments', async()=>{
585
+ let data = await fetchAssignments(241250);
586
+ expect(data).toContain(241676);
587
+ });
588
+
584
589
  });
585
590
 
586
591
  describe('Filter Builder', function () {
File without changes
File without changes