66 lines
4.7 KiB
TypeScript
66 lines
4.7 KiB
TypeScript
import { expect } from "bun:test";
|
|
import { forEachDb } from "./helpers";
|
|
import { FIXTURES, makeApp } from "./app";
|
|
import { extraCourses } from "./courses";
|
|
|
|
forEachDb("progress: mark done, positions never undo done, gating blocks writes", async (db) => {
|
|
const t = await makeApp(db, [FIXTURES, await extraCourses()]);
|
|
await t.signUp("[email protected]");
|
|
const me = await t.signUp("[email protected]");
|
|
const put = (course: string, lesson: string, body: unknown, cookie = me) => t.call("PUT", `/api/courses/${course}/progress/${lesson}`, { cookie, body });
|
|
|
|
expect((await put("sample", "m1-intro", { state: "done" }, "")).status).toBe(401);
|
|
expect((await put("sample", "m1-intro", { state: "finished" })).status).toBe(400);
|
|
expect((await (await put("sample", "m1-video", { state: "in-progress", positionSeconds: 1.5 })).json()).positionSeconds).toBe(1.5);
|
|
await put("sample", "m1-video", { state: "done" });
|
|
const after = await (await put("sample", "m1-video", { state: "in-progress", positionSeconds: 0.5 })).json();
|
|
expect(after).toMatchObject({ state: "done", positionSeconds: 0.5 });
|
|
expect((await put("sample", "nope", { state: "done" })).status).toBe(404);
|
|
|
|
expect((await put("gated", "g2a", { state: "done" })).status).toBe(403);
|
|
await put("gated", "g1a", { state: "done" });
|
|
await put("gated", "g1b", { state: "done" });
|
|
expect((await put("gated", "g2a", { state: "done" })).status).toBe(200);
|
|
const all = await (await t.call("GET", "/api/courses/gated/progress", { cookie: me })).json();
|
|
expect(Object.keys(all).sort()).toEqual(["g1a", "g1b", "g2a"]);
|
|
}, 30_000);
|
|
|
|
forEachDb("notes persist per lesson with slide and video anchors", async (db) => {
|
|
const t = await makeApp(db);
|
|
const me = await t.signUp("[email protected]");
|
|
const other = await t.signUp("[email protected]");
|
|
const post = (b: unknown, cookie = me) => t.call("POST", "/api/courses/sample/notes", { cookie, body: b });
|
|
expect((await post({ lessonId: "m1-video", anchorKind: "slide", anchorValue: 2, body: "x" })).status).toBe(400); // no deck id
|
|
expect((await post({ lessonId: "m1-video", anchorKind: "video", body: "x" })).status).toBe(400);
|
|
const s10 = await (await post({ lessonId: "m1-video", anchorKind: "slide", anchorValue: 10, deckId: "d1", body: "slide ten" })).json();
|
|
await post({ lessonId: "m1-video", anchorKind: "slide", anchorValue: 2, deckId: "d1", body: "slide two" });
|
|
await post({ lessonId: "m1-video", anchorKind: "video", anchorValue: 1.25, body: "at 1.25s" });
|
|
await post({ lessonId: "m1-intro", body: "general" });
|
|
const list = await (await t.call("GET", "/api/courses/sample/notes?lesson=m1-video", { cookie: me })).json();
|
|
expect(list.map((n: { body: string }) => n.body)).toEqual(["slide two", "slide ten", "at 1.25s"]);
|
|
expect(list[0]).toMatchObject({ anchorKind: "slide", anchorValue: "2", deckId: "d1" });
|
|
expect(list[0].userId).toBeUndefined();
|
|
expect((await (await t.call("GET", "/api/courses/sample/notes", { cookie: me })).json()).length).toBe(4);
|
|
expect(await (await t.call("GET", "/api/courses/sample/notes", { cookie: other })).json()).toEqual([]);
|
|
|
|
expect((await t.call("PATCH", `/api/notes/${s10.id}`, { cookie: other, body: { body: "hijack" } })).status).toBe(404);
|
|
expect((await (await t.call("PATCH", `/api/notes/${s10.id}`, { cookie: me, body: { body: "edited" } })).json()).body).toBe("edited");
|
|
expect((await t.call("DELETE", `/api/notes/${s10.id}`, { cookie: other })).status).toBe(404);
|
|
expect((await t.call("DELETE", `/api/notes/${s10.id}`, { cookie: me })).status).toBe(200);
|
|
expect((await (await t.call("GET", "/api/courses/sample/notes?lesson=m1-video", { cookie: me })).json()).length).toBe(2);
|
|
}, 30_000);
|
|
|
|
forEachDb("exercise attempts save code and a pass marks the lesson done", async (db) => {
|
|
const t = await makeApp(db);
|
|
const me = await t.signUp("[email protected]");
|
|
const url = "/api/courses/sample/lessons/m2-ex-add/attempt";
|
|
expect(await (await t.call("GET", `${url}?track=js`, { cookie: me })).json()).toBeNull();
|
|
const r1 = await (await t.call("PUT", url, { cookie: me, body: { track: "js", code: "draft", passed: false, result: [{ name: "a", passed: false }] } })).json();
|
|
expect(r1).toEqual({ ok: true, passed: false, state: "in-progress" });
|
|
const r2 = await (await t.call("PUT", url, { cookie: me, body: { track: "js", code: "export const add=(a,b)=>a+b", passed: true, result: [] } })).json();
|
|
expect(r2.state).toBe("done");
|
|
const got = await (await t.call("GET", `${url}?track=js`, { cookie: me })).json();
|
|
expect(got).toMatchObject({ code: "export const add=(a,b)=>a+b", passed: true });
|
|
expect((await t.call("PUT", "/api/courses/sample/lessons/m1-intro/attempt", { cookie: me, body: { code: "x" } })).status).toBe(400);
|
|
}, 30_000);
|