@atomicjolt/lti-client
Version:
Client Javascript libraries to handle LTI.
145 lines (129 loc) • 5.46 kB
text/typescript
import { describe, expect, it, beforeEach, afterEach, vi } from "vitest";
import i18next from "i18next";
import { tryRequestStorageAccess } from "./platform_storage";
import { ltiStorageLaunch } from "./lti_storage_launch";
import { launchNewWindow } from "../html/launch_new_window";
import { InitSettings } from "../types";
i18next.init({
fallbackLng: "en",
keySeparator: false,
});
const openIdCookiePrefix = "oid_";
const settings: InitSettings = {
state: "state",
responseUrl:
"https://canvas.instructure.com/api/lti/authorize_redirect?client_id=43460000000000539",
relaunchInitUrl:
"https://test.atomicjolt.xyz/oidc/init?iss=https%3A%2F%2Fcanvas.instructure.com",
ltiStorageParams: {
target: "_parent",
originSupportBroken: true,
platformOIDCUrl:
"https://canvas.instructure.com/api/lti/authorize_redirect",
},
openIdCookiePrefix,
};
describe("test", () => {
beforeEach(() => {
document.body.innerHTML = `
<div class="aj-main">
<div id="error" class="hidden error">Error</div>
<div id="main-content"></div>
</div>
`;
});
afterEach(() => {
vi.restoreAllMocks();
delete document.hasStorageAccess;
delete document.requestStorageAccess;
document.cookie = `${openIdCookiePrefix}state=; path=/; max-age=-1; SameSite=None;`;
});
it("launches in new window", () => {
const openSpy = vi.spyOn(window, "open");
openSpy.mockImplementation(() => {});
launchNewWindow(settings);
expect(openSpy).toHaveBeenCalledWith(settings.relaunchInitUrl);
expect(document.getElementById("button_launch_new_window").disabled).toBe(
true
);
expect(document.body.innerHTML).toContain("Please click");
expect(document.body.innerHTML).not.toContain("enable cookies");
});
it("submits form when we have cookies", async () => {
vi.spyOn(window.document, "cookie", "get").mockReturnValue(
`${openIdCookiePrefix}state=jwt`
);
const mockReplace = vi.fn();
vi.spyOn(window, "location", "get").mockReturnValue({
replace: mockReplace,
});
await ltiStorageLaunch(settings);
expect(mockReplace).toHaveBeenCalledWith(settings.responseUrl);
});
it("shows cookie error when in top frame", async () => {
await ltiStorageLaunch({ ...settings, ltiStorageParams: null });
expect(document.body.innerHTML).toContain("check your browser");
expect(document.body.innerHTML).not.toContain("Open in a new window");
});
it("shows launch in new window when not in top frame", async () => {
vi.spyOn(window, "top", "get").mockReturnValue({});
await ltiStorageLaunch({ ...settings, ltiStorageParams: null });
expect(document.body.innerHTML).toContain("Open in a new window");
});
it("shows storage api access link when available and not in top frame", async () => {
document.hasStorageAccess = () => Promise.resolve(false);
document.requestStorageAccess = () => Promise.resolve(false);
vi.spyOn(window, "top", "get").mockReturnValue({});
await ltiStorageLaunch({ ...settings, ltiStorageParams: null });
await new Promise(process.nextTick);
expect(document.body.innerHTML).toContain("enable cookies");
});
it("doesn't show storage api access link when not available", async () => {
document.hasStorageAccess = () => Promise.reject();
document.requestStorageAccess = () => Promise.resolve(true);
vi.spyOn(window, "top", "get").mockReturnValue({});
await ltiStorageLaunch({ ...settings, ltiStorageParams: null });
await new Promise(process.nextTick);
expect(document.body.innerHTML).not.toContain("enable cookies");
});
it("doesn't show storage api access link when we already have access", async () => {
document.hasStorageAccess = () => Promise.resolve(true);
document.requestStorageAccess = () => Promise.resolve(true);
vi.spyOn(window, "top", "get").mockReturnValue({});
await ltiStorageLaunch({ ...settings, ltiStorageParams: null });
await new Promise(process.nextTick);
expect(document.body.innerHTML).not.toContain("enable cookies");
});
it("redirects and sets cookie if storage access is granted", async () => {
document.requestStorageAccess = () => Promise.resolve(true);
const mockReplace = vi.fn();
vi.spyOn(window, "location", "get").mockReturnValue({
replace: mockReplace,
});
const cookieSet = vi.spyOn(document, "cookie", "set");
tryRequestStorageAccess(settings);
await new Promise(process.nextTick);
expect(mockReplace).toHaveBeenCalledWith(settings.responseUrl);
expect(cookieSet).toHaveBeenCalledWith(
"oid_state=1; path=/; max-age=60; SameSite=None;"
);
});
it("shows an error if storage access is not granted", async () => {
const logSpy = vi.spyOn(console, "log").mockReturnValue();
document.requestStorageAccess = () =>
new Promise(function () {
throw new Error("No Access");
});
tryRequestStorageAccess(settings);
await new Promise(process.nextTick);
expect(document.body.innerHTML).toContain("browser prevented");
expect(logSpy).toHaveBeenCalled();
});
it("uses the lti storage api when available", async () => {
const postMessageSpy = vi.spyOn(window, "postMessage");
await ltiStorageLaunch(settings);
await new Promise(process.nextTick);
expect(postMessageSpy).toHaveBeenCalled();
// TODO: Figure out how to test the postMessage API
});
});