Version remaniée de la classe principale + réécriture de ses tests.

This commit is contained in:
Fabrice PENHOËT 2021-10-26 18:01:23 +02:00
parent 8c0b9b2aa2
commit 739b83f365
6 changed files with 393 additions and 340 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "freedatas2html", "name": "freedatas2html",
"version": "0.9.0", "version": "0.9.5",
"description": "Conversion and display of data in different formats (CSV, JSON, HTML) with the possibility of filtering, classifying and paginating the results.", "description": "Conversion and display of data in different formats (CSV, JSON, HTML) with the possibility of filtering, classifying and paginating the results.",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -1,7 +1,7 @@
const { compare }=require('natural-orderby'); const { compare }=require("natural-orderby");
const errors=require("./errors.js"); const errors=require("./errors.js");
import { Counter, DatasRenders, DOMElement, Filters, Paginations, Parsers, ParseErrors, RemoteSources, SortingFields, SortingFunctions } from "./interfaces"; import { DatasRenders, DOMElement, Filters, Paginations, Parsers, ParseResults, RemoteSources, SortingFields, SortingFunctions } from "./interfaces";
import { Pagination} from "./Pagination"; import { Pagination} from "./Pagination";
import { ParserForCSV} from "./ParserForCSV"; import { ParserForCSV} from "./ParserForCSV";
import { ParserForHTML} from "./ParserForHTML"; import { ParserForHTML} from "./ParserForHTML";
@ -12,62 +12,50 @@ import { SortingField } from "./SortingField";
export class FreeDatas2HTML export class FreeDatas2HTML
{ {
// L'élément HTML où afficher les données. Laisser à undefined si non affichées : // Les paramètres de base :
private _datasViewElt: DOMElement|undefined=undefined; private _datasViewElt: DOMElement|undefined=undefined;
// Le moteur de rendu pour préparer l'affichage des données
public datasRender: DatasRenders; public datasRender: DatasRenders;
// Le code HTML résultant : public parser: Parsers;
public datasHTML: string = ""; public stopIfParseErrors: boolean=false;
// Le parseur :
public parser: Parsers; // public pour permettre de charger un parseur tiers après instanciation // Les options (classement, pagination, filtres...) :
// Type de données à traiter private _datasCounterElt: DOMElement|undefined=undefined;
public datasType: "CSV"|"HTML"|"JSON"|undefined; private _datasSortingFunctions: SortingFunctions[]=[];
public datasFilters: Filters[]=[];
public datasSortingFields: SortingFields[]=[];
public datasSortedField: SortingFields|undefined;
public pagination: Paginations|undefined;
// Les résultats :
private _fields: ParseResults["fields"]=[];
private _datas: ParseResults["datas"]=[];
private _datas2Rend: {[index: string]:string}[]=[];
private _nbDatasValid: number=0;
// Le nom des champs trouvés dans les données : // Le parseur, comme le render sont initialisés, mais peuvent être modifiés par des instances d'autres classes respectant leur interface.
public fields: string[]|undefined=undefined; constructor(datasFormat:"CSV"|"HTML"|"JSON", datas2Parse="", datasRemoteSource?:RemoteSources)
// Les données à proprement parler :
public datas: {[index: string]:string}[]=[];
// Les erreurs rencontrées durant le traitement des données reçues :
public parseErrors: ParseErrors[]|undefined;
// Doit-on tout arrêter si une erreur est rencontrée durant le traitement ?
public stopIfParseErrors: boolean = false;
// Les fonctions spécifiques de classement pour certains champs :
private _datasSortingFunctions: SortingFunctions[] = [];
// Les filtres possible sur certains champs :
datasFilters: Filters[] = [];
// Les champs pouvant être classés :
datasSortingFields: SortingFields[] = [];
// La dernier champ pour lequel le classement a été demandé :
datasSortedField: SortingFields|undefined;
// Éventuelle pagination :
pagination: Paginations|undefined;
// Affichage du nombre total de lignes de données (optionnel) :
private _datasCounter: Counter = {};
// J'initialiser avec des valeurs par défaut pouvant être surchargées par les setters
// Attention, si je transmets datasRemoteSource ici, il ne passera pas par un new RemoteSources()
// Il doit donc déjà avoir été testé
constructor(datasType:"CSV"|"HTML"|"JSON", datas2Parse="", datasRemoteSource?:RemoteSources)
{ {
this.datasRender=new Render(); this.datasRender=new Render();
switch (datasType) switch (datasFormat)
{ {
case "CSV": case "CSV":
this.parser=new ParserForCSV(datasRemoteSource); this.parser=new ParserForCSV();
break; break;
case "HTML": case "HTML":
this.parser=new ParserForHTML(datasRemoteSource); this.parser=new ParserForHTML();
break; break;
case "JSON": case "JSON":
this.parser=new ParserForJSON(datasRemoteSource); this.parser=new ParserForJSON();
break; break;
} }
if(datas2Parse.trim() !== "") if(datas2Parse.trim() !== "")
this.parser.datas2Parse=datas2Parse.trim(); this.parser.datas2Parse=datas2Parse.trim();
else if(datasRemoteSource !== undefined)
this.parser.setRemoteSource(datasRemoteSource);
} }
// Vérifie s'il y a bien un élément dans le DOM pour l'id fourni // Vérifie s'il y a bien un élément dans le DOM pour l'id fourni.
// Fonction statique également utilisée par les autres classes.
public static checkInDOMById(checkedElt: DOMElement) : DOMElement public static checkInDOMById(checkedElt: DOMElement) : DOMElement
{ {
let searchEltInDOM=document.getElementById(checkedElt.id); let searchEltInDOM=document.getElementById(checkedElt.id);
@ -79,24 +67,49 @@ export class FreeDatas2HTML
return checkedElt; return checkedElt;
} }
} }
// Vérifie qu'un champ existe bien dans les données
public checkFieldExist(nb: number) : boolean
{
if(this.fields === undefined || this.fields[nb] === undefined)
return false;
else
return true;
}
// Vérifie que l'élément devant afficher les données existe dans le DOM :
set datasViewElt(elt: DOMElement) set datasViewElt(elt: DOMElement)
{ {
this._datasViewElt=FreeDatas2HTML.checkInDOMById(elt); this._datasViewElt=FreeDatas2HTML.checkInDOMById(elt);
} }
// Vérifie que les numéros de champs pour lesquels il y a des fonctions de classement spécifiques sont cohérents set datasCounterElt(counterDisplayElement: DOMElement)
// ! Ne peut être testé qu'après avoir reçu les données {
this._datasCounterElt=FreeDatas2HTML.checkInDOMById(counterDisplayElement);
}
get datas(): ParseResults["datas"]
{
return this._datas;
}
get fields(): ParseResults["fields"]
{
return this._fields;
}
get datas2Rend(): {[index: string]:string}[]
{
return this._datas2Rend;
}
get nbDatasValid(): number
{
return this._nbDatasValid;
}
// Vérifie qu'un champ existe bien dans les données parsées.
// Utilisée par les autres classes.
public checkFieldExist(nb: number) : boolean
{
if(this.parser.parseResults === undefined || this.parser.parseResults.fields[nb] === undefined)
return false;
else
return true;
}
// Vérifie que les numéros de champs pour lesquels il y a des fonctions de classement spécifiques sont cohérents.
// ! Ne peut donc être utilisé qu'après avoir parsé les données.
set datasSortingFunctions(SortingFunctions: SortingFunctions[]) set datasSortingFunctions(SortingFunctions: SortingFunctions[])
{ {
this._datasSortingFunctions=[]; this._datasSortingFunctions=[];
@ -108,22 +121,7 @@ export class FreeDatas2HTML
this._datasSortingFunctions.push(checkedFunction); this._datasSortingFunctions.push(checkedFunction);
} }
} }
// On teste l'id de l'élément du DOM où afficher le compteur s'il est fourni
set datasCounter(counterDisplayElement: DOMElement)
{
this._datasCounter={ displayElement: FreeDatas2HTML.checkInDOMById(counterDisplayElement), value: undefined };
}
// Retourne la valeur du compteur de lignes (sans l'élément DOM)
public getDatasCounterValue(): number|undefined
{
if(this._datasCounter !== undefined && this._datasCounter.value != undefined)
return this._datasCounter.value;
else
return undefined;
}
// Retourne l'éventuelle fonction spécifique de classement associée à un champ // Retourne l'éventuelle fonction spécifique de classement associée à un champ
public getSortingFunctionForField(datasFieldNb: number): SortingFunctions|undefined public getSortingFunctionForField(datasFieldNb: number): SortingFunctions|undefined
{ {
@ -135,27 +133,22 @@ export class FreeDatas2HTML
return undefined; return undefined;
} }
// Traite les données fournies via le parseur adhoc // Lancer le parsage des données et lance éventuellement un 1er affichage.
// Si un élément du DOM est fourni, appelle la fonction affichant les données
public async run(): Promise<any> public async run(): Promise<any>
{ {
await this.parser.parse(); await this.parser.parse();
if(this.parser.parseResults === undefined) if(this.parser.parseResults === undefined) // mais le parseur devrait lui-même générer une erreur avant
throw new Error(errors.parserFail); throw new Error(errors.parserFail);
else else
{ {
if(this.parser.parseResults.fields === undefined) if(this.stopIfParseErrors && this.parser.parseResults.errors !== undefined)
throw new Error(errors.parserDatasNotFound);
else if(this.stopIfParseErrors && this.parser.parseResults.errors !== undefined)
throw new Error(errors.parserMeetErrors); throw new Error(errors.parserMeetErrors);
else else
{ {
// revoir l'intérêt de copier ces 3 attributs ? this._fields=this.parser.parseResults.fields;
this.fields=this.parser.parseResults.fields; this._datas=this.parser.parseResults.datas;
this.datas=this.parser.parseResults.datas; // Les champs ne bougeront plus, donc on peut déjà les passer au moteur de rendu :
this.parseErrors=this.parser.parseResults.errors; this.datasRender.fields=this._fields;
// Les champs ne bougeront plus donc on peut aussi les passer au moteur de rendu
this.datasRender.fields=this.fields;
if(this._datasViewElt !== undefined) if(this._datasViewElt !== undefined)
this.refreshView(); this.refreshView();
return true; return true;
@ -163,81 +156,83 @@ export class FreeDatas2HTML
} }
} }
// Actualise l'affichage des données.
// Méthode également appelée par les autres classes.
public refreshView() : void public refreshView() : void
{ {
if(this.fields === undefined || this._datasViewElt === undefined || this._datasViewElt.eltDOM === undefined) if(this._fields.length === 0 || this._datasViewElt === undefined)
throw new Error(errors.converterRefreshFail); throw new Error(errors.converterRefreshFail);
else else
{ {
this.datasHTML=this.createDatas2Display(this.fields, this.datas); this._datas2Rend=this.datas2HTML();
this._datasViewElt.eltDOM.innerHTML=this.datasHTML; this.datasRender.datas= this._datas2Rend;
// On réactive les éventuels champs de classement qui ont été écrasés this._datasViewElt.eltDOM!.innerHTML=this.datasRender.rend2HTML(); // "!", car l'existence de "eltDOM" est testée par le setter.
// Actualisation de l'éventuel compteur :
if(this._datasCounterElt !== undefined)
this._datasCounterElt.eltDOM!.innerHTML=""+this._nbDatasValid; // même remarque pour le "!".
// Réactivation des éventuels champs de classement qui ont pu être écrasés :
for(let field of this.datasSortingFields) for(let field of this.datasSortingFields)
field.field2HTML(); field.field2HTML();
// Tout réaffichage peut entraîner une modification du nombre de pages (évolution filtres, etc.)
if(this.pagination !== undefined)
this.pagination.pages2HTML();
} }
} }
private createDatas2Display(fields: string[], datas: any[]) : string // Fonction sélectionnant les données à afficher en prenant en compte les éventuels filtres, la pagination, etc.
public datas2HTML() : {[index: string]:string}[]
{ {
// Dois-je classer les données par rapport à un champ ? // Dois-je classer les données par rapport à un champ ?
if(this.datasSortedField !== undefined && this.datasSortedField.datasFieldNb !==undefined) if(this.datasSortedField !== undefined)
{ {
const field=fields[this.datasSortedField.datasFieldNb]; const field=this._fields[this.datasSortedField.datasFieldNb];
const fieldOrder=this.datasSortedField.order; const fieldOrder=this.datasSortedField.order;
// Une fonction spécifique de classement a-t-elle été définie ? // Une fonction spécifique de classement a-t-elle été définie pour ce champ ?
if(this.getSortingFunctionForField(this.datasSortedField.datasFieldNb) !== undefined) if(this.getSortingFunctionForField(this.datasSortedField.datasFieldNb) !== undefined)
{ {
let myFunction=this.getSortingFunctionForField(this.datasSortedField.datasFieldNb); const myFunction=this.getSortingFunctionForField(this.datasSortedField.datasFieldNb);
datas.sort( (a, b) => { return myFunction!.sort(a[field], b[field], fieldOrder); }); this._datas.sort( (a, b) => { return myFunction!.sort(a[field], b[field], fieldOrder); });
} }
else else
datas.sort( (a, b) => compare( {order: fieldOrder} )(a[field], b[field])); this._datas.sort( (a, b) => compare( {order: fieldOrder} )(a[field], b[field]));
} }
// Dois-je prendre en compte une pagination ? // Dois-je prendre en compte une pagination ?
let firstData=0; let firstData=0;
if (this.pagination !== undefined && this.pagination.selectedValue !== undefined && this.pagination.pages !== undefined && this.pagination.pages.selectedValue !== undefined) if (this.pagination !== undefined && this.pagination.selectedValue !== undefined && this.pagination.pages !== undefined && this.pagination.pages.selectedValue !== undefined)
firstData=this.pagination.selectedValue*(this.pagination.pages.selectedValue-1); firstData=this.pagination.selectedValue*(this.pagination.pages.selectedValue-1);
let maxData = (this.pagination !== undefined && this.pagination.selectedValue !== undefined) ? this.pagination.selectedValue : datas.length+1; let maxData=(this.pagination !== undefined && this.pagination.selectedValue !== undefined) ? this.pagination.selectedValue : this._datas.length;
// Création du tableau des données à afficher : // Création du tableau des données à afficher :
const datas2Display=[]; const datas2Display=[];
let nbVisible=0, nbTotal=0; let nbVisible=0, nbTotal=0;
for (let row in datas) for (let row in this._datas)
{ {
let visible=true; // Pour être affichée une ligne doit valider tous les filtres connus
if(this.datasFilters.length !== 0) let valid=true, i=0;
while(this.datasFilters[i] !== undefined && valid === true)
{ {
let i=0; valid=this.datasFilters[i].dataIsOk(this._datas[row]);
while(this.datasFilters[i] !== undefined && visible===true) i++;
{
visible=this.datasFilters[i].dataIsOk(datas[row]);
i++;
}
} }
if(visible && nbTotal >= firstData && nbVisible < maxData) if(valid && nbTotal >= firstData && nbVisible < maxData)
{ {
datas2Display.push(datas[row]); datas2Display.push(this._datas[row]);
nbVisible++; nbVisible++;
nbTotal++; nbTotal++;
} }
else if(visible) else if(valid)
nbTotal++; nbTotal++;
} }
if(this._datasCounter !== undefined && this._datasCounter.displayElement !== undefined) this._nbDatasValid=nbTotal;
{ return datas2Display;
this._datasCounter.value=nbTotal;
this._datasCounter.displayElement.eltDOM!.innerHTML=""+nbTotal; // eltDOM ne peut être undefined (cf setter)
}
// Tout réaffichage peut entraîner une modification du nombre de pages (évolution filtres, etc.)
if(this.pagination !== undefined)
this.pagination.pages2HTML(nbTotal);
this.datasRender.datas=datas2Display;
return this.datasRender.rend2HTML();
} }
} }
// Permet l'appel des dépendances via un seul script // Permet l'appel des principales classes du module via un seul script :
export { Pagination } from "./Pagination"; export { Pagination } from "./Pagination";
export { Render} from "./Render"; export { Render} from "./Render";
export { Selector } from "./Selector"; export { Selector } from "./Selector";

