Files
rts/tests/sync.test.js
T

128 lines
3.0 KiB
JavaScript

// Unit tests for RTS Background Sync
import { jest } from "@jest/globals";
// Mock Dexie and jQuery globally before importing modules that use them
const mockAnswersWhere = jest.fn();
const mockAnswersFilter = jest.fn();
const mockAnswersToArray = jest.fn();
const mockAnswersPut = jest.fn();
const mockTransaction = jest.fn();
globalThis.Dexie = class {
constructor(name) {
this.name = name;
this.answers = {
where: mockAnswersWhere,
put: mockAnswersPut,
};
}
version() {
return {
stores: () => {}
};
}
transaction(mode, tables, cb) {
return mockTransaction(mode, tables, cb);
}
};
// Define mock jQuery $.post
const mockPostDone = jest.fn();
const mockPostFail = jest.fn();
const mockPost = jest.fn(() => ({
done: (cb) => {
mockPostDone(cb);
return {
fail: (failCb) => {
mockPostFail(failCb);
}
};
}
}));
globalThis.$ = {
post: mockPost,
};
// Mock DOM elements
const mockHtml = jest.fn();
globalThis.document = {
getElementById: jest.fn(() => ({
set innerHTML(val) {
mockHtml(val);
}
})),
};
// Dynamic import to avoid ES module hoisting execution before mocks are set up
let performSync, updateSyncUI;
describe("RTS Sync Unit Tests", () => {
beforeAll(async () => {
const syncModule = await import("../js/sync.js");
performSync = syncModule.performSync;
updateSyncUI = syncModule.updateSyncUI;
});
beforeEach(() => {
jest.clearAllMocks();
});
test("updateSyncUI updates the DOM container", () => {
updateSyncUI("syncing");
expect(globalThis.document.getElementById).toHaveBeenCalledWith("sync-status");
expect(mockHtml).toHaveBeenCalledWith(expect.stringContaining("Saving to server..."));
});
test("performSync does nothing if exam details are missing", async () => {
await performSync(null, {});
expect(mockAnswersWhere).not.toHaveBeenCalled();
});
test("performSync processes unsynced answers and marks them as synced", async () => {
const examDetails = {
aid: "session-123",
cid: "9999",
eid: "rapid/1",
start_time: 1234567,
};
const URLS = {
exam_submit_url: "/submit-url",
};
const unsyncedAnswers = [
{ aid: "session-123", cid: "9999", eid: "rapid/1", qid: 1, qidn: "1", ans: "Normal", synced: false }
];
mockAnswersWhere.mockReturnValue({
filter: mockAnswersFilter.mockReturnValue({
toArray: mockAnswersToArray.mockResolvedValue(unsyncedAnswers)
})
});
mockPostDone.mockImplementation((cb) => {
cb({ success: true });
});
mockTransaction.mockImplementation(async (mode, tables, cb) => {
await cb();
});
await performSync(examDetails, URLS);
expect(mockAnswersWhere).toHaveBeenCalledWith({
aid: examDetails.aid,
cid: examDetails.cid,
eid: examDetails.eid,
});
expect(mockPost).toHaveBeenCalledWith(
URLS.exam_submit_url,
expect.objectContaining({
in_progress: "true",
}),
null,
"json"
);
});
});