prepare for better integration and testing
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
// 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"
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user