Nouvelle version classe des filtres/sélecteurs + revue des tests associés.
This commit is contained in:
parent
8a129d169b
commit
a58c7da008
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "freedatas2html",
|
||||
"version": "0.8.9",
|
||||
"version": "0.9.0",
|
||||
"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",
|
||||
"scripts": {
|
||||
|
181
src/Selector.ts
181
src/Selector.ts
@ -1,40 +1,40 @@
|
||||
const { compare }= require('natural-orderby');
|
||||
const errors = require("./errors.js");
|
||||
const { compare }=require('natural-orderby');
|
||||
const errors=require("./errors.js");
|
||||
import { DOMElement, Selectors } from "./interfaces";
|
||||
import { FreeDatas2HTML } from "./freeDatas2HTML";
|
||||
|
||||
export class Selector implements Selectors
|
||||
{
|
||||
_converter: FreeDatas2HTML;
|
||||
_datasViewElt: DOMElement= { id:"", eltDOM:undefined }; // élément du DOM dans lequel afficher le "select"
|
||||
_datasFieldNb: number; // numéro du champ dont les données serviront au filtre
|
||||
_separator: string|undefined; // séparateur éventuel pour les données du champ
|
||||
name: string = ""; // nom à afficher dans le DOM comme "label" du "select"
|
||||
values: string[]=[]; // données proposées par le filtre, après traitement des données reçues
|
||||
private _converter: FreeDatas2HTML;
|
||||
private _datasFieldNb: number;
|
||||
private _datasViewElt: DOMElement={ id: "", eltDOM: undefined };
|
||||
private _selectedValue: number|undefined=undefined;
|
||||
private _separator: string|undefined;
|
||||
private _values: string[]=[];
|
||||
private _name: string="";
|
||||
|
||||
// Injection de la classe principale, mais uniquement si les données ont été importées
|
||||
constructor(converter: FreeDatas2HTML, datasFieldNb: number, elt: DOMElement)
|
||||
// Injection de la classe principale, mais uniquement si des données ont été importées
|
||||
// Le champ duquel le sélecteur tire ses données doit exister ?
|
||||
constructor(converter: FreeDatas2HTML, datasFieldNb: number, elt: DOMElement, separator?: string)
|
||||
{
|
||||
if(converter.fields === undefined || converter.datas.length === 0)
|
||||
throw new Error(errors.selectorNeedDatas);
|
||||
throw new Error(errors.filterNeedDatas);
|
||||
else if(! converter.checkFieldExist(Number(datasFieldNb)))
|
||||
throw new Error(errors.selectorFieldNotFound);
|
||||
else
|
||||
{
|
||||
this._datasViewElt=FreeDatas2HTML.checkInDOMById(elt); // provoque une erreur, si élement non trouvé dans DOM
|
||||
this._datasViewElt=FreeDatas2HTML.checkInDOMById(elt);
|
||||
this._converter=converter;
|
||||
this._datasFieldNb=datasFieldNb;
|
||||
// Pas de trim(), car l'espace peut être le séparateur :
|
||||
if(separator !== undefined && separator !== "")
|
||||
this._separator=separator;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore un séparateur de données vide
|
||||
// Attention : pas de trim(), car l'espace peut être un séparateur
|
||||
set separator(separator: string|undefined)
|
||||
get converter() : FreeDatas2HTML
|
||||
{
|
||||
if(separator === "")
|
||||
this._separator=undefined;
|
||||
else
|
||||
this._separator=separator;
|
||||
return this._converter;
|
||||
}
|
||||
|
||||
get datasViewElt() : DOMElement
|
||||
@ -47,91 +47,102 @@ export class Selector implements Selectors
|
||||
return this._datasFieldNb;
|
||||
}
|
||||
|
||||
get name() : string
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get selectedValue() : number|undefined
|
||||
{
|
||||
return this._selectedValue;
|
||||
}
|
||||
|
||||
get separator() : string|undefined
|
||||
{
|
||||
return this._separator;
|
||||
}
|
||||
|
||||
// Création du <select> dans le HTML correspondant au filtre
|
||||
public filter2HTML() : void
|
||||
get values(): string[]
|
||||
{
|
||||
if(this._converter === undefined || this._datasViewElt.eltDOM === undefined || this._datasFieldNb === undefined)
|
||||
throw new Error(errors.filter2HTMLFail);
|
||||
else
|
||||
{
|
||||
this.name=this._converter.fields![this._datasFieldNb]; // this._converter.parse... ne peuvent être indéfinis si this._converter existe (cf constructeur)
|
||||
for (let row of this._converter.datas)
|
||||
{
|
||||
if(this._separator === undefined)
|
||||
{
|
||||
if(row[this.name] !== "" && this.values.indexOf(row[this.name]) === -1)
|
||||
this.values.push(row[this.name]);
|
||||
}
|
||||
else
|
||||
{
|
||||
let checkedValues=row[this.name].split(this._separator);
|
||||
for(let value of checkedValues)
|
||||
{
|
||||
if(value !== "" && this.values.indexOf(value) === -1)
|
||||
this.values.push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(this.values.length > 0)
|
||||
{
|
||||
// Classement des données à l'aide (ou non) d'une fonction spécifique :
|
||||
if(this._converter.getSortingFunctionForField(this._datasFieldNb) !== undefined)
|
||||
this.values.sort(this._converter.getSortingFunctionForField(this._datasFieldNb)!.sort); // sans le "!" : TS2532: Object is possibly 'undefined' ??
|
||||
else
|
||||
this.values.sort(compare());
|
||||
return this._values;
|
||||
}
|
||||
|
||||
// Création et injection du SELECT dans le DOM
|
||||
let selectorsHTML="<label for='freeDatas2HTML_"+this._datasViewElt.id+"'>"+this.name+" : </label><select name='freeDatas2HTML_"+this._datasViewElt.id+"' id='freeDatas2HTML_"+this._datasViewElt.id+"'><option value='0'>----</option>"; // l'option zéro permet d'actualiser l'affichage en ignorant ce filtre
|
||||
for(let i=0; i< this.values.length; i++)
|
||||
selectorsHTML+="<option value='"+(i+1)+"'>"+this.values[i]+"</option>";
|
||||
selectorsHTML+="</select>";
|
||||
this. _datasViewElt.eltDOM.innerHTML=selectorsHTML;
|
||||
const selectElement=document.getElementById("freeDatas2HTML_"+this._datasViewElt.id) as HTMLInputElement, mySelector=this;
|
||||
selectElement.addEventListener("change", function(e)
|
||||
{
|
||||
mySelector._converter.refreshView();
|
||||
});
|
||||
// Création du <select> dans le DOM correspondant au filtre
|
||||
public filter2HTML(label:string="") : void
|
||||
{
|
||||
this._name=this._converter.fields![this._datasFieldNb]; // "!" car l'existence du champ est testé par le constructeur
|
||||
for (let row of this._converter.datas)
|
||||
{
|
||||
let checkedValue;
|
||||
if(this._separator === undefined)
|
||||
{
|
||||
checkedValue=row[this._name].trim(); // trim() évite des problèmes de classement des éléments du SELECT
|
||||
if(checkedValue !== "" && this._values.indexOf(checkedValue) === -1)
|
||||
this._values.push(checkedValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
let checkedValues=row[this._name].split(this._separator);
|
||||
for(let value of checkedValues)
|
||||
{
|
||||
checkedValue=value.trim();
|
||||
if(checkedValue !== "" && this._values.indexOf(checkedValue) === -1)
|
||||
this._values.push(checkedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vérifie si une valeur est sélectionnée dans la liste et, si oui, la retourne
|
||||
public getSelectionnedId() : number
|
||||
{
|
||||
const selectElement=document.getElementById("freeDatas2HTML_"+this._datasViewElt.id) as HTMLInputElement;
|
||||
if(selectElement === undefined)
|
||||
return 0;
|
||||
|
||||
if(this._values.length === 0) // possible si uniquement des valeurs vides pour ce champ
|
||||
throw new Error(errors.selectorFieldIsEmpty);
|
||||
else
|
||||
return parseInt(selectElement.value,10);
|
||||
{
|
||||
// Classement des données à l'aide (ou non) d'une fonction spécifique :
|
||||
if(this._converter.getSortingFunctionForField(this._datasFieldNb) !== undefined)
|
||||
this._values.sort(this._converter.getSortingFunctionForField(this._datasFieldNb)!.sort); // sans le "!" : TS2532: Object is possibly 'undefined' ???
|
||||
else
|
||||
this._values.sort(compare());
|
||||
|
||||
// Création et injection du SELECT dans le DOM
|
||||
label=(label === "") ? this._name : label;
|
||||
let selectorsHTML="<label for='freeDatas2HTML_"+this._datasViewElt.id+"'>"+label+" :</label><select name='freeDatas2HTML_"+this._datasViewElt.id+"' id='freeDatas2HTML_"+this._datasViewElt.id+"'><option value='0'>----</option>"; // l'option zéro permet d'actualiser l'affichage en ignorant ce filtre
|
||||
for(let i=0; i< this._values.length; i++)
|
||||
selectorsHTML+="<option value='"+(i+1)+"'>"+this._values[i]+"</option>";
|
||||
selectorsHTML+="</select>";
|
||||
this. _datasViewElt.eltDOM!.innerHTML=selectorsHTML;// "!" car l'existence de "eltDOM" est testé par le constructeur
|
||||
|
||||
const selectElement=document.getElementById("freeDatas2HTML_"+this._datasViewElt.id) as HTMLInputElement, mySelector=this;
|
||||
selectElement.addEventListener("change", function(e)
|
||||
{
|
||||
if(selectElement.value === "0")
|
||||
mySelector._selectedValue=undefined;
|
||||
else
|
||||
mySelector._selectedValue=parseInt(selectElement.value,10)-1;
|
||||
mySelector._converter.refreshView();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Vérifie sur l'enregistrement passé correspond à la valeur sélectionnée par l'utilisateur dans le filtre
|
||||
public dataIsOk(data: any) : boolean
|
||||
public dataIsOk(data: {[index: string]:string}) : boolean
|
||||
{
|
||||
if(this.name === undefined || this.name === "")
|
||||
throw new Error(errors.selectorCheckIsOkFail);
|
||||
|
||||
let selectedValue = this.getSelectionnedId();
|
||||
if(selectedValue === 0) // = pas de valeur sélectionnée = pas de filtre sur ce champ
|
||||
// Permet de vérifier que filter2HTML() a été préalablement appelée :
|
||||
if(this._name === "")
|
||||
throw new Error(errors.filterCheckIsOkFail);
|
||||
|
||||
// Pas de valeur sélectionnée = pas de filtre sur ce champ
|
||||
if(this._selectedValue === undefined)
|
||||
return true;
|
||||
else
|
||||
selectedValue=selectedValue-1;
|
||||
|
||||
if(this.values[selectedValue] === undefined)
|
||||
if(this._values[this._selectedValue] === undefined) // théoriquement impossible, mais cela vient du client...
|
||||
throw new Error(errors.selectorSelectedIndexNotFound);
|
||||
|
||||
if(data[this.name] === undefined) // champ absent pour cet enregistrement, qui est donc refusé
|
||||
// Si le champ est absent pour un enregistrement, il est refusé
|
||||
if(data[this._name] === undefined)
|
||||
return false;
|
||||
|
||||
const selectedValueTxt=this.values[selectedValue] ;
|
||||
const selectedValueTxt=this._values[this._selectedValue];
|
||||
if(this._separator === undefined)
|
||||
{
|
||||
if(data[this.name] !== selectedValueTxt)
|
||||
if(data[this._name].trim() !== selectedValueTxt)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
@ -139,10 +150,10 @@ export class Selector implements Selectors
|
||||
else
|
||||
{
|
||||
let find=false;
|
||||
let checkedValues=data[this.name].split(this._separator);
|
||||
let checkedValues=data[this._name].split(this._separator);
|
||||
for(let value of checkedValues)
|
||||
{
|
||||
if(value === selectedValueTxt)
|
||||
if(value.trim() === selectedValueTxt)
|
||||
{
|
||||
find=true;
|
||||
break;
|
||||
|
@ -4,6 +4,8 @@ module.exports =
|
||||
converterFieldNotFound : "Le champ n'existe pas dans les données ou les données n'ont pas encore été chargées.",
|
||||
converterNeedDatasElt: "Merci de fournir un id valide pour l'élément où afficher les données.",
|
||||
converterRefreshFail: "Le nom des champs et l'élement du DOM receveur sont nécessaires à l'affichage des données.",
|
||||
filterCheckIsOkFail: "Le test est lancé sur un filtre incorrectement initialisé ou sur un attribut absent de la donnée à tester.",
|
||||
filterNeedDatas: "Le création d'un filtre nécessite la présence des données à filtrer.",
|
||||
pagination2HTMLFail : "Toutes les donnée nécessaires à la création des sélecteurs de pagination n'ont pas été fournies.",
|
||||
paginationNeedByfaultValueBeInOptions: "La valeur de pagination par défaut doit faire partie des options proposées.",
|
||||
paginationNeedDatas: "Il ne peut y avoir de pagination, si les données n'ont pas été récupérées.",
|
||||
@ -28,11 +30,9 @@ module.exports =
|
||||
remoteSourceUrlFail: "L'url fournie ne semble pas valide.",
|
||||
renderNeedFields: "Les noms de champs doivent être fournis avant de demander l'affichage des données.",
|
||||
selector2HTMLFail: "Le création d'un filtre dans le DOM nécessite l'initialisation de l'élément HTML et du numéro du champs à filter.",
|
||||
selectorCheckIsOkFail: "Le test est lancé sur un filtre incorrectement initialisé ou sur un attribut absent de la donnée à tester.",
|
||||
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.",
|
||||
selectorNeedDatas: "Le création d'un filtre nécessite la transmission des données à filtrer.",
|
||||
selectorSelectedIndexNotFound: "La valeur sélectionnée n'a pas été trouvée dans la liste des champs.",
|
||||
sortingField2HTMLFail: "Toutes les donnée nécessaires à la création du lien de classement n'ont pas été fournies.",
|
||||
sortingFieldNeedDatas: "Le 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.",
|
||||
sortingFieldsNbFail: "Le nombre de champs trouvés dans le DOM ne correspond pas à celui des données à classer.",
|
||||
|
@ -31,7 +31,7 @@ export interface Filters
|
||||
{
|
||||
datasViewElt: DOMElement;
|
||||
filter2HTML() : void;
|
||||
dataIsOk(data: any) : boolean;
|
||||
dataIsOk(data: {[index: string]:string}) : boolean;
|
||||
}
|
||||
export interface Paginations
|
||||
{
|
||||
@ -54,10 +54,6 @@ export interface PaginationsPages
|
||||
values?: number[];
|
||||
selectedValue?: number;
|
||||
}
|
||||
export interface Datas
|
||||
{
|
||||
[key: string]: string;
|
||||
}
|
||||
export interface ParseErrors
|
||||
{
|
||||
code?: string;
|
||||
@ -93,9 +89,10 @@ export interface RemoteSources extends RemoteSourceSettings
|
||||
export interface Selectors extends Filters
|
||||
{
|
||||
datasFieldNb: number;
|
||||
separator?: string|undefined;
|
||||
name?: string;
|
||||
values?: string[];
|
||||
name: string;
|
||||
selectedValue: number|undefined;
|
||||
separator: string|undefined;
|
||||
values: string[];
|
||||
}
|
||||
export interface SortingFields
|
||||
{
|
||||
|
@ -1,12 +1,15 @@
|
||||
module.exports =
|
||||
{
|
||||
datasViewEltHTML: '<div id="fixture"><div id="selector1"></div><div id="selector2"></div><div id="paginationOptions"></div><div id="counter"></div><div id="datas"></div><div id="pages"></div></div>',
|
||||
selector1HTML: '<label for="freeDatas2HTML_selector1">Famille : </label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Actinide</option><option value="2">Gaz noble</option><option value="3">gaz rare</option><option value="4">Halogène</option><option value="5">Indéfinie</option><option value="6">Lanthanide</option><option value="7">Métal alcalin</option><option value="8">Métal alcalino-terreux</option><option value="9">Métal de transition</option><option value="10">Métal pauvre</option><option value="11">Métalloïde</option><option value="12">Non-métal</option></select>',
|
||||
selector2HTML: '<label for="freeDatas2HTML_selector2">Abondance des éléments dans la croûte terrestre (μg/k) : </label><select name="freeDatas2HTML_selector2" id="freeDatas2HTML_selector2"><option value="0">----</option><option value="1">> 1 et < 100 000</option><option value="2">> 100000</option><option value="3">≤ 1</option><option value="4">Inexistant</option><option value="5">Traces</option></select>',
|
||||
selector1HTMLWithSeparator: '<label for="freeDatas2HTML_selector1">Étiquettes : </label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Exemple0</option><option value="2">Exemple1</option><option value="3">Exemple2</option><option value="4">Exemple3</option><option value="5">Exemple4</option><option value="6">Exemple5</option><option value="7">Exemple6</option><option value="8">Exemple7</option><option value="9">Exemple8</option><option value="10">Exemple9</option><option value="11">Exemple10</option></select>',
|
||||
selector1HTMLWithFunction: '<label for="freeDatas2HTML_selector1">Abondance des éléments dans la croûte terrestre (μg/k) : </label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Inexistant</option><option value="2">Traces</option><option value="3">≤ 1</option><option value="4">> 1 et < 100 000</option><option value="5">> 100000</option></select>',
|
||||
sortingColumn1HTML: '<a href="#freeDatas2HTMLSorting0" id="freeDatas2HTMLSorting0">Z (numéro atomique)</a>',
|
||||
sortingColumn2HTML: '<a href="#freeDatas2HTMLSorting2" id="freeDatas2HTMLSorting2">Symbole</a>',
|
||||
selector1HTML: '<label for="freeDatas2HTML_selector1">Famille :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Actinide</option><option value="2">Gaz noble</option><option value="3">gaz rare</option><option value="4">Halogène</option><option value="5">Indéfinie</option><option value="6">Lanthanide</option><option value="7">Métal alcalin</option><option value="8">Métal alcalino-terreux</option><option value="9">Métal de transition</option><option value="10">Métal pauvre</option><option value="11">Métalloïde</option><option value="12">Non-métal</option></select>',
|
||||
selector2HTML: '<label for="freeDatas2HTML_selector2">Abondance des éléments dans la croûte terrestre (μg/k) :</label><select name="freeDatas2HTML_selector2" id="freeDatas2HTML_selector2"><option value="0">----</option><option value="1">> 1 et < 100 000</option><option value="2">> 100000</option><option value="3">≤ 1</option><option value="4">Inexistant</option><option value="5">Traces</option></select>',
|
||||
selector2HTMLWithLabel: '<label for="freeDatas2HTML_selector2">Abondance des éléments :</label><select name="freeDatas2HTML_selector2" id="freeDatas2HTML_selector2"><option value="0">----</option><option value="1">> 1 et < 100 000</option><option value="2">> 100000</option><option value="3">≤ 1</option><option value="4">Inexistant</option><option value="5">Traces</option></select>',
|
||||
selector1HTMLWithSeparator: '<label for="freeDatas2HTML_selector1">Étiquettes :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Exemple0</option><option value="2">Exemple1</option><option value="3">Exemple2</option><option value="4">Exemple3</option><option value="5">Exemple4</option><option value="6">Exemple5</option><option value="7">Exemple6</option><option value="8">Exemple7</option><option value="9">Exemple8</option><option value="10">Exemple9</option><option value="11">Exemple10</option></select>',
|
||||
selectorHTMLWithTrim: '<label for="freeDatas2HTML_selector1">Famille :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Gaz noble</option><option value="2">Métal alcalin</option><option value="3">Métal alcalino-terreux</option><option value="4">Métalloïde</option><option value="5">Non-métal</option></select>',
|
||||
selector1HTMLWithFunction: '<label for="freeDatas2HTML_selector1">Abondance des éléments dans la croûte terrestre (μg/k) :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Inexistant</option><option value="2">Traces</option><option value="3">≤ 1</option><option value="4">> 1 et < 100 000</option><option value="5">> 100000</option></select>',
|
||||
selectorHTMLWithFakeItem: '<label for="freeDatas2HTML_selector1">Famille :</label><select name="freeDatas2HTML_selector1" id="freeDatas2HTML_selector1"><option value="0">----</option><option value="1">Actinide</option><option value="2">Gaz noble</option><option value="3">gaz rare</option><option value="4">Halogène</option><option value="5">Indéfinie</option><option value="6">Lanthanide</option><option value="7">Métal alcalin</option><option value="8">Métal alcalino-terreux</option><option value="9">Métal de transition</option><option value="10">Métal pauvre</option><option value="11">Métalloïde</option><option value="12">Non-métal</option><option value="13">Je suis un gros fake !</option></select>',
|
||||
sortingColumn1HTML: '<a href="#freeDatas2HTMLSorting0" id="freeDatas2HTMLSorting0">Z (numéro atomique)</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>',
|
||||
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>',
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { FreeDatas2HTML, Selector } from "../src/freeDatas2HTML";
|
||||
|
||||
const errors=require("../src/errors.js");
|
||||
const fixtures=require("./fixtures.js");
|
||||
|
||||
describe("Test des filtres de données", () =>
|
||||
describe("Test des sélecteurs de données", () =>
|
||||
{
|
||||
let converter: FreeDatas2HTML;
|
||||
let selector: Selector;
|
||||
let selectElement : HTMLInputElement;
|
||||
|
||||
beforeEach( async () =>
|
||||
{
|
||||
@ -22,13 +22,18 @@ describe("Test des filtres de données", () =>
|
||||
document.body.removeChild(document.getElementById("fixture"));
|
||||
});
|
||||
|
||||
describe("Test des données reçues pour configurer un filtre.", () =>
|
||||
describe("Test des données de configuration.", () =>
|
||||
{
|
||||
it("Doit générer une erreur, si initialisé sans fournir la liste des champs servant à classer les données.", () =>
|
||||
it("Doit générer une erreur, si initialisé sans avoir au préalable charger des données.", async () =>
|
||||
{
|
||||
// Convertisseur non lancé :
|
||||
converter=new FreeDatas2HTML("CSV");
|
||||
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1.csv" });
|
||||
expect(() => { return new Selector(converter, 0, { id:"selector1" }); }).toThrowError(errors.selectorNeedDatas);
|
||||
expect(() => { return new Selector(converter, 0, { id:"selector1" }); }).toThrowError(errors.filterNeedDatas);
|
||||
// Note : les parseurs vont générer une erreur en amont s'ils ne trouvent pas de noms de champs.
|
||||
// Par contre, ils acceptent de ne pas trouver de données :
|
||||
converter.parser.datas2Parse="Z (numéro atomique),Élément,Symbole,Famille,Abondance des éléments dans la croûte terrestre (μg/k)";
|
||||
await converter.run();
|
||||
expect(() => { return new Selector(converter, 0, { id:"selector1" }); }).toThrowError(errors.filterNeedDatas);
|
||||
});
|
||||
|
||||
it("Doit générer une erreur, si le numéro de champ fourni n'existe pas dans les données.", () =>
|
||||
@ -40,24 +45,20 @@ describe("Test des filtres de données", () =>
|
||||
|
||||
it("Si un séparateur vide est fourni pour un filtre, il doit être ignoré.", () =>
|
||||
{
|
||||
selector=new Selector(converter, 0, { id:"selector1" });
|
||||
selector.separator="";
|
||||
selector=new Selector(converter, 0, { id:"selector1" }, "");
|
||||
expect(selector.separator).toBeUndefined();
|
||||
});
|
||||
|
||||
it("Si toutes les paramètres sont correctes, ils doivent être acceptés.", () =>
|
||||
{
|
||||
const elt=document.getElementById("selector1");
|
||||
const selector=new Selector(converter, 2, { id:"selector1" });
|
||||
selector.separator=",";
|
||||
expect(selector.datasFieldNb).toEqual(2);
|
||||
expect(selector.datasViewElt).toEqual({ id:"selector1", eltDOM:elt });
|
||||
expect(selector.separator).toEqual(",");
|
||||
expect(() => { selector=new Selector(converter, 2, { id:"selector1" }, ","); return true; }).not.toThrowError();
|
||||
expect(selector.datasFieldNb).toEqual(2);
|
||||
expect(selector.datasViewElt).toEqual({ id:"selector1", eltDOM:document.getElementById("selector1") });
|
||||
expect(selector.separator).toEqual(",");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("Création et action des sélecteurs permettant de filter les données affichées.", () =>
|
||||
describe("Création des sélecteurs.", () =>
|
||||
{
|
||||
beforeEach( async () =>
|
||||
{
|
||||
@ -73,22 +74,34 @@ describe("Test des filtres de données", () =>
|
||||
expect(document.getElementById("selector2").innerHTML).toEqual(fixtures.selector2HTML);
|
||||
});
|
||||
|
||||
it("Doit prendre en compte l'éventuel label fourni pour le SELECT.", () =>
|
||||
{
|
||||
selector=new Selector(converter, 4, { id:"selector2" });
|
||||
selector.filter2HTML("Abondance des éléments");
|
||||
expect(document.getElementById("selector2").innerHTML).toEqual(fixtures.selector2HTMLWithLabel);
|
||||
});
|
||||
|
||||
it("Si des valeurs vides sont présentes dans une champ utilisé pour un sélecteur, elles doivent être ignorées.", async () =>
|
||||
{
|
||||
converter=new FreeDatas2HTML("CSV");
|
||||
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1-emtyinfield.csv" });
|
||||
await converter.run();
|
||||
selector.converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1-emtyinfield.csv" });
|
||||
await selector.converter.run();
|
||||
selector.filter2HTML();
|
||||
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTML);
|
||||
});
|
||||
|
||||
it("Si des espaces entourent certaines valeurs pour ce champ, ils doivent être supprimés.", async () =>
|
||||
{
|
||||
selector.converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datasNeedTrim.csv" });
|
||||
await selector.converter.run();
|
||||
selector.filter2HTML();
|
||||
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selectorHTMLWithTrim);
|
||||
});
|
||||
|
||||
it("Si un séparateur est fourni, les valeurs distinctes extraites de ce champ doivent le prendre en compte.", async () =>
|
||||
{
|
||||
converter=new FreeDatas2HTML("CSV");
|
||||
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1+tagsfield.csv" });
|
||||
await converter.run();
|
||||
selector=new Selector(converter, 5, { id:"selector1" });
|
||||
selector.separator="|";
|
||||
selector=new Selector(converter, 5, { id:"selector1" }, "|");
|
||||
selector.filter2HTML();
|
||||
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTMLWithSeparator);
|
||||
});
|
||||
@ -109,93 +122,130 @@ describe("Test des filtres de données", () =>
|
||||
};
|
||||
converter.datasSortingFunctions=[{ datasFieldNb: 4, sort:mySort }];
|
||||
selector=new Selector(converter, 4, { id:"selector1" });
|
||||
selector.separator="|";
|
||||
selector.filter2HTML();
|
||||
selector.filter2HTML();
|
||||
expect(document.getElementById("selector1").innerHTML).toEqual(fixtures.selector1HTMLWithFunction);
|
||||
});
|
||||
|
||||
it("Doit générer une erreur si une donnée est testée pour un sélecteur non correctement initialisé.", () =>
|
||||
it("Doit générer une erreur, si aucune donnée n'a été trouvée pour créer le <SELECT>.", async () =>
|
||||
{
|
||||
let data2Test= {
|
||||
"Z (numéro atomique)" : "53",
|
||||
"Élément": "Iode",
|
||||
"Symbole": "I",
|
||||
"Famille": "Halogène",
|
||||
"Abondance des éléments dans la croûte terrestre (μg/k)": "> 1 et < 100 000",
|
||||
};
|
||||
expect(() => { selector.dataIsOk(data2Test); }).toThrowError(errors.selectorCheckIsOkFail);
|
||||
selector.converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datasEmptyField.csv" });
|
||||
await selector.converter.run();
|
||||
expect(() => { return selector.filter2HTML(); }).toThrowError(errors.selectorFieldIsEmpty);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Manipulation des sélecteurs et filtre des données.", () =>
|
||||
{
|
||||
beforeEach( async () =>
|
||||
{
|
||||
selector=new Selector(converter, 3, { id:"selector1" }); // filtre sur le champ "famille"
|
||||
selector.filter2HTML();
|
||||
selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
||||
});
|
||||
|
||||
it("Doit retourner false, si la donnée testée ne possède pas le champ sur lequel les données sont filtrées.", () =>
|
||||
it("La manipulation d'un sélecteur doit enregistrer la valeur sélectionnée et appeler la fonction actualisant l'affichage.", () =>
|
||||
{
|
||||
selector.filter2HTML();
|
||||
let selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
||||
spyOn(converter, "refreshView");
|
||||
|
||||
selectElement.value="4";
|
||||
let data2Test= { // le champ à filtrer ("Famille") est manquant
|
||||
"Z (numéro atomique)" : "53",
|
||||
"Élément": "Iode",
|
||||
"Symbole": "I",
|
||||
"Abondance des éléments dans la croûte terrestre (μg/k)": "> 1 et < 100 000",
|
||||
};
|
||||
expect(selector.dataIsOk(data2Test)).toBeFalse();
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(selector.selectedValue).toEqual(3);
|
||||
expect(converter.refreshView).toHaveBeenCalledTimes(1);
|
||||
|
||||
selectElement.value="0"; // 0 = annulation de ce filtre, puisqu'aucune valeur choisie
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(selector.selectedValue).toBeUndefined();
|
||||
expect(converter.refreshView).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("Doit retourner false, si une donnée testée ne correspond pas à la valeur sélectionnée pour le filtre.", () =>
|
||||
it("Doit générer une erreur si une donnée est testée sur un sélecteur non affiché dans la page.", () =>
|
||||
{
|
||||
selector.filter2HTML();
|
||||
let selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
||||
selectElement.value="4";
|
||||
let data2Test= {
|
||||
"Z (numéro atomique)" : "53",
|
||||
"Élément": "Iode",
|
||||
"Symbole": "I",
|
||||
"Famille": "Halogene", // manque un accent :)
|
||||
"Abondance des éléments dans la croûte terrestre (μg/k)": "> 1 et < 100 000",
|
||||
};
|
||||
expect(selector.dataIsOk(data2Test)).toBeFalse();
|
||||
selector=new Selector(converter, 3, { id:"selector1" });
|
||||
expect(() => { selector.dataIsOk({ "nom" : "oui" }); }).toThrowError(errors.filterCheckIsOkFail);
|
||||
});
|
||||
|
||||
it("Doit toujours retourner true si aucune des valeurs du filtre n'est sélectionnée.", () =>
|
||||
{
|
||||
// Le filtre est sur 0 par défaut
|
||||
expect(selector.dataIsOk({ "nom" : "oui" })).toBeTrue();
|
||||
// Même comportement après un retour :
|
||||
selectElement.value="2";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
selectElement.value="0";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(selector.dataIsOk({ "nom" : "oui" })).toBeTrue();
|
||||
});
|
||||
|
||||
it("Doit générer une erreur si la valeur sélectionnée n'est pas trouvé dans la liste des valeurs connues.", () =>
|
||||
{
|
||||
selectElement.innerHTML=fixtures.selectorHTMLWithFakeItem;
|
||||
selectElement.value="13";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(() => { selector.dataIsOk({ "nom" : "oui" }); }).toThrowError(errors.selectorSelectedIndexNotFound);
|
||||
});
|
||||
|
||||
it("Doit retourner false, si la donnée testée ne possède pas le champ sur lequel les données sont filtrées.", () =>
|
||||
{
|
||||
selectElement.value="2";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(selector.dataIsOk({ "nom" : "rémi sans famille" })).toBeFalse();
|
||||
});
|
||||
|
||||
it("Doit retourner false, si une donnée testée ne correspond pas à la valeur sélectionnée pour le filtre.", async () =>
|
||||
{
|
||||
selectElement.value="4"; // = Halogène
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(selector.dataIsOk({ "Famille": "Hallo Eugène !" })).toBeFalse();
|
||||
});
|
||||
|
||||
it("Doit retourner true, si une donnée testée correspond pas à la valeur sélectionnée pour ce filtre.", () =>
|
||||
{
|
||||
selector.filter2HTML();
|
||||
let selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
||||
selectElement.value="4";
|
||||
let data2Test= {
|
||||
"Z (numéro atomique)" : "53",
|
||||
"Élément": "Iode",
|
||||
"Symbole": "I",
|
||||
"Famille": "Halogène",
|
||||
"Abondance des éléments dans la croûte terrestre (μg/k)": "> 1 et < 100 000",
|
||||
};
|
||||
expect(selector.dataIsOk(data2Test)).toBeTrue();
|
||||
});
|
||||
|
||||
it("Doit toujours retourner true, si aucune valeur sélectionnée dans la liste.", () =>
|
||||
{
|
||||
selector.filter2HTML();
|
||||
let data2Test= {
|
||||
"Z (numéro atomique)" : "530",
|
||||
"Élément": "Yode",
|
||||
"Symbole": "L",
|
||||
"Famille": "Halogene",
|
||||
"Abondance des éléments": "> 1 et < 100 000",
|
||||
};
|
||||
expect(selector.dataIsOk(data2Test)).toBeTrue();
|
||||
});
|
||||
|
||||
it("La manipulation d'un sélecteur doit appeler la fonction actualisant l'affichage, y compris pour supprimer ce filtre (0).", () =>
|
||||
{
|
||||
selector=new Selector(converter, 3, { id:"selector1" });
|
||||
selector.filter2HTML();
|
||||
converter.datasFilters=[selector];
|
||||
spyOn(converter, "refreshView");
|
||||
let selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
||||
selectElement.value="4";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(converter.refreshView).toHaveBeenCalledTimes(1);
|
||||
selectElement.value="0";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(converter.refreshView).toHaveBeenCalledTimes(2);
|
||||
expect(selector.dataIsOk({ "Famille": "Halogène" })).toBeTrue();
|
||||
// Y compris si entouré d'espaces :
|
||||
expect(selector.dataIsOk({ "Famille": " Halogène " })).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Manipulation des sélecteurs avec séparateur.", () =>
|
||||
{
|
||||
beforeEach( async () =>
|
||||
{
|
||||
converter.parser.setRemoteSource({ url:"http://localhost:9876/datas/datas1+tagsfield.csv" });
|
||||
await converter.run();
|
||||
selector=new Selector(converter, 5, { id:"selector1" }, "|"); // filtre sur le champ "Étiquettes"
|
||||
selector.filter2HTML();
|
||||
selectElement=document.getElementById("freeDatas2HTML_selector1") as HTMLInputElement;
|
||||
});
|
||||
|
||||
it("Doit retourner false, si la donnée testée ne possède pas le champ sur lequel les données sont filtrées.", () =>
|
||||
{
|
||||
selectElement.value="2";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(selector.dataIsOk({ "nom" : "oui" })).toBeFalse();
|
||||
});
|
||||
|
||||
it("Doit retourner false, si une donnée testée ne correspond pas à la valeur sélectionnée pour le filtre.", () =>
|
||||
{
|
||||
selectElement.value="4"; // = Exemple3
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(selector.dataIsOk({ "Étiquettes": "Mauvais exemple" })).toBeFalse();
|
||||
});
|
||||
|
||||
it("Doit retourner true, si une donnée testée correspond pas à la valeur sélectionnée pour ce filtre.", () =>
|
||||
{
|
||||
selectElement.value="4";
|
||||
selectElement.dispatchEvent(new Event('change'));
|
||||
expect(selector.dataIsOk({ "Étiquettes": "Exemple3" })).toBeTrue();
|
||||
// Même pas seule :
|
||||
expect(selector.dataIsOk({ "Étiquettes": "Exemple3|Exemple1|Exemple9" })).toBeTrue();
|
||||
expect(selector.dataIsOk({ "Étiquettes": "Exemple0|Exemple3|Exemple2" })).toBeTrue();
|
||||
expect(selector.dataIsOk({ "Étiquettes": "Exemple0|Exemple4|Exemple3" })).toBeTrue();
|
||||
// Y compris si entourée d'espaces :
|
||||
expect(selector.dataIsOk({ "Étiquettes": "Exemple0|Exemple4| Exemple3 " })).toBeTrue();
|
||||
expect(selector.dataIsOk({ "Étiquettes": " Exemple3 " })).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue
Block a user