View File

@ -33,7 +33,7 @@ module.exports =
selectorFieldIsEmpty: "Aucune donnée trouvée pour le champ du filtre", selectorFieldIsEmpty: "Aucune donnée trouvée pour le champ du filtre",
selectorFieldNotFound: "Au moins un des champs devant servir à filtrer les données n'existe pas dans le fichier.", selectorFieldNotFound: "Au moins un des champs devant servir à filtrer les données n'existe pas dans le fichier.",
selectorSelectedIndexNotFound: "La valeur sélectionnée n'a pas été trouvée dans la liste des champs.", selectorSelectedIndexNotFound: "La valeur sélectionnée n'a pas été trouvée dans la liste des champs.",
sortingFieldNeedDatas: "Le création d'un champ de classement nécessite la transmission de la liste des champs.", sortingFieldNeedDatas: "La création d'un champ de classement nécessite la transmission de la liste des champs.",
sortingFieldNotFound: "Au moins un des champs devant permettre de classer les données n'existe pas dans le fichier.", sortingFieldNotFound: "Au moins un des champs devant permettre de classer les données n'existe pas dans le fichier.",
sortingFieldsNbFail: "Le nombre de champs trouvés dans le DOM ne correspond pas à celui des données à classer.", sortingFieldsNbFail: "Le nombre de champs trouvés dans le DOM ne correspond pas à celui des données à classer.",
sortingFieldsNotInHTML: "Les champs pouvant servir à classer les données n'ont pas été trouvés dans le DOM.", sortingFieldsNotInHTML: "Les champs pouvant servir à classer les données n'ont pas été trouvés dans le DOM.",

