@instructure/platform-mock-canvas-api 0.4.0 → 0.5.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/dist/fixtures/index.d.ts +2 -0
- package/dist/fixtures/index.d.ts.map +1 -1
- package/dist/fixtures/modules.d.ts +124 -0
- package/dist/fixtures/modules.d.ts.map +1 -0
- package/dist/fixtures.js +160 -16
- package/dist/handlers/index.d.ts +3 -1
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/modules.d.ts +11 -0
- package/dist/handlers/modules.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +112 -44
- package/package.json +2 -2
package/dist/fixtures/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { courses } from './courses';
|
|
2
2
|
export { educatorAccessibilityCourseStatistics, mockEducatorAccessibilityStatistic, } from './educatorAccessibility';
|
|
3
|
+
export type { CanvasCompletionRequirement, CanvasContentDetails, CanvasCourseModules, CanvasModule, CanvasModuleItem, CanvasModuleItemType, } from './modules';
|
|
4
|
+
export { buildCanvasCourseModules, MODULE_ITEMS_INLINE_LIMIT, MODULES_SMALL_MODULE_COUNT, moduleScenariosByCourseId, modulesCourseEmpty, modulesCourseFatModule, modulesCourseLarge, modulesCourseSmall, } from './modules';
|
|
3
5
|
export { stickerDescriptions } from './stickerDescriptions';
|
|
4
6
|
export { stickerTranslations } from './stickerTranslations';
|
|
5
7
|
export { submissions, submissionsStore } from './submissions';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EACL,qCAAqC,EACrC,kCAAkC,GACnC,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EACL,qCAAqC,EACrC,kCAAkC,GACnC,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,2BAA2B,EAC3B,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,WAAW,CAAA;AAClB,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas REST wire shapes for the modules API.
|
|
3
|
+
*
|
|
4
|
+
* These are deliberately *not* the normalised domain model that
|
|
5
|
+
* `@instructure/platform-modules` exposes — they are what
|
|
6
|
+
* `lib/api/v1/context_module.rb` actually puts on the wire: snake_case keys,
|
|
7
|
+
* numeric ids, CamelCase item types, `quiz_lti` for new quizzes, and an
|
|
8
|
+
* `estimated_duration` that Canvas Career serialises as an ISO-8601 duration.
|
|
9
|
+
* A REST adapter that can turn these into the domain model has been proven
|
|
10
|
+
* against the real shape rather than a tidied-up one.
|
|
11
|
+
*
|
|
12
|
+
* The four scenarios are sized to match the ones in
|
|
13
|
+
* `packages/modules/src/fixtures/scenarios.ts`, so a REST run and an in-memory
|
|
14
|
+
* run are comparable. Generation is deterministic: no `Math.random()`, no
|
|
15
|
+
* `Date.now()`.
|
|
16
|
+
*
|
|
17
|
+
* The generation *rules* are deliberately not identical, and it would be wrong to
|
|
18
|
+
* claim they are: these produce Canvas's wire shape, so the student state arrives
|
|
19
|
+
* as a module-level `state` string plus a per-item `completion_requirement.completed`
|
|
20
|
+
* flag, where the domain fixtures carry an already-derived `ModuleStatus` and
|
|
21
|
+
* `ModuleItemStatus`. Turning the former into the latter is exactly the job a REST
|
|
22
|
+
* adapter has to do, so the two must not agree too early.
|
|
23
|
+
*
|
|
24
|
+
* These fixtures cannot be imported from `@instructure/platform-modules` — that
|
|
25
|
+
* package depends on this one — so the shared numbers are restated here with the
|
|
26
|
+
* reason attached rather than derived.
|
|
27
|
+
*/
|
|
28
|
+
/** Canvas's item `type` values, as sent. */
|
|
29
|
+
export type CanvasModuleItemType = 'Assignment' | 'Quiz' | 'Discussion' | 'Page' | 'File' | 'ExternalUrl' | 'ExternalTool' | 'SubHeader';
|
|
30
|
+
export interface CanvasCompletionRequirement {
|
|
31
|
+
type: string;
|
|
32
|
+
/** Sent only for `min_score` (`lib/api/v1/context_module.rb:166`). */
|
|
33
|
+
min_score?: number;
|
|
34
|
+
/** Sent only for `min_percentage` (`lib/api/v1/context_module.rb:167`). */
|
|
35
|
+
min_percentage?: number;
|
|
36
|
+
/** Per-student: whether this requirement is in `progression.requirements_met`. */
|
|
37
|
+
completed: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface CanvasContentDetails {
|
|
40
|
+
points_possible?: number;
|
|
41
|
+
due_at?: string | null;
|
|
42
|
+
unlock_at?: string | null;
|
|
43
|
+
lock_at?: string | null;
|
|
44
|
+
}
|
|
45
|
+
export interface CanvasModuleItem {
|
|
46
|
+
id: number;
|
|
47
|
+
module_id: number;
|
|
48
|
+
position: number;
|
|
49
|
+
title: string;
|
|
50
|
+
indent: number;
|
|
51
|
+
type: CanvasModuleItemType;
|
|
52
|
+
content_id?: number;
|
|
53
|
+
html_url: string;
|
|
54
|
+
url?: string;
|
|
55
|
+
page_url?: string;
|
|
56
|
+
external_url?: string;
|
|
57
|
+
new_tab?: boolean;
|
|
58
|
+
published: boolean;
|
|
59
|
+
/** Set on new quizzes, which Canvas reports as `Assignment`. */
|
|
60
|
+
quiz_lti?: boolean;
|
|
61
|
+
completion_requirement?: CanvasCompletionRequirement;
|
|
62
|
+
content_details?: CanvasContentDetails;
|
|
63
|
+
/** Canvas Career only. ISO-8601 duration, e.g. `PT25M`. */
|
|
64
|
+
estimated_duration?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface CanvasModule {
|
|
67
|
+
id: number;
|
|
68
|
+
name: string;
|
|
69
|
+
position: number;
|
|
70
|
+
unlock_at: string | null;
|
|
71
|
+
require_sequential_progress: boolean;
|
|
72
|
+
prerequisite_module_ids: number[];
|
|
73
|
+
published: boolean;
|
|
74
|
+
items_count: number;
|
|
75
|
+
items_url: string;
|
|
76
|
+
/**
|
|
77
|
+
* Present only when the module has at most `MODULE_ITEMS_INLINE_LIMIT`
|
|
78
|
+
* items. Above that Canvas omits the key entirely — see the note on the
|
|
79
|
+
* constant.
|
|
80
|
+
*/
|
|
81
|
+
items?: CanvasModuleItem[];
|
|
82
|
+
state: string;
|
|
83
|
+
completed_at: string | null;
|
|
84
|
+
publish_final_grade: boolean;
|
|
85
|
+
}
|
|
86
|
+
export interface CanvasCourseModules {
|
|
87
|
+
courseId: number;
|
|
88
|
+
modules: CanvasModule[];
|
|
89
|
+
/** Every module's items, including the ones too large to be inlined. */
|
|
90
|
+
itemsByModuleId: Record<string, CanvasModuleItem[]>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Canvas refuses to inline items for a module with more than this many
|
|
94
|
+
* (`Api::MAX_PER_PAGE`, via `lib/api/v1/context_module.rb`): the `items` key is
|
|
95
|
+
* absent from the response rather than truncated, and the client is expected
|
|
96
|
+
* to fall back to `items_url`. Mirrors `INLINE_ITEM_LIMIT` in
|
|
97
|
+
* `@instructure/platform-modules`.
|
|
98
|
+
*/
|
|
99
|
+
export declare const MODULE_ITEMS_INLINE_LIMIT = 100;
|
|
100
|
+
/** Build a course's modules from a per-module item count, e.g. `[8, 250, 8]`. */
|
|
101
|
+
export declare function buildCanvasCourseModules(courseId: number, itemCounts: readonly number[]): CanvasCourseModules;
|
|
102
|
+
/**
|
|
103
|
+
* 7 modules × 8 items. Everything inlines; the course loads in ~2 requests.
|
|
104
|
+
*
|
|
105
|
+
* Seven, matching `courseSmall` in `packages/modules` — sized to `MODULE_STATUS_CYCLE.length`
|
|
106
|
+
* so no `ModuleStatus` is silently omitted.
|
|
107
|
+
*/
|
|
108
|
+
export declare const MODULES_SMALL_MODULE_COUNT = 7;
|
|
109
|
+
export declare function modulesCourseSmall(): CanvasCourseModules;
|
|
110
|
+
/** 120 modules × 25 items. Forces module-list pagination past `per_page=100`. */
|
|
111
|
+
export declare function modulesCourseLarge(): CanvasCourseModules;
|
|
112
|
+
/** 3 modules, the middle one 250 items — that module ships with no `items` key. */
|
|
113
|
+
export declare function modulesCourseFatModule(): CanvasCourseModules;
|
|
114
|
+
/** No modules. The empty state, on the wire. */
|
|
115
|
+
export declare function modulesCourseEmpty(): CanvasCourseModules;
|
|
116
|
+
/**
|
|
117
|
+
* Which scenario each course id serves. The ids line up with the `courses`
|
|
118
|
+
* fixture, so `GET /api/v1/courses/2/modules` is the 120-module course.
|
|
119
|
+
*
|
|
120
|
+
* Builders rather than values: `modulesCourseLarge()` is 3,000 item objects
|
|
121
|
+
* and nothing should pay for it at import time.
|
|
122
|
+
*/
|
|
123
|
+
export declare const moduleScenariosByCourseId: Record<string, () => CanvasCourseModules>;
|
|
124
|
+
//# sourceMappingURL=modules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../src/fixtures/modules.ts"],"names":[],"mappings":"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"}
|
package/dist/fixtures.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const I = [
|
|
2
2
|
{
|
|
3
3
|
id: "1",
|
|
4
4
|
uuid: "WvAU2cWNVZjm0Dup4i36bSusZ4UReXfNVhBjxooC",
|
|
@@ -39,7 +39,7 @@ const i = [
|
|
|
39
39
|
enrollment_term_id: "2",
|
|
40
40
|
term: { id: "2", name: "Spring 2025" }
|
|
41
41
|
}
|
|
42
|
-
],
|
|
42
|
+
], D = (s = {}) => ({
|
|
43
43
|
id: 1,
|
|
44
44
|
course_id: 101,
|
|
45
45
|
course_name: "Introduction to Biology",
|
|
@@ -51,8 +51,8 @@ const i = [
|
|
|
51
51
|
workflow_state: "active",
|
|
52
52
|
created_at: "2026-01-01T00:00:00Z",
|
|
53
53
|
updated_at: "2026-01-02T00:00:00Z",
|
|
54
|
-
...
|
|
55
|
-
}),
|
|
54
|
+
...s
|
|
55
|
+
}), L = [
|
|
56
56
|
{
|
|
57
57
|
id: 1,
|
|
58
58
|
course_id: 101,
|
|
@@ -92,7 +92,143 @@ const i = [
|
|
|
92
92
|
course_code: "CHM301",
|
|
93
93
|
published: !1
|
|
94
94
|
}
|
|
95
|
-
],
|
|
95
|
+
], k = 100, u = [
|
|
96
|
+
"assignment",
|
|
97
|
+
"quiz",
|
|
98
|
+
"discussion",
|
|
99
|
+
"page",
|
|
100
|
+
"file",
|
|
101
|
+
"external_url",
|
|
102
|
+
"external_tool",
|
|
103
|
+
"sub_header"
|
|
104
|
+
], _ = [
|
|
105
|
+
"must_view",
|
|
106
|
+
"must_submit",
|
|
107
|
+
"must_contribute",
|
|
108
|
+
"must_mark_done",
|
|
109
|
+
"min_score",
|
|
110
|
+
"min_percentage"
|
|
111
|
+
], f = ["assignment", "quiz", "discussion"], g = Date.UTC(2025, 0, 6), w = 864e5, l = (s) => new Date(g + s * w).toISOString(), m = ["unlocked", "started", "completed", "locked"], h = (s) => m[(s - 1) % m.length], A = (s, e) => {
|
|
112
|
+
const i = _[Math.floor(s / 3) % _.length], a = h(e), t = a === "completed" || a === "started" && s % 2 === 0;
|
|
113
|
+
return i === "min_score" ? { type: i, min_score: 10, completed: t } : i === "min_percentage" ? { type: i, min_percentage: 80, completed: t } : { type: i, completed: t };
|
|
114
|
+
}, b = (s, e, i, a) => {
|
|
115
|
+
const t = i + 5e4;
|
|
116
|
+
switch (s) {
|
|
117
|
+
case "assignment":
|
|
118
|
+
return {
|
|
119
|
+
type: "Assignment",
|
|
120
|
+
content_id: t,
|
|
121
|
+
url: `/api/v1/courses/${e}/assignments/${t}`
|
|
122
|
+
};
|
|
123
|
+
case "quiz":
|
|
124
|
+
return Math.floor(a / u.length) % 2 === 0 ? {
|
|
125
|
+
type: "Quiz",
|
|
126
|
+
content_id: t,
|
|
127
|
+
url: `/api/v1/courses/${e}/quizzes/${t}`
|
|
128
|
+
} : {
|
|
129
|
+
type: "Assignment",
|
|
130
|
+
quiz_lti: !0,
|
|
131
|
+
content_id: t,
|
|
132
|
+
url: `/api/v1/courses/${e}/assignments/${t}`
|
|
133
|
+
};
|
|
134
|
+
case "discussion":
|
|
135
|
+
return {
|
|
136
|
+
type: "Discussion",
|
|
137
|
+
content_id: t,
|
|
138
|
+
url: `/api/v1/courses/${e}/discussion_topics/${t}`
|
|
139
|
+
};
|
|
140
|
+
case "page":
|
|
141
|
+
return {
|
|
142
|
+
type: "Page",
|
|
143
|
+
page_url: `page-${i}`,
|
|
144
|
+
url: `/api/v1/courses/${e}/pages/page-${i}`
|
|
145
|
+
};
|
|
146
|
+
case "file":
|
|
147
|
+
return { type: "File", content_id: t, url: `/api/v1/files/${t}` };
|
|
148
|
+
case "external_url":
|
|
149
|
+
return {
|
|
150
|
+
type: "ExternalUrl",
|
|
151
|
+
external_url: `https://example.com/resource/${i}`,
|
|
152
|
+
new_tab: !0
|
|
153
|
+
};
|
|
154
|
+
case "external_tool":
|
|
155
|
+
return {
|
|
156
|
+
type: "ExternalTool",
|
|
157
|
+
content_id: t,
|
|
158
|
+
external_url: `https://lti.example.com/launch/${i}`,
|
|
159
|
+
new_tab: !1
|
|
160
|
+
};
|
|
161
|
+
case "sub_header":
|
|
162
|
+
return { type: "SubHeader" };
|
|
163
|
+
}
|
|
164
|
+
}, y = (s, e, i, a) => {
|
|
165
|
+
const t = u[a % u.length], o = e * 1e3 + i + 1, n = t === "sub_header", r = {
|
|
166
|
+
id: o,
|
|
167
|
+
module_id: e,
|
|
168
|
+
position: i + 1,
|
|
169
|
+
title: `${t} ${i + 1}`,
|
|
170
|
+
indent: i % 5 === 4 ? 1 : 0,
|
|
171
|
+
html_url: `/courses/${s}/modules/items/${o}`,
|
|
172
|
+
published: a % 7 !== 0,
|
|
173
|
+
...b(t, s, o, a)
|
|
174
|
+
};
|
|
175
|
+
return a % 3 === 0 && !n && (r.completion_requirement = A(a, e)), f.includes(t) && a % 4 === 0 && (r.content_details = { points_possible: 10 + a % 5 * 5, due_at: l(a % 90) }), a % 37 === 0 && (r.estimated_duration = `PT${5 + a % 4 * 10}M`), r;
|
|
176
|
+
}, S = (s, e, i) => {
|
|
177
|
+
const a = h(e), t = {
|
|
178
|
+
id: e,
|
|
179
|
+
name: `Module ${e}`,
|
|
180
|
+
position: e,
|
|
181
|
+
unlock_at: e % 5 === 0 ? l(e) : null,
|
|
182
|
+
require_sequential_progress: e % 6 === 0,
|
|
183
|
+
prerequisite_module_ids: e > 1 && e % 3 === 0 ? [e - 1] : [],
|
|
184
|
+
published: e % 4 !== 0,
|
|
185
|
+
// `items_count` is the true total, whether or not the items are inlined.
|
|
186
|
+
items_count: i.length,
|
|
187
|
+
items_url: `/api/v1/courses/${s}/modules/${e}/items`,
|
|
188
|
+
state: a,
|
|
189
|
+
// Canvas sets `completed_at` only on a completed progression
|
|
190
|
+
// (`app/models/context_module_progression.rb:57-61`).
|
|
191
|
+
completed_at: a === "completed" ? l(e + 30) : null,
|
|
192
|
+
publish_final_grade: !1
|
|
193
|
+
};
|
|
194
|
+
return i.length <= k && (t.items = i), t;
|
|
195
|
+
};
|
|
196
|
+
function c(s, e) {
|
|
197
|
+
const i = [], a = {};
|
|
198
|
+
let t = 0;
|
|
199
|
+
return e.forEach((o, n) => {
|
|
200
|
+
const r = n + 1, p = Array.from(
|
|
201
|
+
{ length: o },
|
|
202
|
+
(Z, d) => y(s, r, d, t + d)
|
|
203
|
+
);
|
|
204
|
+
t += o, i.push(S(s, r, p)), a[String(r)] = p;
|
|
205
|
+
}), { courseId: s, modules: i, itemsByModuleId: a };
|
|
206
|
+
}
|
|
207
|
+
const T = 7;
|
|
208
|
+
function v() {
|
|
209
|
+
return c(
|
|
210
|
+
1,
|
|
211
|
+
Array.from({ length: T }, () => 8)
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
function E() {
|
|
215
|
+
return c(
|
|
216
|
+
2,
|
|
217
|
+
Array.from({ length: 120 }, () => 25)
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
function C() {
|
|
221
|
+
return c(3, [8, 250, 8]);
|
|
222
|
+
}
|
|
223
|
+
function M() {
|
|
224
|
+
return c(4, []);
|
|
225
|
+
}
|
|
226
|
+
const O = {
|
|
227
|
+
1: v,
|
|
228
|
+
2: E,
|
|
229
|
+
3: C,
|
|
230
|
+
4: M
|
|
231
|
+
}, B = {
|
|
96
232
|
default: "A placeholder sticker with a smiley face and a plus sign.",
|
|
97
233
|
star: "A sticker with a picture of a smiling star.",
|
|
98
234
|
trophy: "A sticker with a picture of a golden trophy.",
|
|
@@ -144,13 +280,13 @@ const i = [
|
|
|
144
280
|
tag: "A sticker with a picture of a clip-on identification tag.",
|
|
145
281
|
presentation: "A sticker with a picture of a projector screen with presentation content on it.",
|
|
146
282
|
column: "A sticker with a picture of a roman column."
|
|
147
|
-
},
|
|
283
|
+
}, x = {
|
|
148
284
|
chooseASticker: "Choose a sticker",
|
|
149
285
|
close: "Close",
|
|
150
286
|
removeSticker: "Remove sticker",
|
|
151
287
|
removedSticker: "Removed sticker",
|
|
152
288
|
selectedSticker: "Selected sticker"
|
|
153
|
-
},
|
|
289
|
+
}, $ = [
|
|
154
290
|
{
|
|
155
291
|
id: "1",
|
|
156
292
|
course_id: "1",
|
|
@@ -199,15 +335,23 @@ const i = [
|
|
|
199
335
|
grade: "A+",
|
|
200
336
|
score: 98
|
|
201
337
|
}
|
|
202
|
-
],
|
|
203
|
-
|
|
338
|
+
], q = new Map(
|
|
339
|
+
$.map((s) => [s.id, { ...s }])
|
|
204
340
|
);
|
|
205
341
|
export {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
342
|
+
T as MODULES_SMALL_MODULE_COUNT,
|
|
343
|
+
k as MODULE_ITEMS_INLINE_LIMIT,
|
|
344
|
+
c as buildCanvasCourseModules,
|
|
345
|
+
I as courses,
|
|
346
|
+
L as educatorAccessibilityCourseStatistics,
|
|
347
|
+
D as mockEducatorAccessibilityStatistic,
|
|
348
|
+
O as moduleScenariosByCourseId,
|
|
349
|
+
M as modulesCourseEmpty,
|
|
350
|
+
C as modulesCourseFatModule,
|
|
351
|
+
E as modulesCourseLarge,
|
|
352
|
+
v as modulesCourseSmall,
|
|
353
|
+
B as stickerDescriptions,
|
|
354
|
+
x as stickerTranslations,
|
|
355
|
+
$ as submissions,
|
|
356
|
+
q as submissionsStore
|
|
213
357
|
};
|
package/dist/handlers/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { RequestHandler } from 'msw';
|
|
2
2
|
import { courseHandlers } from './courses';
|
|
3
3
|
import { educatorAccessibilityHandlers } from './educatorAccessibility';
|
|
4
|
+
import { moduleHandlers } from './modules';
|
|
4
5
|
import { submissionHandlers } from './submissions';
|
|
5
6
|
import { userColorHandlers } from './userColors';
|
|
6
7
|
export declare const handlers: RequestHandler[];
|
|
7
|
-
export { courseHandlers, educatorAccessibilityHandlers, submissionHandlers, userColorHandlers };
|
|
8
|
+
export { courseHandlers, educatorAccessibilityHandlers, moduleHandlers, submissionHandlers, userColorHandlers, };
|
|
9
|
+
export { buildLinkHeader, resetModuleScenarios } from './modules';
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAA;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD,eAAO,MAAM,QAAQ,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAA;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD,eAAO,MAAM,QAAQ,EAAE,cAAc,EAMpC,CAAA;AAED,OAAO,EACL,cAAc,EACd,6BAA6B,EAC7B,cAAc,EACd,kBAAkB,EAClB,iBAAiB,GAClB,CAAA;AACD,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RequestHandler } from 'msw';
|
|
2
|
+
/** Drops any cached scenario, so a test can start from a clean fixture. */
|
|
3
|
+
export declare function resetModuleScenarios(): void;
|
|
4
|
+
/**
|
|
5
|
+
* An RFC-5988 `Link` header in Canvas's order: current, next, prev, first,
|
|
6
|
+
* last. `next` is absent on the final page — that absence is the only signal a
|
|
7
|
+
* client gets that it has reached the end.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildLinkHeader(url: URL, page: number, perPage: number, totalCount: number): string;
|
|
10
|
+
export declare const moduleHandlers: RequestHandler[];
|
|
11
|
+
//# sourceMappingURL=modules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../src/handlers/modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAA;AAmDzC,2EAA2E;AAC3E,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAgCD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,MAAM,CAQR;AASD,eAAO,MAAM,cAAc,EAAE,cAAc,EAuC1C,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export * from './fixtures';
|
|
2
|
-
export { courseHandlers, educatorAccessibilityHandlers, handlers, submissionHandlers, userColorHandlers, } from './handlers';
|
|
2
|
+
export { buildLinkHeader, courseHandlers, educatorAccessibilityHandlers, handlers, moduleHandlers, resetModuleScenarios, submissionHandlers, userColorHandlers, } from './handlers';
|
|
3
3
|
export type * from './types';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,OAAO,EACL,cAAc,EACd,6BAA6B,EAC7B,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,YAAY,CAAA;AACnB,mBAAmB,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,OAAO,EACL,eAAe,EACf,cAAc,EACd,6BAA6B,EAC7B,QAAQ,EACR,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,YAAY,CAAA;AACnB,mBAAmB,SAAS,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,70 +1,138 @@
|
|
|
1
|
-
import { courses as
|
|
2
|
-
import { mockEducatorAccessibilityStatistic as
|
|
3
|
-
import { http as
|
|
4
|
-
const
|
|
1
|
+
import { courses as I, educatorAccessibilityCourseStatistics as _, moduleScenariosByCourseId as S, submissionsStore as m } from "./fixtures.js";
|
|
2
|
+
import { MODULES_SMALL_MODULE_COUNT as F, MODULE_ITEMS_INLINE_LIMIT as R, buildCanvasCourseModules as O, mockEducatorAccessibilityStatistic as B, modulesCourseEmpty as G, modulesCourseFatModule as $, modulesCourseLarge as K, modulesCourseSmall as X, stickerDescriptions as Y, stickerTranslations as q, submissions as z } from "./fixtures.js";
|
|
3
|
+
import { http as u, HttpResponse as r } from "msw";
|
|
4
|
+
const j = [
|
|
5
5
|
// GET /api/v1/courses
|
|
6
|
-
|
|
6
|
+
u.get("/api/v1/courses", () => r.json(I)),
|
|
7
7
|
// GET /api/v1/courses/:courseId (courseId may be a numeric id or a `uuid:<uuid>` ref)
|
|
8
|
-
|
|
9
|
-
const s = String(e.courseId).replace(/^uuid:/, ""),
|
|
10
|
-
return
|
|
8
|
+
u.get("/api/v1/courses/:courseId", ({ params: e }) => {
|
|
9
|
+
const s = String(e.courseId).replace(/^uuid:/, ""), n = I.find((t) => t.id === s || t.uuid === s);
|
|
10
|
+
return n ? r.json(n) : r.json({ errors: [{ message: "Course not found" }] }, { status: 404 });
|
|
11
11
|
})
|
|
12
|
-
],
|
|
13
|
-
|
|
14
|
-
],
|
|
12
|
+
], P = [
|
|
13
|
+
u.get("/api/v1/users/:userId/educator_accessibility_course_statistics", () => r.json(_))
|
|
14
|
+
], M = 10, k = 100, l = () => r.json(
|
|
15
|
+
{ errors: [{ message: "The specified resource does not exist." }] },
|
|
16
|
+
{
|
|
17
|
+
status: 404
|
|
18
|
+
}
|
|
19
|
+
), g = /* @__PURE__ */ new Map(), b = (e) => {
|
|
20
|
+
const s = g.get(e);
|
|
21
|
+
if (s) return s;
|
|
22
|
+
const n = S[e];
|
|
23
|
+
if (!n) return;
|
|
24
|
+
const t = n();
|
|
25
|
+
return g.set(e, t), t;
|
|
26
|
+
};
|
|
27
|
+
function H() {
|
|
28
|
+
g.clear();
|
|
29
|
+
}
|
|
30
|
+
const f = (e) => {
|
|
31
|
+
const s = Number.parseInt(e.searchParams.get("per_page") ?? "", 10), n = Number.parseInt(e.searchParams.get("page") ?? "", 10);
|
|
32
|
+
return {
|
|
33
|
+
perPage: Number.isFinite(s) && s > 0 ? Math.min(s, k) : M,
|
|
34
|
+
page: Number.isFinite(n) && n > 0 ? n : 1
|
|
35
|
+
};
|
|
36
|
+
}, v = (e) => [...e.searchParams.getAll("include[]"), ...e.searchParams.getAll("include")].flatMap(
|
|
37
|
+
(s) => s.split(",")
|
|
38
|
+
), y = (e, s, n) => {
|
|
39
|
+
const t = new URL(e.href);
|
|
40
|
+
return t.searchParams.set("page", String(s)), t.searchParams.set("per_page", String(n)), t.href;
|
|
41
|
+
};
|
|
42
|
+
function h(e, s, n, t) {
|
|
43
|
+
const o = Math.max(1, Math.ceil(t / n)), i = [["current", s]];
|
|
44
|
+
return s < o && i.push(["next", s + 1]), s > 1 && i.push(["prev", s - 1]), i.push(["first", 1], ["last", o]), i.map(([a, c]) => `<${y(e, c, n)}>; rel="${a}"`).join(",");
|
|
45
|
+
}
|
|
46
|
+
const L = (e) => {
|
|
47
|
+
const s = { ...e };
|
|
48
|
+
return delete s.items, s;
|
|
49
|
+
}, A = [
|
|
50
|
+
// GET /api/v1/courses/:courseId/modules
|
|
51
|
+
u.get("/api/v1/courses/:courseId/modules", ({ params: e, request: s }) => {
|
|
52
|
+
const n = b(String(e.courseId));
|
|
53
|
+
if (!n) return l();
|
|
54
|
+
const t = new URL(s.url), { page: o, perPage: i } = f(t), a = v(t).includes("items"), c = (o - 1) * i, d = n.modules.slice(c, c + i).map((p) => a ? p : L(p));
|
|
55
|
+
return r.json(d, {
|
|
56
|
+
headers: { Link: h(t, o, i, n.modules.length) }
|
|
57
|
+
});
|
|
58
|
+
}),
|
|
59
|
+
// GET /api/v1/courses/:courseId/modules/:moduleId/items
|
|
60
|
+
u.get("/api/v1/courses/:courseId/modules/:moduleId/items", ({ params: e, request: s }) => {
|
|
61
|
+
const n = b(String(e.courseId));
|
|
62
|
+
if (!n) return l();
|
|
63
|
+
const t = String(e.moduleId), o = n.itemsByModuleId[t];
|
|
64
|
+
if (!o) return l();
|
|
65
|
+
const i = new URL(s.url), { page: a, perPage: c } = f(i), d = (a - 1) * c;
|
|
66
|
+
return r.json(o.slice(d, d + c), {
|
|
67
|
+
headers: { Link: h(i, a, c, o.length) }
|
|
68
|
+
});
|
|
69
|
+
})
|
|
70
|
+
], C = 300, E = [
|
|
15
71
|
// GET submission
|
|
16
|
-
|
|
72
|
+
u.get(
|
|
17
73
|
"/api/v1/courses/:courseId/assignments/:assignmentId/submissions/:submissionId",
|
|
18
74
|
({ params: e }) => {
|
|
19
|
-
const s =
|
|
20
|
-
return s ?
|
|
75
|
+
const s = m.get(e.submissionId);
|
|
76
|
+
return s ? r.json(s) : r.json({ errors: [{ message: "Submission not found" }] }, { status: 404 });
|
|
21
77
|
}
|
|
22
78
|
),
|
|
23
79
|
// PATCH submission (update sticker)
|
|
24
|
-
|
|
80
|
+
u.patch(
|
|
25
81
|
"/api/v1/courses/:courseId/assignments/:assignmentId/submissions/:submissionId",
|
|
26
82
|
async ({ params: e, request: s }) => {
|
|
27
|
-
const { submissionId:
|
|
28
|
-
return
|
|
83
|
+
const { submissionId: n } = e, t = await s.json(), o = m.get(n);
|
|
84
|
+
return o ? (t.submission && "sticker" in t.submission && t.submission.sticker !== void 0 && (o.sticker = t.submission.sticker, m.set(n, o)), await new Promise((i) => setTimeout(i, C)), r.json(o)) : r.json({ errors: [{ message: "Submission not found" }] }, { status: 404 });
|
|
29
85
|
}
|
|
30
86
|
),
|
|
31
87
|
// GET all submissions for an assignment
|
|
32
|
-
|
|
33
|
-
const s = Array.from(
|
|
34
|
-
(
|
|
88
|
+
u.get("/api/v1/courses/:courseId/assignments/:assignmentId/submissions", ({ params: e }) => {
|
|
89
|
+
const s = Array.from(m.values()).filter(
|
|
90
|
+
(n) => n.course_id === e.courseId && n.assignment_id === e.assignmentId
|
|
35
91
|
);
|
|
36
|
-
return
|
|
92
|
+
return r.json(s);
|
|
37
93
|
})
|
|
38
|
-
],
|
|
94
|
+
], w = [
|
|
39
95
|
// PUT /api/v1/users/:userId/colors/:assetString -> persist a course color
|
|
40
|
-
|
|
96
|
+
u.put("/api/v1/users/:userId/colors/:assetString", async ({ request: e }) => {
|
|
41
97
|
const s = await e.json().catch(() => ({}));
|
|
42
|
-
return
|
|
98
|
+
return r.json({ hexcode: s.hexcode ?? "" });
|
|
43
99
|
}),
|
|
44
100
|
// PUT /api/v1/users/self/course_nicknames/:courseId -> set a nickname
|
|
45
|
-
|
|
101
|
+
u.put("/api/v1/users/self/course_nicknames/:courseId", async ({ request: e }) => {
|
|
46
102
|
const s = await e.json().catch(() => ({}));
|
|
47
|
-
return
|
|
103
|
+
return r.json({ nickname: s.nickname ?? "", name: s.nickname ?? "" });
|
|
48
104
|
}),
|
|
49
105
|
// DELETE /api/v1/users/self/course_nicknames/:courseId -> clear a nickname
|
|
50
|
-
|
|
51
|
-
],
|
|
52
|
-
...
|
|
53
|
-
...
|
|
54
|
-
...
|
|
55
|
-
...
|
|
106
|
+
u.delete("/api/v1/users/self/course_nicknames/:courseId", () => r.json({ nickname: null, name: "" }))
|
|
107
|
+
], N = [
|
|
108
|
+
...j,
|
|
109
|
+
...P,
|
|
110
|
+
...A,
|
|
111
|
+
...E,
|
|
112
|
+
...w
|
|
56
113
|
];
|
|
57
114
|
export {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
j as
|
|
63
|
-
|
|
64
|
-
_ as
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
115
|
+
F as MODULES_SMALL_MODULE_COUNT,
|
|
116
|
+
R as MODULE_ITEMS_INLINE_LIMIT,
|
|
117
|
+
O as buildCanvasCourseModules,
|
|
118
|
+
h as buildLinkHeader,
|
|
119
|
+
j as courseHandlers,
|
|
120
|
+
I as courses,
|
|
121
|
+
_ as educatorAccessibilityCourseStatistics,
|
|
122
|
+
P as educatorAccessibilityHandlers,
|
|
123
|
+
N as handlers,
|
|
124
|
+
B as mockEducatorAccessibilityStatistic,
|
|
125
|
+
A as moduleHandlers,
|
|
126
|
+
S as moduleScenariosByCourseId,
|
|
127
|
+
G as modulesCourseEmpty,
|
|
128
|
+
$ as modulesCourseFatModule,
|
|
129
|
+
K as modulesCourseLarge,
|
|
130
|
+
X as modulesCourseSmall,
|
|
131
|
+
H as resetModuleScenarios,
|
|
132
|
+
Y as stickerDescriptions,
|
|
133
|
+
q as stickerTranslations,
|
|
134
|
+
E as submissionHandlers,
|
|
135
|
+
z as submissions,
|
|
136
|
+
m as submissionsStore,
|
|
137
|
+
w as userColorHandlers
|
|
70
138
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@instructure/platform-mock-canvas-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"./fixtures": {
|
|
14
14
|
"types": "./dist/fixtures/index.d.ts",
|
|
15
|
-
"import": "./dist/fixtures
|
|
15
|
+
"import": "./dist/fixtures.js"
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"files": [
|