gogcli-mcp 2.0.0 → 2.0.2
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/README.md +3 -0
- package/dist/index.js +864 -8
- package/dist/lib.js +866 -8
- package/manifest.json +229 -1
- package/package.json +18 -1
- package/src/lib.ts +2 -0
- package/src/server.ts +10 -1
- package/src/tools/classroom.ts +696 -0
- package/src/tools/drive.ts +17 -6
- package/src/tools/slides.ts +203 -0
- package/src/tools/utils.ts +9 -1
- package/tests/runner.test.ts +16 -0
- package/tests/server.test.ts +43 -0
- package/tests/tools/classroom.test.ts +875 -0
- package/tests/tools/drive.test.ts +49 -3
- package/tests/tools/slides.test.ts +441 -0
- package/tests/tools/utils.test.ts +65 -0
|
@@ -0,0 +1,875 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { registerClassroomTools } from '../../src/tools/classroom.js';
|
|
4
|
+
import * as runner from '../../src/runner.js';
|
|
5
|
+
|
|
6
|
+
vi.mock('../../src/runner.js');
|
|
7
|
+
|
|
8
|
+
type ToolHandler = (args: Record<string, unknown>) => Promise<{ content: Array<{ type: string; text: string }> }>;
|
|
9
|
+
|
|
10
|
+
function setupHandlers(): Map<string, ToolHandler> {
|
|
11
|
+
const server = new McpServer({ name: 'test', version: '0.0.0' });
|
|
12
|
+
const handlers = new Map<string, ToolHandler>();
|
|
13
|
+
vi.spyOn(server, 'registerTool').mockImplementation((name, _config, cb) => {
|
|
14
|
+
handlers.set(name, cb as ToolHandler);
|
|
15
|
+
return undefined as never;
|
|
16
|
+
});
|
|
17
|
+
registerClassroomTools(server);
|
|
18
|
+
return handlers;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let handlers: Map<string, ToolHandler>;
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
vi.clearAllMocks();
|
|
25
|
+
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
26
|
+
handlers = setupHandlers();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('gog_classroom_courses_list', () => {
|
|
30
|
+
it('calls run with no flags', async () => {
|
|
31
|
+
await handlers.get('gog_classroom_courses_list')!({});
|
|
32
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'courses', 'list'], { account: undefined });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('passes all listing flags', async () => {
|
|
36
|
+
await handlers.get('gog_classroom_courses_list')!({
|
|
37
|
+
state: 'ACTIVE,ARCHIVED',
|
|
38
|
+
teacher: 'teacher1',
|
|
39
|
+
student: 'student1',
|
|
40
|
+
max: 50,
|
|
41
|
+
page: 'tok',
|
|
42
|
+
all: true,
|
|
43
|
+
});
|
|
44
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
45
|
+
['classroom', 'courses', 'list', '--state=ACTIVE,ARCHIVED', '--teacher=teacher1', '--student=student1', '--max=50', '--page=tok', '--all'],
|
|
46
|
+
{ account: undefined },
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('omits --all when false', async () => {
|
|
51
|
+
await handlers.get('gog_classroom_courses_list')!({ all: false });
|
|
52
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'courses', 'list'], { account: undefined });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('returns error text on failure', async () => {
|
|
56
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('List failed'));
|
|
57
|
+
const result = await handlers.get('gog_classroom_courses_list')!({});
|
|
58
|
+
expect(result.content[0].text).toBe('Error: List failed');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('gog_classroom_courses_get', () => {
|
|
63
|
+
it('calls run with courseId', async () => {
|
|
64
|
+
await handlers.get('gog_classroom_courses_get')!({ courseId: 'c1' });
|
|
65
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'courses', 'get', 'c1'], { account: undefined });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('returns error text on failure', async () => {
|
|
69
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
|
|
70
|
+
const result = await handlers.get('gog_classroom_courses_get')!({ courseId: 'bad' });
|
|
71
|
+
expect(result.content[0].text).toBe('Error: Not found');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('gog_classroom_courses_create', () => {
|
|
76
|
+
it('calls run with required name only', async () => {
|
|
77
|
+
await handlers.get('gog_classroom_courses_create')!({ name: 'Math 101' });
|
|
78
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
79
|
+
['classroom', 'courses', 'create', '--name=Math 101'],
|
|
80
|
+
{ account: undefined },
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('passes all optional flags', async () => {
|
|
85
|
+
await handlers.get('gog_classroom_courses_create')!({
|
|
86
|
+
name: 'Math 101',
|
|
87
|
+
owner: 'me',
|
|
88
|
+
section: 'Section A',
|
|
89
|
+
descriptionHeading: 'Welcome',
|
|
90
|
+
description: 'Algebra',
|
|
91
|
+
room: 'R101',
|
|
92
|
+
state: 'ACTIVE',
|
|
93
|
+
});
|
|
94
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
95
|
+
['classroom', 'courses', 'create', '--name=Math 101', '--owner=me', '--section=Section A', '--description-heading=Welcome', '--description=Algebra', '--room=R101', '--state=ACTIVE'],
|
|
96
|
+
{ account: undefined },
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('returns error text on failure', async () => {
|
|
101
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Create failed'));
|
|
102
|
+
const result = await handlers.get('gog_classroom_courses_create')!({ name: 'X' });
|
|
103
|
+
expect(result.content[0].text).toBe('Error: Create failed');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe('gog_classroom_courses_update', () => {
|
|
108
|
+
it('calls run with courseId only', async () => {
|
|
109
|
+
await handlers.get('gog_classroom_courses_update')!({ courseId: 'c1' });
|
|
110
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'courses', 'update', 'c1'], { account: undefined });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('passes all optional flags', async () => {
|
|
114
|
+
await handlers.get('gog_classroom_courses_update')!({
|
|
115
|
+
courseId: 'c1',
|
|
116
|
+
name: 'New Name',
|
|
117
|
+
owner: 'me',
|
|
118
|
+
section: 'B',
|
|
119
|
+
descriptionHeading: 'Heading',
|
|
120
|
+
description: 'Desc',
|
|
121
|
+
room: 'R2',
|
|
122
|
+
state: 'ARCHIVED',
|
|
123
|
+
});
|
|
124
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
125
|
+
['classroom', 'courses', 'update', 'c1', '--name=New Name', '--owner=me', '--section=B', '--description-heading=Heading', '--description=Desc', '--room=R2', '--state=ARCHIVED'],
|
|
126
|
+
{ account: undefined },
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('returns error text on failure', async () => {
|
|
131
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Update failed'));
|
|
132
|
+
const result = await handlers.get('gog_classroom_courses_update')!({ courseId: 'bad' });
|
|
133
|
+
expect(result.content[0].text).toBe('Error: Update failed');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('gog_classroom_courses_delete', () => {
|
|
138
|
+
it('calls run with courseId', async () => {
|
|
139
|
+
await handlers.get('gog_classroom_courses_delete')!({ courseId: 'c1' });
|
|
140
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'courses', 'delete', 'c1'], { account: undefined });
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('returns error text on failure', async () => {
|
|
144
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Delete failed'));
|
|
145
|
+
const result = await handlers.get('gog_classroom_courses_delete')!({ courseId: 'bad' });
|
|
146
|
+
expect(result.content[0].text).toBe('Error: Delete failed');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('gog_classroom_courses_archive', () => {
|
|
151
|
+
it('calls run with courseId', async () => {
|
|
152
|
+
await handlers.get('gog_classroom_courses_archive')!({ courseId: 'c1' });
|
|
153
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'courses', 'archive', 'c1'], { account: undefined });
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('returns error text on failure', async () => {
|
|
157
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Archive failed'));
|
|
158
|
+
const result = await handlers.get('gog_classroom_courses_archive')!({ courseId: 'x' });
|
|
159
|
+
expect(result.content[0].text).toBe('Error: Archive failed');
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe('gog_classroom_courses_unarchive', () => {
|
|
164
|
+
it('calls run with courseId', async () => {
|
|
165
|
+
await handlers.get('gog_classroom_courses_unarchive')!({ courseId: 'c1' });
|
|
166
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'courses', 'unarchive', 'c1'], { account: undefined });
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('returns error text on failure', async () => {
|
|
170
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Unarchive failed'));
|
|
171
|
+
const result = await handlers.get('gog_classroom_courses_unarchive')!({ courseId: 'x' });
|
|
172
|
+
expect(result.content[0].text).toBe('Error: Unarchive failed');
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('gog_classroom_students_list', () => {
|
|
177
|
+
it('calls run with courseId only', async () => {
|
|
178
|
+
await handlers.get('gog_classroom_students_list')!({ courseId: 'c1' });
|
|
179
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'students', 'list', 'c1'], { account: undefined });
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('passes all listing flags', async () => {
|
|
183
|
+
await handlers.get('gog_classroom_students_list')!({ courseId: 'c1', max: 20, page: 'tok', all: true });
|
|
184
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
185
|
+
['classroom', 'students', 'list', 'c1', '--max=20', '--page=tok', '--all'],
|
|
186
|
+
{ account: undefined },
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('omits --all when false', async () => {
|
|
191
|
+
await handlers.get('gog_classroom_students_list')!({ courseId: 'c1', all: false });
|
|
192
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'students', 'list', 'c1'], { account: undefined });
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('returns error text on failure', async () => {
|
|
196
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('List failed'));
|
|
197
|
+
const result = await handlers.get('gog_classroom_students_list')!({ courseId: 'c1' });
|
|
198
|
+
expect(result.content[0].text).toBe('Error: List failed');
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
describe('gog_classroom_students_get', () => {
|
|
203
|
+
it('calls run with courseId and userId', async () => {
|
|
204
|
+
await handlers.get('gog_classroom_students_get')!({ courseId: 'c1', userId: 'u1' });
|
|
205
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'students', 'get', 'c1', 'u1'], { account: undefined });
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('returns error text on failure', async () => {
|
|
209
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
|
|
210
|
+
const result = await handlers.get('gog_classroom_students_get')!({ courseId: 'c1', userId: 'bad' });
|
|
211
|
+
expect(result.content[0].text).toBe('Error: Not found');
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('gog_classroom_students_add', () => {
|
|
216
|
+
it('calls run with courseId and userId', async () => {
|
|
217
|
+
await handlers.get('gog_classroom_students_add')!({ courseId: 'c1', userId: 'u1' });
|
|
218
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'students', 'add', 'c1', 'u1'], { account: undefined });
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('passes --enrollment-code when provided', async () => {
|
|
222
|
+
await handlers.get('gog_classroom_students_add')!({ courseId: 'c1', userId: 'u1', enrollmentCode: 'abc123' });
|
|
223
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
224
|
+
['classroom', 'students', 'add', 'c1', 'u1', '--enrollment-code=abc123'],
|
|
225
|
+
{ account: undefined },
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('returns error text on failure', async () => {
|
|
230
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Add failed'));
|
|
231
|
+
const result = await handlers.get('gog_classroom_students_add')!({ courseId: 'c1', userId: 'u1' });
|
|
232
|
+
expect(result.content[0].text).toBe('Error: Add failed');
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('gog_classroom_students_remove', () => {
|
|
237
|
+
it('calls run with courseId and userId', async () => {
|
|
238
|
+
await handlers.get('gog_classroom_students_remove')!({ courseId: 'c1', userId: 'u1' });
|
|
239
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'students', 'remove', 'c1', 'u1'], { account: undefined });
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('returns error text on failure', async () => {
|
|
243
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Remove failed'));
|
|
244
|
+
const result = await handlers.get('gog_classroom_students_remove')!({ courseId: 'c1', userId: 'u1' });
|
|
245
|
+
expect(result.content[0].text).toBe('Error: Remove failed');
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
describe('gog_classroom_teachers_list', () => {
|
|
250
|
+
it('calls run with courseId only', async () => {
|
|
251
|
+
await handlers.get('gog_classroom_teachers_list')!({ courseId: 'c1' });
|
|
252
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'teachers', 'list', 'c1'], { account: undefined });
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('passes all listing flags', async () => {
|
|
256
|
+
await handlers.get('gog_classroom_teachers_list')!({ courseId: 'c1', max: 20, page: 'tok', all: true });
|
|
257
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
258
|
+
['classroom', 'teachers', 'list', 'c1', '--max=20', '--page=tok', '--all'],
|
|
259
|
+
{ account: undefined },
|
|
260
|
+
);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('omits --all when false', async () => {
|
|
264
|
+
await handlers.get('gog_classroom_teachers_list')!({ courseId: 'c1', all: false });
|
|
265
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'teachers', 'list', 'c1'], { account: undefined });
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('returns error text on failure', async () => {
|
|
269
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('List failed'));
|
|
270
|
+
const result = await handlers.get('gog_classroom_teachers_list')!({ courseId: 'c1' });
|
|
271
|
+
expect(result.content[0].text).toBe('Error: List failed');
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
describe('gog_classroom_teachers_get', () => {
|
|
276
|
+
it('calls run with courseId and userId', async () => {
|
|
277
|
+
await handlers.get('gog_classroom_teachers_get')!({ courseId: 'c1', userId: 'u1' });
|
|
278
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'teachers', 'get', 'c1', 'u1'], { account: undefined });
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('returns error text on failure', async () => {
|
|
282
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
|
|
283
|
+
const result = await handlers.get('gog_classroom_teachers_get')!({ courseId: 'c1', userId: 'bad' });
|
|
284
|
+
expect(result.content[0].text).toBe('Error: Not found');
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe('gog_classroom_teachers_add', () => {
|
|
289
|
+
it('calls run with courseId and userId', async () => {
|
|
290
|
+
await handlers.get('gog_classroom_teachers_add')!({ courseId: 'c1', userId: 'u1' });
|
|
291
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'teachers', 'add', 'c1', 'u1'], { account: undefined });
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('returns error text on failure', async () => {
|
|
295
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Add failed'));
|
|
296
|
+
const result = await handlers.get('gog_classroom_teachers_add')!({ courseId: 'c1', userId: 'u1' });
|
|
297
|
+
expect(result.content[0].text).toBe('Error: Add failed');
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
describe('gog_classroom_teachers_remove', () => {
|
|
302
|
+
it('calls run with courseId and userId', async () => {
|
|
303
|
+
await handlers.get('gog_classroom_teachers_remove')!({ courseId: 'c1', userId: 'u1' });
|
|
304
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'teachers', 'remove', 'c1', 'u1'], { account: undefined });
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('returns error text on failure', async () => {
|
|
308
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Remove failed'));
|
|
309
|
+
const result = await handlers.get('gog_classroom_teachers_remove')!({ courseId: 'c1', userId: 'u1' });
|
|
310
|
+
expect(result.content[0].text).toBe('Error: Remove failed');
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
describe('gog_classroom_roster', () => {
|
|
315
|
+
it('calls run with courseId only', async () => {
|
|
316
|
+
await handlers.get('gog_classroom_roster')!({ courseId: 'c1' });
|
|
317
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'roster', 'c1'], { account: undefined });
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('passes all flags', async () => {
|
|
321
|
+
await handlers.get('gog_classroom_roster')!({ courseId: 'c1', students: true, teachers: true, max: 50, page: 'tok', all: true });
|
|
322
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
323
|
+
['classroom', 'roster', 'c1', '--students', '--teachers', '--max=50', '--page=tok', '--all'],
|
|
324
|
+
{ account: undefined },
|
|
325
|
+
);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('omits boolean flags when false', async () => {
|
|
329
|
+
await handlers.get('gog_classroom_roster')!({ courseId: 'c1', students: false, teachers: false, all: false });
|
|
330
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'roster', 'c1'], { account: undefined });
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('returns error text on failure', async () => {
|
|
334
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Roster failed'));
|
|
335
|
+
const result = await handlers.get('gog_classroom_roster')!({ courseId: 'c1' });
|
|
336
|
+
expect(result.content[0].text).toBe('Error: Roster failed');
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
describe('gog_classroom_coursework_list', () => {
|
|
341
|
+
it('calls run with courseId only', async () => {
|
|
342
|
+
await handlers.get('gog_classroom_coursework_list')!({ courseId: 'c1' });
|
|
343
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'coursework', 'list', 'c1'], { account: undefined });
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('passes all listing flags', async () => {
|
|
347
|
+
await handlers.get('gog_classroom_coursework_list')!({
|
|
348
|
+
courseId: 'c1',
|
|
349
|
+
state: 'PUBLISHED',
|
|
350
|
+
topic: 't1',
|
|
351
|
+
orderBy: 'updateTime desc',
|
|
352
|
+
max: 50,
|
|
353
|
+
page: 'tok',
|
|
354
|
+
all: true,
|
|
355
|
+
scanPages: 5,
|
|
356
|
+
});
|
|
357
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
358
|
+
['classroom', 'coursework', 'list', 'c1', '--state=PUBLISHED', '--topic=t1', '--order-by=updateTime desc', '--max=50', '--page=tok', '--all', '--scan-pages=5'],
|
|
359
|
+
{ account: undefined },
|
|
360
|
+
);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it('omits --all when false', async () => {
|
|
364
|
+
await handlers.get('gog_classroom_coursework_list')!({ courseId: 'c1', all: false });
|
|
365
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'coursework', 'list', 'c1'], { account: undefined });
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('returns error text on failure', async () => {
|
|
369
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('List failed'));
|
|
370
|
+
const result = await handlers.get('gog_classroom_coursework_list')!({ courseId: 'c1' });
|
|
371
|
+
expect(result.content[0].text).toBe('Error: List failed');
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
describe('gog_classroom_coursework_get', () => {
|
|
376
|
+
it('calls run with courseId and courseworkId', async () => {
|
|
377
|
+
await handlers.get('gog_classroom_coursework_get')!({ courseId: 'c1', courseworkId: 'w1' });
|
|
378
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'coursework', 'get', 'c1', 'w1'], { account: undefined });
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('returns error text on failure', async () => {
|
|
382
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
|
|
383
|
+
const result = await handlers.get('gog_classroom_coursework_get')!({ courseId: 'c1', courseworkId: 'bad' });
|
|
384
|
+
expect(result.content[0].text).toBe('Error: Not found');
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
describe('gog_classroom_coursework_create', () => {
|
|
389
|
+
it('calls run with required title only', async () => {
|
|
390
|
+
await handlers.get('gog_classroom_coursework_create')!({ courseId: 'c1', title: 'HW1' });
|
|
391
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
392
|
+
['classroom', 'coursework', 'create', 'c1', '--title=HW1'],
|
|
393
|
+
{ account: undefined },
|
|
394
|
+
);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('passes all optional flags', async () => {
|
|
398
|
+
await handlers.get('gog_classroom_coursework_create')!({
|
|
399
|
+
courseId: 'c1',
|
|
400
|
+
title: 'HW1',
|
|
401
|
+
description: 'Chapter 1',
|
|
402
|
+
type: 'ASSIGNMENT',
|
|
403
|
+
state: 'PUBLISHED',
|
|
404
|
+
maxPoints: 100,
|
|
405
|
+
due: '2026-05-01T23:59',
|
|
406
|
+
dueDate: '2026-05-01',
|
|
407
|
+
dueTime: '23:59',
|
|
408
|
+
scheduled: '2026-04-30T12:00',
|
|
409
|
+
topic: 't1',
|
|
410
|
+
});
|
|
411
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
412
|
+
['classroom', 'coursework', 'create', 'c1', '--title=HW1', '--description=Chapter 1', '--type=ASSIGNMENT', '--state=PUBLISHED', '--max-points=100', '--due=2026-05-01T23:59', '--due-date=2026-05-01', '--due-time=23:59', '--scheduled=2026-04-30T12:00', '--topic=t1'],
|
|
413
|
+
{ account: undefined },
|
|
414
|
+
);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('returns error text on failure', async () => {
|
|
418
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Create failed'));
|
|
419
|
+
const result = await handlers.get('gog_classroom_coursework_create')!({ courseId: 'c1', title: 'HW1' });
|
|
420
|
+
expect(result.content[0].text).toBe('Error: Create failed');
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
describe('gog_classroom_coursework_update', () => {
|
|
425
|
+
it('calls run with ids only', async () => {
|
|
426
|
+
await handlers.get('gog_classroom_coursework_update')!({ courseId: 'c1', courseworkId: 'w1' });
|
|
427
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'coursework', 'update', 'c1', 'w1'], { account: undefined });
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it('passes all optional flags', async () => {
|
|
431
|
+
await handlers.get('gog_classroom_coursework_update')!({
|
|
432
|
+
courseId: 'c1',
|
|
433
|
+
courseworkId: 'w1',
|
|
434
|
+
title: 'New Title',
|
|
435
|
+
description: 'Desc',
|
|
436
|
+
type: 'SHORT_ANSWER_QUESTION',
|
|
437
|
+
state: 'DRAFT',
|
|
438
|
+
maxPoints: 50,
|
|
439
|
+
due: '2026-05-01T23:59',
|
|
440
|
+
dueDate: '2026-05-01',
|
|
441
|
+
dueTime: '23:59',
|
|
442
|
+
scheduled: '2026-04-30T12:00',
|
|
443
|
+
topic: 't1',
|
|
444
|
+
});
|
|
445
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
446
|
+
['classroom', 'coursework', 'update', 'c1', 'w1', '--title=New Title', '--description=Desc', '--type=SHORT_ANSWER_QUESTION', '--state=DRAFT', '--max-points=50', '--due=2026-05-01T23:59', '--due-date=2026-05-01', '--due-time=23:59', '--scheduled=2026-04-30T12:00', '--topic=t1'],
|
|
447
|
+
{ account: undefined },
|
|
448
|
+
);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
it('returns error text on failure', async () => {
|
|
452
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Update failed'));
|
|
453
|
+
const result = await handlers.get('gog_classroom_coursework_update')!({ courseId: 'c1', courseworkId: 'w1' });
|
|
454
|
+
expect(result.content[0].text).toBe('Error: Update failed');
|
|
455
|
+
});
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
describe('gog_classroom_coursework_delete', () => {
|
|
459
|
+
it('calls run with ids', async () => {
|
|
460
|
+
await handlers.get('gog_classroom_coursework_delete')!({ courseId: 'c1', courseworkId: 'w1' });
|
|
461
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'coursework', 'delete', 'c1', 'w1'], { account: undefined });
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it('returns error text on failure', async () => {
|
|
465
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Delete failed'));
|
|
466
|
+
const result = await handlers.get('gog_classroom_coursework_delete')!({ courseId: 'c1', courseworkId: 'w1' });
|
|
467
|
+
expect(result.content[0].text).toBe('Error: Delete failed');
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
describe('gog_classroom_submissions_list', () => {
|
|
472
|
+
it('calls run with ids only', async () => {
|
|
473
|
+
await handlers.get('gog_classroom_submissions_list')!({ courseId: 'c1', courseworkId: 'w1' });
|
|
474
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'submissions', 'list', 'c1', 'w1'], { account: undefined });
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
it('passes all listing flags', async () => {
|
|
478
|
+
await handlers.get('gog_classroom_submissions_list')!({
|
|
479
|
+
courseId: 'c1',
|
|
480
|
+
courseworkId: 'w1',
|
|
481
|
+
state: 'TURNED_IN',
|
|
482
|
+
late: 'late',
|
|
483
|
+
user: 'u1',
|
|
484
|
+
max: 20,
|
|
485
|
+
page: 'tok',
|
|
486
|
+
all: true,
|
|
487
|
+
});
|
|
488
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
489
|
+
['classroom', 'submissions', 'list', 'c1', 'w1', '--state=TURNED_IN', '--late=late', '--user=u1', '--max=20', '--page=tok', '--all'],
|
|
490
|
+
{ account: undefined },
|
|
491
|
+
);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
it('omits --all when false', async () => {
|
|
495
|
+
await handlers.get('gog_classroom_submissions_list')!({ courseId: 'c1', courseworkId: 'w1', all: false });
|
|
496
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'submissions', 'list', 'c1', 'w1'], { account: undefined });
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it('returns error text on failure', async () => {
|
|
500
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('List failed'));
|
|
501
|
+
const result = await handlers.get('gog_classroom_submissions_list')!({ courseId: 'c1', courseworkId: 'w1' });
|
|
502
|
+
expect(result.content[0].text).toBe('Error: List failed');
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
describe('gog_classroom_submissions_get', () => {
|
|
507
|
+
it('calls run with all three ids', async () => {
|
|
508
|
+
await handlers.get('gog_classroom_submissions_get')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 's1' });
|
|
509
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'submissions', 'get', 'c1', 'w1', 's1'], { account: undefined });
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
it('returns error text on failure', async () => {
|
|
513
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
|
|
514
|
+
const result = await handlers.get('gog_classroom_submissions_get')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 'bad' });
|
|
515
|
+
expect(result.content[0].text).toBe('Error: Not found');
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
describe('gog_classroom_submissions_grade', () => {
|
|
520
|
+
it('calls run with ids only', async () => {
|
|
521
|
+
await handlers.get('gog_classroom_submissions_grade')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 's1' });
|
|
522
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'submissions', 'grade', 'c1', 'w1', 's1'], { account: undefined });
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
it('passes --draft and --assigned when provided', async () => {
|
|
526
|
+
await handlers.get('gog_classroom_submissions_grade')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 's1', draft: '90', assigned: '95' });
|
|
527
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
528
|
+
['classroom', 'submissions', 'grade', 'c1', 'w1', 's1', '--draft=90', '--assigned=95'],
|
|
529
|
+
{ account: undefined },
|
|
530
|
+
);
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it('returns error text on failure', async () => {
|
|
534
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Grade failed'));
|
|
535
|
+
const result = await handlers.get('gog_classroom_submissions_grade')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 's1' });
|
|
536
|
+
expect(result.content[0].text).toBe('Error: Grade failed');
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
describe('gog_classroom_submissions_return', () => {
|
|
541
|
+
it('calls run with ids', async () => {
|
|
542
|
+
await handlers.get('gog_classroom_submissions_return')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 's1' });
|
|
543
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'submissions', 'return', 'c1', 'w1', 's1'], { account: undefined });
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
it('returns error text on failure', async () => {
|
|
547
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Return failed'));
|
|
548
|
+
const result = await handlers.get('gog_classroom_submissions_return')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 's1' });
|
|
549
|
+
expect(result.content[0].text).toBe('Error: Return failed');
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
describe('gog_classroom_submissions_turn_in', () => {
|
|
554
|
+
it('calls run with ids', async () => {
|
|
555
|
+
await handlers.get('gog_classroom_submissions_turn_in')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 's1' });
|
|
556
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'submissions', 'turn-in', 'c1', 'w1', 's1'], { account: undefined });
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
it('returns error text on failure', async () => {
|
|
560
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Turn-in failed'));
|
|
561
|
+
const result = await handlers.get('gog_classroom_submissions_turn_in')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 's1' });
|
|
562
|
+
expect(result.content[0].text).toBe('Error: Turn-in failed');
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
describe('gog_classroom_submissions_reclaim', () => {
|
|
567
|
+
it('calls run with ids', async () => {
|
|
568
|
+
await handlers.get('gog_classroom_submissions_reclaim')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 's1' });
|
|
569
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'submissions', 'reclaim', 'c1', 'w1', 's1'], { account: undefined });
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
it('returns error text on failure', async () => {
|
|
573
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Reclaim failed'));
|
|
574
|
+
const result = await handlers.get('gog_classroom_submissions_reclaim')!({ courseId: 'c1', courseworkId: 'w1', submissionId: 's1' });
|
|
575
|
+
expect(result.content[0].text).toBe('Error: Reclaim failed');
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
describe('gog_classroom_announcements_list', () => {
|
|
580
|
+
it('calls run with courseId only', async () => {
|
|
581
|
+
await handlers.get('gog_classroom_announcements_list')!({ courseId: 'c1' });
|
|
582
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'announcements', 'list', 'c1'], { account: undefined });
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
it('passes all listing flags', async () => {
|
|
586
|
+
await handlers.get('gog_classroom_announcements_list')!({ courseId: 'c1', state: 'PUBLISHED', orderBy: 'updateTime desc', max: 20, page: 'tok', all: true });
|
|
587
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
588
|
+
['classroom', 'announcements', 'list', 'c1', '--state=PUBLISHED', '--order-by=updateTime desc', '--max=20', '--page=tok', '--all'],
|
|
589
|
+
{ account: undefined },
|
|
590
|
+
);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
it('omits --all when false', async () => {
|
|
594
|
+
await handlers.get('gog_classroom_announcements_list')!({ courseId: 'c1', all: false });
|
|
595
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'announcements', 'list', 'c1'], { account: undefined });
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
it('returns error text on failure', async () => {
|
|
599
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('List failed'));
|
|
600
|
+
const result = await handlers.get('gog_classroom_announcements_list')!({ courseId: 'c1' });
|
|
601
|
+
expect(result.content[0].text).toBe('Error: List failed');
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
describe('gog_classroom_announcements_get', () => {
|
|
606
|
+
it('calls run with ids', async () => {
|
|
607
|
+
await handlers.get('gog_classroom_announcements_get')!({ courseId: 'c1', announcementId: 'a1' });
|
|
608
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'announcements', 'get', 'c1', 'a1'], { account: undefined });
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
it('returns error text on failure', async () => {
|
|
612
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
|
|
613
|
+
const result = await handlers.get('gog_classroom_announcements_get')!({ courseId: 'c1', announcementId: 'bad' });
|
|
614
|
+
expect(result.content[0].text).toBe('Error: Not found');
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
describe('gog_classroom_announcements_create', () => {
|
|
619
|
+
it('calls run with required text only', async () => {
|
|
620
|
+
await handlers.get('gog_classroom_announcements_create')!({ courseId: 'c1', text: 'Hi' });
|
|
621
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
622
|
+
['classroom', 'announcements', 'create', 'c1', '--text=Hi'],
|
|
623
|
+
{ account: undefined },
|
|
624
|
+
);
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
it('passes all optional flags', async () => {
|
|
628
|
+
await handlers.get('gog_classroom_announcements_create')!({ courseId: 'c1', text: 'Hi', state: 'DRAFT', scheduled: '2026-05-01T12:00' });
|
|
629
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
630
|
+
['classroom', 'announcements', 'create', 'c1', '--text=Hi', '--state=DRAFT', '--scheduled=2026-05-01T12:00'],
|
|
631
|
+
{ account: undefined },
|
|
632
|
+
);
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
it('returns error text on failure', async () => {
|
|
636
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Create failed'));
|
|
637
|
+
const result = await handlers.get('gog_classroom_announcements_create')!({ courseId: 'c1', text: 'x' });
|
|
638
|
+
expect(result.content[0].text).toBe('Error: Create failed');
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
describe('gog_classroom_announcements_update', () => {
|
|
643
|
+
it('calls run with ids only', async () => {
|
|
644
|
+
await handlers.get('gog_classroom_announcements_update')!({ courseId: 'c1', announcementId: 'a1' });
|
|
645
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'announcements', 'update', 'c1', 'a1'], { account: undefined });
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
it('passes all optional flags', async () => {
|
|
649
|
+
await handlers.get('gog_classroom_announcements_update')!({ courseId: 'c1', announcementId: 'a1', text: 'edited', state: 'PUBLISHED', scheduled: '2026-05-01T12:00' });
|
|
650
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
651
|
+
['classroom', 'announcements', 'update', 'c1', 'a1', '--text=edited', '--state=PUBLISHED', '--scheduled=2026-05-01T12:00'],
|
|
652
|
+
{ account: undefined },
|
|
653
|
+
);
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
it('returns error text on failure', async () => {
|
|
657
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Update failed'));
|
|
658
|
+
const result = await handlers.get('gog_classroom_announcements_update')!({ courseId: 'c1', announcementId: 'a1' });
|
|
659
|
+
expect(result.content[0].text).toBe('Error: Update failed');
|
|
660
|
+
});
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
describe('gog_classroom_announcements_delete', () => {
|
|
664
|
+
it('calls run with ids', async () => {
|
|
665
|
+
await handlers.get('gog_classroom_announcements_delete')!({ courseId: 'c1', announcementId: 'a1' });
|
|
666
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'announcements', 'delete', 'c1', 'a1'], { account: undefined });
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
it('returns error text on failure', async () => {
|
|
670
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Delete failed'));
|
|
671
|
+
const result = await handlers.get('gog_classroom_announcements_delete')!({ courseId: 'c1', announcementId: 'a1' });
|
|
672
|
+
expect(result.content[0].text).toBe('Error: Delete failed');
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
describe('gog_classroom_topics_list', () => {
|
|
677
|
+
it('calls run with courseId only', async () => {
|
|
678
|
+
await handlers.get('gog_classroom_topics_list')!({ courseId: 'c1' });
|
|
679
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'topics', 'list', 'c1'], { account: undefined });
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
it('passes all listing flags', async () => {
|
|
683
|
+
await handlers.get('gog_classroom_topics_list')!({ courseId: 'c1', max: 20, page: 'tok', all: true });
|
|
684
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
685
|
+
['classroom', 'topics', 'list', 'c1', '--max=20', '--page=tok', '--all'],
|
|
686
|
+
{ account: undefined },
|
|
687
|
+
);
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
it('omits --all when false', async () => {
|
|
691
|
+
await handlers.get('gog_classroom_topics_list')!({ courseId: 'c1', all: false });
|
|
692
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'topics', 'list', 'c1'], { account: undefined });
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
it('returns error text on failure', async () => {
|
|
696
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('List failed'));
|
|
697
|
+
const result = await handlers.get('gog_classroom_topics_list')!({ courseId: 'c1' });
|
|
698
|
+
expect(result.content[0].text).toBe('Error: List failed');
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
describe('gog_classroom_topics_get', () => {
|
|
703
|
+
it('calls run with ids', async () => {
|
|
704
|
+
await handlers.get('gog_classroom_topics_get')!({ courseId: 'c1', topicId: 't1' });
|
|
705
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'topics', 'get', 'c1', 't1'], { account: undefined });
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
it('returns error text on failure', async () => {
|
|
709
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
|
|
710
|
+
const result = await handlers.get('gog_classroom_topics_get')!({ courseId: 'c1', topicId: 'bad' });
|
|
711
|
+
expect(result.content[0].text).toBe('Error: Not found');
|
|
712
|
+
});
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
describe('gog_classroom_topics_create', () => {
|
|
716
|
+
it('calls run with courseId and name', async () => {
|
|
717
|
+
await handlers.get('gog_classroom_topics_create')!({ courseId: 'c1', name: 'Week 1' });
|
|
718
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
719
|
+
['classroom', 'topics', 'create', 'c1', '--name=Week 1'],
|
|
720
|
+
{ account: undefined },
|
|
721
|
+
);
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
it('returns error text on failure', async () => {
|
|
725
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Create failed'));
|
|
726
|
+
const result = await handlers.get('gog_classroom_topics_create')!({ courseId: 'c1', name: 'x' });
|
|
727
|
+
expect(result.content[0].text).toBe('Error: Create failed');
|
|
728
|
+
});
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
describe('gog_classroom_topics_update', () => {
|
|
732
|
+
it('calls run with ids and name', async () => {
|
|
733
|
+
await handlers.get('gog_classroom_topics_update')!({ courseId: 'c1', topicId: 't1', name: 'Week 2' });
|
|
734
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
735
|
+
['classroom', 'topics', 'update', 'c1', 't1', '--name=Week 2'],
|
|
736
|
+
{ account: undefined },
|
|
737
|
+
);
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
it('returns error text on failure', async () => {
|
|
741
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Update failed'));
|
|
742
|
+
const result = await handlers.get('gog_classroom_topics_update')!({ courseId: 'c1', topicId: 't1', name: 'x' });
|
|
743
|
+
expect(result.content[0].text).toBe('Error: Update failed');
|
|
744
|
+
});
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
describe('gog_classroom_topics_delete', () => {
|
|
748
|
+
it('calls run with ids', async () => {
|
|
749
|
+
await handlers.get('gog_classroom_topics_delete')!({ courseId: 'c1', topicId: 't1' });
|
|
750
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'topics', 'delete', 'c1', 't1'], { account: undefined });
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
it('returns error text on failure', async () => {
|
|
754
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Delete failed'));
|
|
755
|
+
const result = await handlers.get('gog_classroom_topics_delete')!({ courseId: 'c1', topicId: 't1' });
|
|
756
|
+
expect(result.content[0].text).toBe('Error: Delete failed');
|
|
757
|
+
});
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
describe('gog_classroom_invitations_list', () => {
|
|
761
|
+
it('calls run with no flags', async () => {
|
|
762
|
+
await handlers.get('gog_classroom_invitations_list')!({});
|
|
763
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'invitations', 'list'], { account: undefined });
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
it('passes all listing flags', async () => {
|
|
767
|
+
await handlers.get('gog_classroom_invitations_list')!({ course: 'c1', user: 'u1', max: 20, page: 'tok', all: true });
|
|
768
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
769
|
+
['classroom', 'invitations', 'list', '--course=c1', '--user=u1', '--max=20', '--page=tok', '--all'],
|
|
770
|
+
{ account: undefined },
|
|
771
|
+
);
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
it('omits --all when false', async () => {
|
|
775
|
+
await handlers.get('gog_classroom_invitations_list')!({ all: false });
|
|
776
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'invitations', 'list'], { account: undefined });
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
it('returns error text on failure', async () => {
|
|
780
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('List failed'));
|
|
781
|
+
const result = await handlers.get('gog_classroom_invitations_list')!({});
|
|
782
|
+
expect(result.content[0].text).toBe('Error: List failed');
|
|
783
|
+
});
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
describe('gog_classroom_invitations_get', () => {
|
|
787
|
+
it('calls run with invitationId', async () => {
|
|
788
|
+
await handlers.get('gog_classroom_invitations_get')!({ invitationId: 'i1' });
|
|
789
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'invitations', 'get', 'i1'], { account: undefined });
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
it('returns error text on failure', async () => {
|
|
793
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
|
|
794
|
+
const result = await handlers.get('gog_classroom_invitations_get')!({ invitationId: 'bad' });
|
|
795
|
+
expect(result.content[0].text).toBe('Error: Not found');
|
|
796
|
+
});
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
describe('gog_classroom_invitations_create', () => {
|
|
800
|
+
it('calls run with courseId, userId, role', async () => {
|
|
801
|
+
await handlers.get('gog_classroom_invitations_create')!({ courseId: 'c1', userId: 'u1', role: 'STUDENT' });
|
|
802
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
803
|
+
['classroom', 'invitations', 'create', 'c1', 'u1', '--role=STUDENT'],
|
|
804
|
+
{ account: undefined },
|
|
805
|
+
);
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
it('returns error text on failure', async () => {
|
|
809
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Create failed'));
|
|
810
|
+
const result = await handlers.get('gog_classroom_invitations_create')!({ courseId: 'c1', userId: 'u1', role: 'TEACHER' });
|
|
811
|
+
expect(result.content[0].text).toBe('Error: Create failed');
|
|
812
|
+
});
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
describe('gog_classroom_invitations_accept', () => {
|
|
816
|
+
it('calls run with invitationId', async () => {
|
|
817
|
+
await handlers.get('gog_classroom_invitations_accept')!({ invitationId: 'i1' });
|
|
818
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'invitations', 'accept', 'i1'], { account: undefined });
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
it('returns error text on failure', async () => {
|
|
822
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Accept failed'));
|
|
823
|
+
const result = await handlers.get('gog_classroom_invitations_accept')!({ invitationId: 'bad' });
|
|
824
|
+
expect(result.content[0].text).toBe('Error: Accept failed');
|
|
825
|
+
});
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
describe('gog_classroom_invitations_delete', () => {
|
|
829
|
+
it('calls run with invitationId', async () => {
|
|
830
|
+
await handlers.get('gog_classroom_invitations_delete')!({ invitationId: 'i1' });
|
|
831
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'invitations', 'delete', 'i1'], { account: undefined });
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
it('returns error text on failure', async () => {
|
|
835
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Delete failed'));
|
|
836
|
+
const result = await handlers.get('gog_classroom_invitations_delete')!({ invitationId: 'bad' });
|
|
837
|
+
expect(result.content[0].text).toBe('Error: Delete failed');
|
|
838
|
+
});
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
describe('gog_classroom_profile_get', () => {
|
|
842
|
+
it('calls run with no userId (self)', async () => {
|
|
843
|
+
await handlers.get('gog_classroom_profile_get')!({});
|
|
844
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'profile', 'get'], { account: undefined });
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
it('passes userId when provided', async () => {
|
|
848
|
+
await handlers.get('gog_classroom_profile_get')!({ userId: 'u1' });
|
|
849
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'profile', 'get', 'u1'], { account: undefined });
|
|
850
|
+
});
|
|
851
|
+
|
|
852
|
+
it('returns error text on failure', async () => {
|
|
853
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Profile failed'));
|
|
854
|
+
const result = await handlers.get('gog_classroom_profile_get')!({});
|
|
855
|
+
expect(result.content[0].text).toBe('Error: Profile failed');
|
|
856
|
+
});
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
describe('gog_classroom_run', () => {
|
|
860
|
+
it('passes subcommand and args to runner', async () => {
|
|
861
|
+
await handlers.get('gog_classroom_run')!({ subcommand: 'guardians', args: ['list', 'u1'] });
|
|
862
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'guardians', 'list', 'u1'], { account: undefined });
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
it('passes account through', async () => {
|
|
866
|
+
await handlers.get('gog_classroom_run')!({ subcommand: 'materials', args: [], account: 'a@b.com' });
|
|
867
|
+
expect(runner.run).toHaveBeenCalledWith(['classroom', 'materials'], { account: 'a@b.com' });
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
it('returns error text on failure', async () => {
|
|
871
|
+
vi.mocked(runner.run).mockRejectedValue(new Error('Run failed'));
|
|
872
|
+
const result = await handlers.get('gog_classroom_run')!({ subcommand: 'guardians', args: [] });
|
|
873
|
+
expect(result.content[0].text).toBe('Error: Run failed');
|
|
874
|
+
});
|
|
875
|
+
});
|