View File

@ -1,8 +1,3 @@
export interface Counter
{
displayElement?: DOMElement; // peut être undefined si on ne souhaite pas d'affichage automatique dans la page
value?: number; // undefined jusqu'à recevoir sa première valeur
}
export interface DatasRenders export interface DatasRenders
{ {
fields: string[]; fields: string[];
@ -39,7 +34,7 @@ export interface Paginations
selectedValue: number|undefined; selectedValue: number|undefined;
pages: PaginationsPages; pages: PaginationsPages;
options2HTML(): void; options2HTML(): void;
pages2HTML(nbTotal:number) : void; pages2HTML() : void;
} }
export interface PaginationsOptions export interface PaginationsOptions
{ {

View File

@ -11,7 +11,6 @@ module.exports =
sortingColumn1HTML: '<a href="#freeDatas2HTMLSorting0" id="freeDatas2HTMLSorting0">Z (numéro atomique)</a>', sortingColumn1HTML: '<a href="#freeDatas2HTMLSorting0" id="freeDatas2HTMLSorting0">Z (numéro atomique)</a>',
sortingColumn2HTML: '<a href="#freeDatas2HTMLSorting2" id="freeDatas2HTMLSorting2">Symbole</a>', sortingColumn2HTML: '<a href="#freeDatas2HTMLSorting2" id="freeDatas2HTMLSorting2">Symbole</a>',
selectorForPagination: '<label for="freeDatas2HTMLPaginationSelector">Choix de pagination : </label><select name="freeDatas2HTMLPaginationSelector" id="freeDatas2HTMLPaginationSelector"><option value="0">----</option><option value="1">10</option><option value="2">20</option><option value="3">50</option><option value="4">500</option></select>', selectorForPagination: '<label for="freeDatas2HTMLPaginationSelector">Choix de pagination : </label><select name="freeDatas2HTMLPaginationSelector" id="freeDatas2HTMLPaginationSelector"><option value="0">----</option><option value="1">10</option><option value="2">20</option><option value="3">50</option><option value="4">500</option></select>',
selectorFor2Pages: '<label for="freeDatas2HTMLPagesSelector">Page à afficher :</label><select name="freeDatas2HTMLPagesSelector" id="freeDatas2HTMLPagesSelector"><option value="1">1</option><option value="2">2</option></select>',
selectorForManyPages: '<label for="freeDatas2HTMLPagesSelector">Page à afficher :</label><select name="freeDatas2HTMLPagesSelector" id="freeDatas2HTMLPagesSelector"><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option><option value="9">9</option><option value="10">10</option><option value="11">11</option><option value="12">12</option></select>', selectorForManyPages: '<label for="freeDatas2HTMLPagesSelector">Page à afficher :</label><select name="freeDatas2HTMLPagesSelector" id="freeDatas2HTMLPagesSelector"><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option><option value="9">9</option><option value="10">10</option><option value="11">11</option><option value="12">12</option></select>',
firstLineForPageSelection1:"<td>51</td><td>Antimoine</td><td>Sb</td><td>Métalloïde</td><td>&gt; 1 et &lt; 100 000</td>", firstLineForPageSelection1:"<td>51</td><td>Antimoine</td><td>Sb</td><td>Métalloïde</td><td>&gt; 1 et &lt; 100 000</td>",
lastLineForPageSelection1:"<td>100</td><td>Fermium</td><td>Fm</td><td>Actinide</td><td>Inexistant</td>", lastLineForPageSelection1:"<td>100</td><td>Fermium</td><td>Fm</td><td>Actinide</td><td>Inexistant</td>",

View File

@ -1,18 +1,20 @@
import { FreeDatas2HTML, Render} from "../src/FreeDatas2HTML"; 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 errors=require("../src/errors.js");
const fixtures=require("./fixtures.js"); const fixtures=require("./fixtures.js");
/// EN CHANTIER !!! describe("Tests du script central de FreeDatas2HTML", () =>
/// Tests à revoir après avoir fait le tour des autres classes
/*
describe("Test du script central de FreeDatas2HTML", () =>
{ {
let converter: FreeDatas2HTML; let converter: FreeDatas2HTML;
beforeEach( () => beforeEach( () =>
{ {
converter=new FreeDatas2HTML("CSV"); converter=new FreeDatas2HTML("CSV");
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
document.body.insertAdjacentHTML('afterbegin', fixtures.datasViewEltHTML); document.body.insertAdjacentHTML('afterbegin', fixtures.datasViewEltHTML);
}); });
@ -26,26 +28,139 @@ describe("Test du script central de FreeDatas2HTML", () =>
expect(converter).toBeInstanceOf(FreeDatas2HTML); expect(converter).toBeInstanceOf(FreeDatas2HTML);
}); });
describe("Test des données de configuration reçues.", () => describe("Test des paramètres de configuration reçus.", () =>
{ {
it("Doit générer une erreur s'il n'y a pas d'élément dans la page pour l'id fourni.", () => 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"); expect(() => { return FreeDatas2HTML.checkInDOMById({ id:"dontExist" }); }).toThrowError(errors.converterElementNotFound+"dontExist");
}); });
it("S'il y a bien un élément dans la page pour l'id fourni, doit retourner l'élement DOM complété.", () => 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 eltInDOM=document.getElementById("datas");
const checkElt=FreeDatas2HTML.checkInDOMById({ id:"datas" }); const checkElt=FreeDatas2HTML.checkInDOMById({ id:"datas" });
expect(checkElt).toEqual({ id:"datas", eltDOM: eltInDOM }); expect(checkElt).toEqual({ id:"datas", eltDOM: eltInDOM });
}); });
});
it("Doit retourner false si un numéro de champ n'est pas trouvé dans les données.", async () =>
describe("Parsage et récupération des données.", () =>
{
beforeEach( async () =>
{ {
let check=converter.checkFieldExist(2); // aucune donnée chargée, donc le champ ne peut être trouvé converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
expect(check).toBeFalse();
await converter.run(); await converter.run();
check=converter.checkFieldExist(-2); });
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é, la liste des champs trouvés doit être transmise au moteur de rendu sans altération.", () =>
{
expect(converter.datasRender.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 va 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(); expect(check).toBeFalse();
check=converter.checkFieldExist(1.1); check=converter.checkFieldExist(1.1);
expect(check).toBeFalse(); expect(check).toBeFalse();
@ -53,149 +168,135 @@ describe("Test du script central de FreeDatas2HTML", () =>
expect(check).toBeFalse(); expect(check).toBeFalse();
}); });
it("Doit retourner true si un numéro de champ est bien trouvé dans les données.", async () => it("Doit retourner true si le numéro de champ est bien trouvé dans les données.", () =>
{ {
await converter.run();
let check=converter.checkFieldExist(0); let check=converter.checkFieldExist(0);
expect(check).toBeTrue(); expect(check).toBeTrue();
check=converter.checkFieldExist(2); check=converter.checkFieldExist(2);
expect(check).toBeTrue(); expect(check).toBeTrue();
}); });
it("Doit générer une erreur si une fonction est associée à un champ n'existant pas dans les données.", async () => it("Doit générer une erreur si une fonction est associée à un champ n'existant pas dans les données.", () =>
{ {
const simpleSort = (a: any, b: any) =>
{
if(a < b)
return 1;
else if(a > b)
return -1;
else
return 0;
};
expect(() => { return converter.datasSortingFunctions=[{ datasFieldNb:0, sort:simpleSort }]; }).toThrowError(errors.converterFieldNotFound); // données non chargées
converter=new FreeDatas2HTML("CSV");
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
await converter.run();
expect(() => { return converter.datasSortingFunctions=[{ datasFieldNb:10, sort:simpleSort }]; }).toThrowError(errors.converterFieldNotFound); 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.", async () => it("Doit accepter la fonction associée à un champ, de manière à ce qu'elle soit utilisable pour comparer deux valeurs.", () =>
{ {
const simpleSort = (a: any, b: any) => expect(() => { return converter.datasSortingFunctions=[{ datasFieldNb:0, sort:simpleSort }]; }).not.toThrowError();
{
if(a < b)
return 1;
else if(a > b)
return -1;
else
return 0;
};
await converter.run();
converter.datasSortingFunctions=[{ datasFieldNb:0, sort:simpleSort }];
expect(converter.getSortingFunctionForField(0)).toBeDefined(); expect(converter.getSortingFunctionForField(0)).toBeDefined();
expect([7,9,3,5].sort(converter.getSortingFunctionForField(0).sort)).toEqual([9,7,5,3]); expect([7,9,3,5].sort(converter.getSortingFunctionForField(0).sort)).toEqual([9,7,5,3]);
}); });
}); });
describe("Affichage des données reçues.", () => describe("Fonction actualisant l'affichage.", () =>
{ {
it("Doit générer une erreur si des données n'ont pas été importées.", async () => beforeEach( async () =>
{ {
// Parseur non lancé : converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
expect(() => { return converter.refreshView(); }).toThrowError(errors.converterRefreshFail); await converter.run();// récupére les données sans actualiser affichage car élement HTML non connu
// Lancé, mais sur un fichier vide : à revoir, car c'est le parseur qui génère d'abord une erreur converter.datasViewElt={ id:"datas" }; // pour la suite, si ! :)
//converter=new FreeDatas2HTML("CSV","", { url:"http://localhost:9876/datas/nodatas.csv"});
//await converter.run();
//expect(() => { return converter.refreshView(); }).toThrowError(errors.converterRefreshFail);
}); });
it("Doit générer une erreur si l'élément du DOM où afficher les données est inconnu.", async () => it("Doit générer une erreur si appelée avant d'avoir récupérer des données à afficher.", () =>
{
await converter.run();
expect(() => { return converter.refreshView(); }).toThrowError(errors.converterRefreshFail);
});
it("Ne doit pas générer d'erreur si les informations nécessaires sont ok.", async () =>
{ {
converter=new FreeDatas2HTML("CSV");
converter.datasViewElt={ id:"datas" }; 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(); await converter.run();
expect(() => { return converter.refreshView(); }).not.toThrowError(); 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("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("Doit générer une erreur, si la moindre erreur est rencontrée durant la parsage et que cela n'est pas accepté.", async () => it("Si des champs de classement existent, leur code HTML doit être actualisé.", () =>
{ {
converter=new FreeDatas2HTML("CSV"); converter.refreshView(); // nécessaire pour que les champs soit trouvés dans le HTML
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas-errors1.csv" }); const sortingField1=new SortingField(converter, 0);
converter.stopIfParseErrors=true; const sortingField2=new SortingField(converter, 1);
await expectAsync(converter.run()).toBeRejectedWith(new Error(errors.parserMeetErrors)); converter.datasSortingFields=[sortingField1,sortingField2];
spyOn(sortingField1, "field2HTML");
spyOn(sortingField2, "field2HTML");
converter.refreshView();
expect(sortingField1.field2HTML).toHaveBeenCalled();
expect(sortingField2.field2HTML).toHaveBeenCalled();
}); });
it("Si cela n'est pas demandé, le script ne sera pas bloqué, même si des erreurs sont rencontrées durant le parsage.", async () => it("Si une pagination est configurée, le code HTML listant les pages doit être actualisé.", () =>
{ {
converter.datasViewElt={ id:"datas" }; const pagination=new Pagination(converter, { id:"pages" }, "Page à afficher :");
converter=new FreeDatas2HTML("CSV"); converter.pagination=pagination;
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas-errors1.csv" }); spyOn(pagination, "pages2HTML");
await expectAsync(converter.run()).toBeResolved(); converter.refreshView();
}); expect(pagination.pages2HTML).toHaveBeenCalled();
/// Plutôt pour tester Render
it("Doit afficher un tableau correspondant aux données du fichier csv", async () =>
{
converter.datasViewElt={ id:"datas" };
await converter.run();
const render=new Render();
render.datas=converter.datas;
const htmlForDatas=render.rend2HTML();
// On ne peut comparer directement au contenu du DOM,
// car le navigateur change certains caractères (exemple : ">" devient "&gt;")
expect(converter.datasHTML).toEqual(htmlForDatas);
// Mais le code commence tout de même par <table> :
const txtDatasViewsElt=document.getElementById("datas").innerHTML;
expect(txtDatasViewsElt.indexOf("<table>")).toEqual(0);
// Et on doit retrouver le bon nombre de lignes :
const getTR=document.getElementsByTagName("tr");
expect(getTR.length).toEqual(119);
});
it("Si demandé, doit afficher le nombre de lignes de données du fichier.", async () =>
{
converter.datasViewElt={ id:"datas" };
converter.datasCounter={ id:"counter" };
await converter.run();
let txtDatasViewsElt=document.getElementById("counter").innerHTML;
expect(txtDatasViewsElt).toEqual("118");
}); });
}); });
/* describe("Action des champs de classement en corrélation avec le convertisseur.", () => describe("Fonction filtrant les données à afficher.", () =>
{ {
beforeEach( async () =>
it("Le 1er clic sur l'entête d'une des colonnes doit classer les données dans le sens ascendant, puis descendant et ainsi de suite.", async () =>
{ {
let sortingField=new SortingField(converter, 2); converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
sortingField.field2HTML(); converter.datasViewElt={ id:"datas" };
await converter.run();
});
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]; converter.datasSortingFields=[sortingField];
let getTHLink=document.querySelector("th a") as HTMLElement; sortingField.field2HTML();
getTHLink.click();// tri ascendant const fieldName=converter.fields[0];
let getTR=document.querySelectorAll("tr"); const getTHLink=document.querySelector("th a") as HTMLElement;
let txtDatasViewsElt=getTR[1].innerHTML; getTHLink.click();
expect(txtDatasViewsElt).toEqual("<td>89</td><td>Actinium</td><td>Ac</td><td>Actinide</td><td>≤ 1</td>"); converter.datas.sort( (a, b) => compare( {order: "asc"} )(a[fieldName], b[fieldName]));
getTHLink.click();// tri descendant expect(converter.datas2Rend).toEqual(converter.datas);
getTR=document.querySelectorAll("tr"); getTHLink.click();
txtDatasViewsElt=getTR[1].innerHTML; converter.datas.sort( (a, b) => compare( {order: "desc"} )(a[fieldName], b[fieldName]));
expect(txtDatasViewsElt).toEqual("<td>40</td><td>Zirconium</td><td>Zr</td><td>Métal de transition</td><td>&gt; 100000</td>"); expect(converter.datas2Rend).toEqual(converter.datas);
getTHLink.click();// de nouveau ascendant getTHLink.click();
getTR=document.querySelectorAll("tr"); converter.datas.sort( (a, b) => compare( {order: "asc"} )(a[fieldName], b[fieldName]));
txtDatasViewsElt=getTR[1].innerHTML; expect(converter.datas2Rend).toEqual(converter.datas);
expect(txtDatasViewsElt).toEqual("<td>89</td><td>Actinium</td><td>Ac</td><td>Actinide</td><td>≤ 1</td>");
}); });
it("Prise en compte d'une fonction spécifique associée au champ de classement.", async () => 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 mySort = (a: any, b: any, order: "asc"|"desc" = "asc") =>
{ {
const values=[ "> 100000", "> 1 et < 100 000", "≤ 1", "Traces", "Inexistant"]; const values = [ "> 100000", "> 1 et < 100 000", "≤ 1", "Traces", "Inexistant"];
if(order === "desc") if(order === "desc")
values.reverse(); values.reverse();
if(values.indexOf(a) > values.indexOf(b)) if(values.indexOf(a) > values.indexOf(b))
@ -205,111 +306,74 @@ describe("Test du script central de FreeDatas2HTML", () =>
else else
return 0; return 0;
}; };
converter.datasSortingFunctions=[{ datasFieldNb: 4, sort:mySort }]; converter.datasSortingFunctions=[{ datasFieldNb:4, sort:mySort }];
let sortingField=new SortingField(converter, 4); const sortingField=new SortingField(converter, 4);
sortingField.field2HTML();
converter.datasSortingFields=[sortingField]; converter.datasSortingFields=[sortingField];
let getTHLink=document.querySelector("th a") as HTMLElement; sortingField.field2HTML();
getTHLink.click();// tri ascendant const fieldName=converter.fields[0];
let getTR=document.querySelectorAll("tr"); const getTHLink=document.querySelector("th a") as HTMLElement;
let txtDatasViewsElt=getTR[1].innerHTML; getTHLink.click();
expect(txtDatasViewsElt).toEqual("<td>95</td><td>Américium</td><td>Am</td><td>Actinide</td><td>Inexistant</td>"); converter.datas.sort( (a, b) => { return mySort(a[fieldName], b[fieldName], "asc"); });
getTHLink.click();// tri descendant expect(converter.datas2Rend).toEqual(converter.datas);
getTR=document.querySelectorAll("tr"); getTHLink.click();
txtDatasViewsElt=getTR[1].innerHTML; converter.datas.sort( (a, b) => { return mySort(a[fieldName], b[fieldName], "desc"); });
expect(txtDatasViewsElt).toEqual("<td>1</td><td>Hydrogène</td><td>H</td><td>Non-métal</td><td>&gt; 100000</td>"); expect(converter.datas2Rend).toEqual(converter.datas);
getTHLink.click();// de nouveau ascendant getTHLink.click();
getTR=document.querySelectorAll("tr"); converter.datas.sort( (a, b) => { return mySort(a[fieldName], b[fieldName], "asc"); });
txtDatasViewsElt=getTR[1].innerHTML; expect(converter.datas2Rend).toEqual(converter.datas);
expect(txtDatasViewsElt).toEqual("<td>95</td><td>Américium</td><td>Am</td><td>Actinide</td><td>Inexistant</td>"); });
});
it("Si des options de pagination sont activées par l'utilisateur, seules les données de la page choisie doivent être retournées.", () =>
}); */
/*
describe("Création et action des sélecteurs liés à la pagination des données.", () =>
{
beforeEach( () =>
{ {
pagination.options={ displayElement: { id:"paginationOptions" }, values: [10,20,50,500] , name: "Choix de pagination :" }; 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; pagination.selectedValue=10;
pagination.options2HTML();
converter.pagination=pagination; converter.pagination=pagination;
//converter.refreshView(); 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 une valeur de pagination par défaut fournie, ne doit pas afficher plus de données.", () => it("Si des filtres sont déclarés, ils doivent tous être appelés pour tester les données à afficher.", () =>
{ {
let getTR=document.getElementsByTagName("tr"); const filter1=new Selector(converter, 3, { id:"selector1"} );
expect(getTR.length).toEqual(pagination.selectedValue+1); // 1er TR sert aux titres filter1.filter2HTML();
}); const filter2=new Selector(converter, 4, { id:"selector2"} );
converter.datasFilters=[filter1,filter2];
it("La manipulation du sélecteur de pagination doit appeler la fonction actualisant l'affichage.", () => // si le 1er n'est pas réellement lancé, le second est bloqué, car cela retourne un "false"
{ spyOn(filter1, "dataIsOk").and.callThrough();
spyOn(converter, "refreshView"); spyOn(filter2, "dataIsOk");
let selectElement=document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement; converter.refreshView();
selectElement.value="2"; expect(filter1.dataIsOk).toHaveBeenCalledTimes(118);
selectElement.dispatchEvent(new Event('change')); expect(filter2.dataIsOk).toHaveBeenCalledTimes(118);
expect(converter.refreshView).toHaveBeenCalledTimes(1);
selectElement.value="0";
selectElement.dispatchEvent(new Event('change'));
expect(converter.refreshView).toHaveBeenCalledTimes(2);
}); });
it("Si une des options de pagination fournies est sélectionnée, doit afficher le nombre de résultats correspondants.", () => it("Quand il y a plusieurs filtres, seules les données positives aux précédents sont testées par les suivants.", () =>
{ {
let selectElement=document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement; const filter1=new Selector(converter, 3, { id:"selector1"} );
selectElement.value="2"; // = 20 éléments / page 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')); selectElement.dispatchEvent(new Event('change'));
let getTR=document.getElementsByTagName("tr"); expect(filter1.dataIsOk).toHaveBeenCalledTimes(118);
expect(getTR.length).toEqual(21); expect(filter2.dataIsOk).toHaveBeenCalledTimes(4);
selectElement.value="3"; // = 50 éléments / page
selectElement.dispatchEvent(new Event('change'));
getTR=document.getElementsByTagName("tr");
expect(getTR.length).toEqual(51);
selectElement.value="0"; // = pas de Pagination, on affiche les 118 lignes du fichier
selectElement.dispatchEvent(new Event('change'));
getTR=document.getElementsByTagName("tr");
expect(getTR.length).toEqual(119);
});
it("Si il y a plus de données que le nombre de lignes autorisées par page, un <select> listant les pages doit être affiché.", () =>
{
let selectElement=document.getElementById("pages").innerHTML;
expect(selectElement).toEqual(fixtures.selectorForPages);
});
it("La manipulation du sélecteur de pages doit appeler la fonction actualisant l'affichage.", () =>
{
spyOn(converter, "refreshView");
let selectElement=document.getElementById("freeDatas2HTMLPagesSelector") as HTMLInputElement;
selectElement.value="2";
selectElement.dispatchEvent(new Event('change'));
expect(converter.refreshView).toHaveBeenCalledTimes(1);
selectElement.value="0";
selectElement.dispatchEvent(new Event('change'));
expect(converter.refreshView).toHaveBeenCalledTimes(2);
});
it("Si l'utilisateur sélectionne une des pages proposées, l'affichage des résultats doit s'adapter en prenant en compte la pagination sélectionnée.", () =>
{
let selectElement=document.getElementById("freeDatas2HTMLPaginationSelector") as HTMLInputElement;
selectElement.value="3"; // = 50 éléments / page
selectElement.dispatchEvent(new Event('change'));
selectElement=document.getElementById("freeDatas2HTMLPagesSelector") as HTMLInputElement;
selectElement.value="2";
selectElement.dispatchEvent(new Event('change'));
let getTR=document.getElementsByTagName("tr");
expect(getTR[1].innerHTML).toEqual(fixtures.firstLineForPageSelection1);
expect(getTR[50].innerHTML).toEqual(fixtures.lastLineForPageSelection1);
selectElement.value="3"; // troisième page = incomplète (18 enregistrements)
selectElement.dispatchEvent(new Event('change'));
getTR=document.getElementsByTagName("tr");
expect(getTR[1].innerHTML).toEqual(fixtures.firstLineForPageSelection2);
expect(getTR[18].innerHTML).toEqual(fixtures.lastLineForPageSelection2);
expect(getTR[50]).toBeUndefined();
}); });
}); });
});*/ });