Version remaniée de la classe principale + réécriture de ses tests.
This commit is contained in:
parent
8c0b9b2aa2
commit
739b83f365
@ -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": {
|
||||||
|
@ -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";
|
||||||
|
@ -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.",
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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>> 1 et < 100 000</td>",
|
firstLineForPageSelection1:"<td>51</td><td>Antimoine</td><td>Sb</td><td>Métalloïde</td><td>> 1 et < 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>",
|
||||||
|
@ -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 ">")
|
|
||||||
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>> 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>> 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();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});*/
|
});
|
Loading…
Reference in New Issue
Block a user