443 lines
22 KiB
TypeScript
443 lines
22 KiB
TypeScript
import { FreeDatas2HTML, Pagination, Render, Selector, SortingField } from "../src/FreeDatas2HTML";
|
|
import { ParserForCSV} from "../src/ParserForCSV";
|
|
import { ParserForHTML} from "../src/ParserForHTML";
|
|
import { ParserForJSON} from "../src/ParserForJSON";
|
|
import { RemoteSource} from "../src/RemoteSource";
|
|
|
|
const { compare }=require("natural-orderby");
|
|
const errors=require("../src/errors.js");
|
|
const fixtures=require("./fixtures.js");
|
|
|
|
describe("Tests du script central de FreeDatas2HTML", () =>
|
|
{
|
|
let converter: FreeDatas2HTML;
|
|
|
|
beforeEach( () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV");
|
|
document.body.insertAdjacentHTML('afterbegin', fixtures.datasViewEltHTML);
|
|
});
|
|
|
|
afterEach( () =>
|
|
{
|
|
document.body.removeChild(document.getElementById('fixture'));
|
|
});
|
|
|
|
it("Doit avoir créé une instance de FreeDatas2HTML", () =>
|
|
{
|
|
expect(converter).toBeInstanceOf(FreeDatas2HTML);
|
|
});
|
|
|
|
describe("Test des paramètres de configuration reçus.", () =>
|
|
{
|
|
it("Doit instancier le bon parseur.", () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV");
|
|
expect(converter.parser).toBeInstanceOf(ParserForCSV);
|
|
converter=new FreeDatas2HTML("HTML");
|
|
expect(converter.parser).toBeInstanceOf(ParserForHTML);
|
|
converter=new FreeDatas2HTML("JSON");
|
|
expect(converter.parser).toBeInstanceOf(ParserForJSON);
|
|
});
|
|
|
|
it("S'il est fourni une chaîne vide comme données à parser, elle ne doit pas être passée au parseur.", () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV", "");
|
|
expect(converter.parser.datas2Parse).toEqual("");
|
|
// Idem avec espaces bidons :
|
|
converter=new FreeDatas2HTML("CSV", " ");
|
|
expect(converter.parser.datas2Parse).toEqual("");
|
|
});
|
|
|
|
it("S'il est fourni une chaîne de caractères valide, elle doit être passée au parseur.", () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV", "datas");
|
|
expect(converter.parser.datas2Parse).toEqual("datas");
|
|
});
|
|
|
|
it("Si une source de données distante est fournie en paramètre, elle doit être passée en parseur.", () =>
|
|
{
|
|
const remoteSource=new RemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
|
|
converter=new FreeDatas2HTML("CSV", "", remoteSource);
|
|
expect(converter.parser.datasRemoteSource).toEqual(remoteSource);
|
|
});
|
|
|
|
it("Doit générer une erreur s'il n'est pas trouvé d'élément dans la page pour l'id fourni.", () =>
|
|
{
|
|
expect(() => { return FreeDatas2HTML.checkInDOMById({ id:"dontExist" }); }).toThrowError(errors.converterElementNotFound+"dontExist");
|
|
});
|
|
|
|
it("S'il y a bien un élément trouvé dans la page pour l'id fourni, doit retourner l'élement DOM complété.", () =>
|
|
{
|
|
const eltInDOM=document.getElementById("datas");
|
|
const checkElt=FreeDatas2HTML.checkInDOMById({ id:"datas" });
|
|
expect(checkElt).toEqual({ id:"datas", eltDOM: eltInDOM });
|
|
});
|
|
});
|
|
|
|
describe("Parsage et récupération des données.", () =>
|
|
{
|
|
beforeEach( async () =>
|
|
{
|
|
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
|
|
await converter.run();
|
|
});
|
|
|
|
it("Doit générer une erreur si le parseur ne retourne aucun résultat.", async () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV");
|
|
spyOn(converter.parser, "parse"); // bloque le fonctionnement de parse()
|
|
await expectAsync(converter.run()).toBeRejectedWith(new Error(errors.parserFail));
|
|
});
|
|
|
|
it("Doit générer une erreur si des anomalies sont rencontrées durant le parsage et que cela n'est pas toléré.", async () =>
|
|
{
|
|
const remoteSource=new RemoteSource({ url:"http://localhost:9876/datas/datas-errors1.csv" });
|
|
converter=new FreeDatas2HTML("CSV", "", remoteSource);
|
|
converter.stopIfParseErrors=true;
|
|
await expectAsync(converter.run()).toBeRejectedWith(new Error(errors.parserMeetErrors));
|
|
});
|
|
|
|
it("Ne doit pas générer une erreur si des anomalies sont rencontrées durant le parsage, mais que cela est toléré.", async () =>
|
|
{
|
|
const remoteSource=new RemoteSource({ url:"http://localhost:9876/datas/datas-errors1.csv" });
|
|
converter=new FreeDatas2HTML("CSV", "", remoteSource);
|
|
await expectAsync(converter.run()).toBeResolved();
|
|
});
|
|
|
|
it("Si le parsage s'est bien déroulé, le résultat doit être récupéré.", () =>
|
|
{
|
|
expect(converter.datas).toEqual(converter.parser.parseResults.datas);
|
|
expect(converter.fields).toEqual(converter.parser.parseResults.fields);
|
|
});
|
|
|
|
it("Si le parsage s'est bien déroulé et qu'un élément HTML est renseigné pour recevoir les données, un premier affichage doit être demandé.", async () =>
|
|
{
|
|
spyOn(converter, "refreshView");
|
|
converter.datasViewElt={ id:"datas" };
|
|
await converter.run();
|
|
expect(converter.refreshView).toHaveBeenCalled();
|
|
});
|
|
|
|
it("Si le parsage s'est bien déroulé, mais qu'aucun élément HTML n'est renseigné pour recevoir les données, l'affichage ne doit pas être demandé.", async () =>
|
|
{
|
|
spyOn(converter, "refreshView");
|
|
await converter.run();
|
|
expect(converter.refreshView).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("Tests et configurations après parsage.", () =>
|
|
{
|
|
let simpleSort: (a: number, b: number) => number;
|
|
beforeEach( async () =>
|
|
{
|
|
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
|
|
await converter.run();
|
|
simpleSort = (a: number, b: number) =>
|
|
{
|
|
if(a < b)
|
|
return 1;
|
|
else if(a > b)
|
|
return -1;
|
|
else
|
|
return 0;
|
|
};
|
|
});
|
|
|
|
it("Le test d'existence d'un champ doit retourner false s'il est lancé avant que les données n'aient été parsées.", () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV");
|
|
const check=converter.checkFieldExist(0);
|
|
expect(converter.checkFieldExist(0)).toBeFalse();
|
|
// Dans le cas d'un parsage ne retournant rien, c'est le parseur qui doit générer une erreur.
|
|
});
|
|
|
|
it("Doit retourner false si le numéro de champ n'est pas trouvé dans les données.", () =>
|
|
{
|
|
let check=converter.checkFieldExist(-2);
|
|
expect(check).toBeFalse();
|
|
check=converter.checkFieldExist(1.1);
|
|
expect(check).toBeFalse();
|
|
check=converter.checkFieldExist(10);
|
|
expect(check).toBeFalse();
|
|
});
|
|
|
|
it("Doit retourner true si le numéro de champ est bien trouvé dans les données.", () =>
|
|
{
|
|
let check=converter.checkFieldExist(0);
|
|
expect(check).toBeTrue();
|
|
check=converter.checkFieldExist(2);
|
|
expect(check).toBeTrue();
|
|
});
|
|
|
|
it("Doit générer une erreur si tous les champs devant être affichés ne sont pas présents dans les données reçues.", () =>
|
|
{
|
|
expect(() => { return converter.fields2Rend=[0,2,8]; }).toThrowError(errors.converterFieldNotFound);
|
|
});
|
|
|
|
it("Doit accepter un tableau vide pour la liste de champs à afficher.", () =>
|
|
{
|
|
expect(() => { return converter.fields2Rend=[]; }).not.toThrowError();
|
|
expect(converter.fields2Rend.length).toEqual(0);
|
|
});
|
|
|
|
it("Si tous les champs à afficher sont trouvés dans les données, ils doivent être acceptés.", () =>
|
|
{
|
|
expect(() => { return converter.fields2Rend=[0,1,2]; }).not.toThrowError();
|
|
expect(converter.fields2Rend).toEqual([0,1,2]);
|
|
});
|
|
|
|
it("Doit générer une erreur si une fonction est associée à un champ n'existant pas dans les données.", () =>
|
|
{
|
|
expect(() => { return converter.datasSortingFunctions=[{ datasFieldNb:10, sort:simpleSort }]; }).toThrowError(errors.converterFieldNotFound);
|
|
});
|
|
|
|
it("Doit accepter la fonction associée à un champ, de manière à ce qu'elle soit utilisable pour comparer deux valeurs.", () =>
|
|
{
|
|
expect(() => { return converter.datasSortingFunctions=[{ datasFieldNb:0, sort:simpleSort }]; }).not.toThrowError();
|
|
expect(converter.getSortingFunctionForField(0)).toBeDefined();
|
|
expect([7,9,3,5].sort(converter.getSortingFunctionForField(0).sort)).toEqual([9,7,5,3]);
|
|
});
|
|
});
|
|
|
|
describe("Fonction actualisant l'affichage.", () =>
|
|
{
|
|
beforeEach( async () =>
|
|
{
|
|
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
|
|
await converter.run();// récupére les données sans actualiser affichage car élement HTML non connu
|
|
converter.datasViewElt={ id:"datas" }; // pour la suite, si ! :)
|
|
});
|
|
|
|
it("Doit générer une erreur si appelée avant d'avoir récupérer des données à afficher.", () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV");
|
|
converter.datasViewElt={ id:"datas" };
|
|
expect(() => { return converter.refreshView(); }).toThrowError(errors.converterRefreshFail);
|
|
});
|
|
|
|
it("Doit générer une erreur si appelée sans avoir fourni d'élément HTML où afficher les données.", async () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV");
|
|
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
|
|
await converter.run();
|
|
expect(() => { return converter.refreshView(); }).toThrowError(errors.converterRefreshFail);
|
|
});
|
|
|
|
it("Doit appelé la fonction préparant les données à afficher et transmettre le résultat au moteur de rendu.", () =>
|
|
{
|
|
spyOn(converter, "datas2HTML").and.callThrough();
|
|
converter.refreshView();
|
|
expect(converter.datas2HTML).toHaveBeenCalled();
|
|
expect(converter.datasRender.datas).toEqual(converter.datas2Rend);
|
|
});
|
|
|
|
it("Si des champs à afficher n'ont pas été renseignés, tous ceux trouvés par le parserur doivent tous être transmis au moteur de rendu.", () =>
|
|
{
|
|
converter.refreshView();
|
|
expect(converter.datasRender.fields).toEqual(converter.parser.parseResults.fields);
|
|
});
|
|
|
|
it("Si dans champs à afficher ont été renseignés, ils doivent être transmis au moteur rendu", async () =>
|
|
{
|
|
converter.fields2Rend=[1,2];
|
|
await converter.run();
|
|
expect(converter.datasRender.fields).toEqual([converter.parser.parseResults.fields[1],converter.parser.parseResults.fields[2]]);
|
|
});
|
|
|
|
it("Doit appelé la fonction actualisant le compteur d'enregistrements.", () =>
|
|
{
|
|
spyOn(converter, "datasCounter2HTML");
|
|
converter.refreshView();
|
|
expect(converter.datasCounter2HTML).toHaveBeenCalled();
|
|
});
|
|
|
|
it("Si un élément du DOM est renseigné pour le compteur, il doit afficher le nombre d'enregistrements.", async () =>
|
|
{
|
|
converter.datasCounterElt={ id:"counter" };
|
|
converter.datasCounter2HTML();
|
|
converter.refreshView();
|
|
expect(document.getElementById("counter").textContent).toEqual("118");
|
|
// Y compris quand aucune donnée trouvée :
|
|
converter.parser=new ParserForCSV();
|
|
converter.parser.datas2Parse="name,firstname,city";
|
|
await converter.run();
|
|
expect(document.getElementById("counter").textContent).toEqual("0");
|
|
});
|
|
|
|
it("Doit appelé le moteur de rendu et afficher le résultat dans la page.", async () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV", "name,firstname,birthday\ndoe,john,2000/12/25");
|
|
await converter.run();// parse sans rien afficher
|
|
converter.datasViewElt={ id:"datas" };
|
|
spyOn(converter.datasRender, "rend2HTML").and.callThrough();
|
|
converter.refreshView();
|
|
expect(converter.datasRender.rend2HTML).toHaveBeenCalled();
|
|
// Les données à afficher doivent être assez simples, car certains caractères peuvent être remplacés par innerHTML (exemples :"<" ou ">")
|
|
expect(document.getElementById("datas").innerHTML).toEqual(converter.datasRender.rend2HTML());
|
|
});
|
|
|
|
it("Si un élément HTML devant affiché le nombre de résultats est connu, il doit être actualisé.", () =>
|
|
{
|
|
converter.datasCounterElt={ id: "counter" };
|
|
converter.refreshView();
|
|
expect(document.getElementById("counter").innerHTML).toEqual(""+converter.nbDatasValid);
|
|
});
|
|
|
|
it("Si des champs de classement existent, leur code HTML doit être actualisé.", () =>
|
|
{
|
|
converter.refreshView(); // nécessaire pour que les champs soit trouvés dans le HTML
|
|
const sortingField1=new SortingField(converter, 0);
|
|
const sortingField2=new SortingField(converter, 1);
|
|
converter.datasSortingFields=[sortingField1,sortingField2];
|
|
spyOn(sortingField1, "field2HTML");
|
|
spyOn(sortingField2, "field2HTML");
|
|
converter.refreshView();
|
|
expect(sortingField1.field2HTML).toHaveBeenCalled();
|
|
expect(sortingField2.field2HTML).toHaveBeenCalled();
|
|
});
|
|
|
|
it("Si une pagination est configurée, le code HTML listant les pages doit être actualisé.", () =>
|
|
{
|
|
const pagination=new Pagination(converter, { id:"pages" }, "Page à afficher :");
|
|
converter.pagination=pagination;
|
|
spyOn(pagination, "pages2HTML");
|
|
converter.refreshView();
|
|
expect(pagination.pages2HTML).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("Fonction filtrant les données à afficher.", () =>
|
|
{
|
|
beforeEach( async () =>
|
|
{
|
|
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
|
|
converter.datasViewElt={ id:"datas" };
|
|
await converter.run();
|
|
});
|
|
|
|
it("Si une liste de champs à afficher a été renseignée, elle doit être prise en compte.", async () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV","id,firstname,name,birthday\n1,john,doe,2001/12/25\n2,donald,duck,1934/06/09");
|
|
converter.datasViewElt={ id:"datas" };
|
|
await converter.run();
|
|
converter.fields2Rend=[1,2];
|
|
converter.refreshView();
|
|
expect(converter.datas2Rend).toEqual([{ firstname:"john", name:"doe" }, { firstname:"donald", name:"duck" }]);
|
|
});
|
|
|
|
it("Par défaut, tous les champs trouvés doivent être affichés.", async () =>
|
|
{
|
|
converter=new FreeDatas2HTML("CSV","id,firstname,name,birthday\n1,john,doe,2001/12/25\n2,donald,duck,1934/06/09");
|
|
converter.datasViewElt={ id:"datas" };
|
|
await converter.run();
|
|
converter.refreshView();
|
|
expect(converter.datas2Rend).toEqual([{ id:"1", firstname:"john", name:"doe", birthday:"2001/12/25" }, { id:"2", firstname:"donald", name:"duck", birthday:"1934/06/09" }]);
|
|
});
|
|
|
|
it("Si un champ de classement est activé par l'utilisateur, les données doivent être classées via ce champ.", () =>
|
|
{
|
|
// Compliqué de tester avec spyOn que sort() a été appelée avec la bonne fonction de classement en paramètre
|
|
// Donc je compare les résultats à ceux attendus
|
|
const sortingField=new SortingField(converter, 0);
|
|
converter.datasSortingFields=[sortingField];
|
|
sortingField.field2HTML();
|
|
const fieldName=converter.fields[0];
|
|
const getTHLink=document.querySelector("th a") as HTMLElement;
|
|
getTHLink.click();
|
|
converter.datas.sort( (a, b) => compare( {order: "asc"} )(a[fieldName], b[fieldName]));
|
|
expect(converter.datas2Rend).toEqual(converter.datas);
|
|
getTHLink.click();
|
|
converter.datas.sort( (a, b) => compare( {order: "desc"} )(a[fieldName], b[fieldName]));
|
|
expect(converter.datas2Rend).toEqual(converter.datas);
|
|
getTHLink.click();
|
|
converter.datas.sort( (a, b) => compare( {order: "asc"} )(a[fieldName], b[fieldName]));
|
|
expect(converter.datas2Rend).toEqual(converter.datas);
|
|
});
|
|
|
|
it("Si une fonction de classement est définie pour le champ activé par l'utilisateur, elle doit être prise en compte.", () =>
|
|
{
|
|
const mySort = (a: any, b: any, order: "asc"|"desc" = "asc") =>
|
|
{
|
|
const values = [ "> 100000", "> 1 et < 100 000", "≤ 1", "Traces", "Inexistant"];
|
|
if(order === "desc")
|
|
values.reverse();
|
|
if(values.indexOf(a) > values.indexOf(b))
|
|
return -1;
|
|
else if(values.indexOf(a) < values.indexOf(b))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
};
|
|
converter.datasSortingFunctions=[{ datasFieldNb:4, sort:mySort }];
|
|
const sortingField=new SortingField(converter, 4);
|
|
converter.datasSortingFields=[sortingField];
|
|
sortingField.field2HTML();
|
|
const fieldName=converter.fields[0];
|
|
const getTHLink=document.querySelector("th a") as HTMLElement;
|
|
getTHLink.click();
|
|
converter.datas.sort( (a, b) => { return mySort(a[fieldName], b[fieldName], "asc"); });
|
|
expect(converter.datas2Rend).toEqual(converter.datas);
|
|
getTHLink.click();
|
|
converter.datas.sort( (a, b) => { return mySort(a[fieldName], b[fieldName], "desc"); });
|
|
expect(converter.datas2Rend).toEqual(converter.datas);
|
|
getTHLink.click();
|
|
converter.datas.sort( (a, b) => { return mySort(a[fieldName], b[fieldName], "asc"); });
|
|
expect(converter.datas2Rend).toEqual(converter.datas);
|
|
});
|
|
|
|
it("Si des options de pagination sont activées par l'utilisateur, seules les données de la page choisie doivent être retournées.", () =>
|
|
{
|
|
const pagination=new Pagination(converter, { id:"pages" }, "Page à afficher :");
|
|
pagination.options={ displayElement: { id:"paginationOptions" }, values: [10,20,50] , name: "Choix de pagination :" };
|
|
pagination.selectedValue=10;
|
|
converter.pagination=pagination;
|
|
pagination.options2HTML();
|
|
converter.refreshView(); // il ne doit plus rester que les 10 premiers enregistrement
|
|
expect(converter.datas2Rend).toEqual(converter.datas.slice(0,10));
|
|
// Sélection de la dernière page, avec une pagination à 50 :
|
|
const selectPagination=document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
|
|
selectPagination.value="3";
|
|
selectPagination.dispatchEvent(new Event('change'));
|
|
const selectPage=document.getElementById("freeDatas2HTMLPagesSelector") as HTMLInputElement;
|
|
selectPage.value="3";
|
|
selectPage.dispatchEvent(new Event('change'));
|
|
expect(converter.datas2Rend).toEqual(converter.datas.slice(100));
|
|
// Annulation de la pagination. Affiche toutes les données :
|
|
selectPagination.value="0";
|
|
selectPagination.dispatchEvent(new Event('change'));
|
|
expect(converter.datas2Rend).toEqual(converter.datas);
|
|
});
|
|
|
|
it("Si des filtres sont déclarés, ils doivent tous être appelés pour tester les données à afficher.", () =>
|
|
{
|
|
const filter1=new Selector(converter, 3, { id:"selector1"} );
|
|
filter1.filter2HTML();
|
|
const filter2=new Selector(converter, 4, { id:"selector2"} );
|
|
converter.datasFilters=[filter1,filter2];
|
|
// si le 1er n'est pas réellement lancé, le second est bloqué, car cela retourne un "false"
|
|
spyOn(filter1, "dataIsOk").and.callThrough();
|
|
spyOn(filter2, "dataIsOk");
|
|
converter.refreshView();
|
|
expect(filter1.dataIsOk).toHaveBeenCalledTimes(118);
|
|
expect(filter2.dataIsOk).toHaveBeenCalledTimes(118);
|
|
});
|
|
|
|
it("Quand il y a plusieurs filtres, seules les données positives aux précédents sont testées par les suivants.", () =>
|
|
{
|
|
const filter1=new Selector(converter, 3, { id:"selector1"} );
|
|
filter1.filter2HTML();
|
|
const filter2=new Selector(converter, 4, { id:"selector2"} );
|
|
converter.datasFilters=[filter1,filter2];
|
|
const selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
|
selectElement.value="2"; // correspond à 4 enregistrements
|
|
spyOn(filter1, "dataIsOk").and.callThrough();
|
|
spyOn(filter2, "dataIsOk");
|
|
// Doit vraiment être lancé pour que la valeur sélectionnée soit retenue pour filter les données
|
|
selectElement.dispatchEvent(new Event('change'));
|
|
expect(filter1.dataIsOk).toHaveBeenCalledTimes(118);
|
|
expect(filter2.dataIsOk).toHaveBeenCalledTimes(4);
|
|
});
|
|
});
|
|
}); |