Skip to content

Commit

Permalink
refactor: split big tests in samaller ones
Browse files Browse the repository at this point in the history
  • Loading branch information
Flowrey committed Sep 10, 2024
1 parent b5526a5 commit ec1ef2a
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 235 deletions.
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export default {
moduleNameMapper: {
"^webextension-polyfill$": "<rootDir>/tests/__mocks__/browser.ts",
},
silent: true,
};
7 changes: 5 additions & 2 deletions src/js/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TeachingUnitRepository } from "./teaching_unit/repository";
import { TeachingUnitView } from "./teaching_unit/view";
import { ValidationError } from "./teaching_unit/model";
import { TeachingUnit, ValidationError } from "./teaching_unit/model";

function getCurriculum() {
const curriculum = document.getElementById("parcours");
Expand All @@ -18,7 +18,10 @@ const curriculum = getCurriculum();
const teachingUnitElements = getTeachingUnitElements(curriculum);
teachingUnitElements.forEach(async (el: Element) => {
try {
const teachingUnit = await TeachingUnitRepository.getFromLocalStorage(el);
const teachingUnit = TeachingUnit.fromElement(el);
teachingUnit.state =
await TeachingUnitRepository.getStateFromLocalStorage(teachingUnit);

new TeachingUnitRepository(teachingUnit);
new TeachingUnitView(el, teachingUnit);
} catch (error) {
Expand Down
27 changes: 11 additions & 16 deletions src/js/teaching_unit/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,26 @@ export class TeachingUnitRepository implements Observer {
public update(subject: TeachingUnit): void {
switch (subject.state) {
case State.Unselected:
this.removeFromLocalStorage(subject);
TeachingUnitRepository.removeStateFromLocalStorage(subject);
break;
case State.Selected:
case State.Validated:
this.saveToLocalStorage(subject);
TeachingUnitRepository.saveStateToLocalStorage(subject);
break;
}
}

public static async getFromLocalStorage(el: Element) {
const teachingUnit = TeachingUnit.fromElement(el);
const record = await browser.storage.local.get(teachingUnit.code);
const state = <State>record[teachingUnit.code];
switch (state) {
case State.Selected:
teachingUnit.select();
break;
case State.Validated:
teachingUnit.validate();
break;
public static async getStateFromLocalStorage(subject: TeachingUnit) {
const record = await browser.storage.local.get(subject.code);
const state = <State>record[subject.code];
if (state) {
return state;
} else {
return State.Unselected;
}
return teachingUnit;
}

private removeFromLocalStorage(subject: TeachingUnit) {
public static removeStateFromLocalStorage(subject: TeachingUnit) {
browser.storage.local.remove(subject.code).then(
() => {
console.debug(`${subject.code} removed from local storage`);
Expand All @@ -45,7 +40,7 @@ export class TeachingUnitRepository implements Observer {
);
}

private saveToLocalStorage(subject: TeachingUnit) {
public static saveStateToLocalStorage(subject: TeachingUnit) {
const record = {};
record[subject.code] = subject.state;
browser.storage.local.set(record).then(
Expand Down
37 changes: 3 additions & 34 deletions tests/__mocks__/webextension-polyfill.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,9 @@
declare global {
// eslint-disable-next-line no-var
var myLocalStorage: object;
}

export const browser = {
storage: {
local: {
get: function (code: string) {
if (globalThis.myLocalStorage == undefined) {
globalThis.myLocalStorage = {};
}
if (code in globalThis.myLocalStorage) {
return Promise.resolve(globalThis.myLocalStorage[code]);
}
return {};
},
set: function (obj: object) {
if (globalThis.myLocalStorage == undefined) {
globalThis.myLocalStorage = {};
}
const code = Object.keys(obj)[0];
const state = Object.values(obj)[0];
const record = {};
record[code] = state;
globalThis.myLocalStorage[code] = record;
return Promise.resolve();
},
remove: function (code: string) {
if (globalThis.myLocalStorage == undefined) {
globalThis.myLocalStorage = {};
}
if (code in globalThis.myLocalStorage) {
delete globalThis.myLocalStorage[code];
}
return Promise.resolve();
},
get: jest.fn(),
set: jest.fn().mockImplementation(() => Promise.resolve()),
remove: jest.fn().mockImplementation(() => Promise.resolve()),
},
},
};
Expand Down
266 changes: 110 additions & 156 deletions tests/teaching_unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,164 +1,118 @@
import { State, TeachingUnit } from "../src/js/teaching_unit/model";
import { Observer } from "../src/js/utils";

test("get teaching unit from element", () => {
// Set up our document body
document.body.innerHTML =
'<div class="ue option clearfix">' +
' <div class=" infos-ue">' +
' <div class="details clearfix">' +
' <div class="credits">6 ECTS<span class="dico"><span class="icon icon-help_simple"></span></span></div>' +
' <h4 class="titre">' +
' <a id="intitule_5df3b7279a53cb218ffb5684789f8939" href="/servlet/uFF?OBJET=ue&amp;CODE=MVA003&amp;LANGUE=0&amp;RF=" target="ue">Mathematical tools for computing</a>' +
" </h4>" +
' <div class="code">' +
' <a id="code_5df3b7279a53cb218ffb5684789f8939" href="/servlet/uFF?OBJET=ue&amp;CODE=MVA003&amp;LANGUE=0&amp;RF=" target="ue">MVA003</a>' +
" </div>" +
" </div>" +
" </div>" +
"</div>";
const el = document.getElementsByClassName("ue")[0];
const teachingUnit = TeachingUnit.fromElement(el);
expect(teachingUnit.code).toBe("MVA003");
expect(teachingUnit.title).toBe("Mathematical tools for computing");
expect(teachingUnit.ects).toBe(6);
});

test("get teaching unit from element with missing title", () => {
// Set up our document body
document.body.innerHTML =
'<div class="ue option clearfix">' +
' <div class=" infos-ue">' +
' <div class="details clearfix">' +
' <div class="credits">6 ECTS<span class="dico"><span class="icon icon-help_simple"></span></span></div>' +
' <div class="code">' +
' <a id="code_5df3b7279a53cb218ffb5684789f8939" href="/servlet/uFF?OBJET=ue&amp;CODE=MVA003&amp;LANGUE=0&amp;RF=" target="ue">MVA003</a>' +
" </div>" +
" </div>" +
" </div>" +
"</div>";
const el = document.getElementsByClassName("ue")[0];

expect(() => {
TeachingUnit.fromElement(el);
}).toThrow("missing field: title");
});

test("get teaching unit from element with missing code", () => {
// Set up our document body
document.body.innerHTML =
'<div class="ue option clearfix">' +
' <div class=" infos-ue">' +
' <div class="details clearfix">' +
' <h4 class="titre">' +
' <a id="intitule_5df3b7279a53cb218ffb5684789f8939" href="/servlet/uFF?OBJET=ue&amp;CODE=MVA003&amp;LANGUE=0&amp;RF=" target="ue">Mathematical tools for computing</a>' +
" </h4>" +
' <div class="credits">6 ECTS<span class="dico"><span class="icon icon-help_simple"></span></span></div>' +
" </div>" +
" </div>" +
"</div>";
const el = document.getElementsByClassName("ue")[0];

expect(() => {
TeachingUnit.fromElement(el);
}).toThrow("missing field: code");
});
import { DummyObserver, mockCallback } from "./utils.test";

test("get teaching unit from element with missing credits", () => {
// Set up our document body
document.body.innerHTML =
'<div class="ue option clearfix">' +
' <div class=" infos-ue">' +
' <div class="details clearfix">' +
' <h4 class="titre">' +
' <a id="intitule_5df3b7279a53cb218ffb5684789f8939" href="/servlet/uFF?OBJET=ue&amp;CODE=MVA003&amp;LANGUE=0&amp;RF=" target="ue">Mathematical tools for computing</a>' +
" </h4>" +
' <div class="code">' +
' <a id="code_5df3b7279a53cb218ffb5684789f8939" href="/servlet/uFF?OBJET=ue&amp;CODE=MVA003&amp;LANGUE=0&amp;RF=" target="ue">MVA003</a>' +
" </div>" +
" </div>" +
" </div>" +
"</div>";
const el = document.getElementsByClassName("ue")[0];

expect(() => {
TeachingUnit.fromElement(el);
}).toThrow("missing field: credits");
});

test("toggle teaching unit", () => {
const teachingUnit = new TeachingUnit(
"Architecture des machines",
"NFA004",
4,
);

expect(teachingUnit.state).toBe(State.Unselected);
teachingUnit.toggle();
expect(teachingUnit.state).toBe(State.Selected);
teachingUnit.toggle();
expect(teachingUnit.state).toBe(State.Validated);
teachingUnit.toggle();
expect(teachingUnit.state).toBe(State.Unselected);
});
function newHTMLTeachingUnit(title?: string, code?: string, ects?: number) {
let html =
'<div class="ue option clearfix"><div class=" infos-ue"><div class="details clearfix">';

test("observe teaching unit", () => {
class DummyObserver implements Observer {
update(subject: TeachingUnit): void {
subject.state = State.Unselected;
}
if (ects != null) {
html += `<div class="credits">${ects} ECTS<span class="dico"><span class="icon icon-help_simple"></span></span></div>`;
}

const obs = new DummyObserver();
const teachingUnit = new TeachingUnit(
"Architecture des machines",
"NFA004",
4,
);

teachingUnit.attach(obs);
expect(teachingUnit.state).toBe(State.Unselected);
teachingUnit.toggle();

expect(teachingUnit.state).toBe(State.Unselected);

teachingUnit.detach(obs);
teachingUnit.toggle();
expect(teachingUnit.state).toBe(State.Selected);
});

test("detach nonexistent observer", () => {
class DummyObserver implements Observer {
update(subject: TeachingUnit): void {
subject.state = State.Unselected;
}
if (title != null) {
html +=
'<h4 class="titre">' +
` <a id="intitule_5df3b7279a53cb218ffb5684789f8939" href="/servlet/uFF?OBJET=ue&amp;CODE=MVA003&amp;LANGUE=0&amp;RF=" target="ue">${title}</a>` +
"</h4>";
}
const obs = new DummyObserver();
const teachingUnit = new TeachingUnit(
"Architecture des machines",
"NFA004",
4,
);

expect(() => {
teachingUnit.detach(obs);
}).toThrow("Nonexistent observer");
});

test("attach twice observer", () => {
class DummyObserver implements Observer {
update(subject: TeachingUnit): void {
subject.state = State.Unselected;
}
if (code != null) {
html +=
'<div class="code">' +
` <a id="code_5df3b7279a53cb218ffb5684789f8939" href="/servlet/uFF?OBJET=ue&amp;CODE=MVA003&amp;LANGUE=0&amp;RF=" target="ue">${code}</a>` +
"</div>";
}
const obs = new DummyObserver();
const teachingUnit = new TeachingUnit(
"Architecture des machines",
"NFA004",
4,
);
teachingUnit.attach(obs);
expect(() => {

html += "</div></div></div>";

return html;
}

describe("TeachingUnit", () => {
describe("given a valid html element", () => {
test("returns a new valid instance", () => {
document.body.innerHTML = newHTMLTeachingUnit(
"Mathematical tools for computing",
"MVA003",
6,
);
const el = document.getElementsByClassName("ue")[0];

const teachingUnit = TeachingUnit.fromElement(el);

expect(teachingUnit.code).toBe("MVA003");
expect(teachingUnit.title).toBe("Mathematical tools for computing");
expect(teachingUnit.ects).toBe(6);
});
});

describe("given an invalid html element", () => {
test("with missing title throws ValidationError", () => {
document.body.innerHTML = newHTMLTeachingUnit(null, "MVA003", 6);

const el = document.getElementsByClassName("ue")[0];

expect(() => {
TeachingUnit.fromElement(el);
}).toThrow("missing field: title");
});

test("with missing code throws ValidationError", () => {
document.body.innerHTML = newHTMLTeachingUnit(
"Mathematical tools for computing",
null,
6,
);

const el = document.getElementsByClassName("ue")[0];

expect(() => {
TeachingUnit.fromElement(el);
}).toThrow("missing field: code");
});

test("with missing credits throws ValidationError", () => {
document.body.innerHTML = newHTMLTeachingUnit(
"Mathematical tools for computing",
"MVA003",
null,
);

const el = document.getElementsByClassName("ue")[0];

expect(() => {
TeachingUnit.fromElement(el);
}).toThrow("missing field: credits");
});
});

test.each([
[State.Unselected, State.Selected],
[State.Selected, State.Validated],
[State.Validated, State.Unselected],
])("next state after %d to be %d", (currentState, nextState) => {
const teachingUnit = new TeachingUnit(
"Architecture des machines",
"NFA004",
4,
currentState,
);

teachingUnit.toggle();

expect(teachingUnit.state).toBe(nextState);
});

test("notify observer on toggle", () => {
const obs = new DummyObserver();
const teachingUnit = new TeachingUnit(
"Architecture des machines",
"NFA004",
4,
);

teachingUnit.attach(obs);
}).toThrow("Observer has been attached already");
teachingUnit.toggle();

expect(mockCallback).toHaveBeenCalledTimes(1);
expect(mockCallback).toHaveBeenCalledWith(teachingUnit);
});
});
Loading

0 comments on commit ec1ef2a

Please sign in to comment.