Nouveaux tests pour la classe principale + adaptations.

This commit is contained in:
Fabrice PENHOËT 2021-11-03 16:03:49 +01:00
parent 895ad0e9e6
commit 9a598901ca
7 changed files with 97 additions and 59 deletions

View File

@ -5,4 +5,5 @@
h4 { font-size:1.1em }
p,li { font-size: 17px }
ul, li { padding-left: 0.5em; margin-left:0 }
}
}
article#datas { overflow-x:auto; }

View File

@ -13,12 +13,11 @@
<body class="paper container">
<h1>freeDatas2HTML</h1>
<h2>Afficher votre fichier CSV dans la page web</h2>
<p>Sur cette page vous permet de tester directement freeDatas2HTML en affichant les données d'un fichier CSV de votre choix, en choisissant en options les champs à afficher, sur lesquels filter filter les données, faire des recherche... ou encore le nombre de lignes par page.</p>
<p>Pour rappel, freeDatas2HTML s'exécute uniquement côté client, c'est-à-dire dans votre navigateur. Les donnée de votre fichier ne sont donc pas envoyées sur un serveur. En conséquence, si vous partager cette page avec d'autres personnes, elles devront elles-mêmes sélectionner le fichier pour visualiser les données.</p>
<p>Il est évidemment possible d'indiquer un fichier à afficher par défaut. C'est ce qui est fait dans les autres exemples.</p>
<p>Sur cette page vous permet de tester directement freeDatas2HTML en affichant les données d'un fichier CSV de votre choix. Vous pourrez choisir les champs/colonnes à afficher. Suivant la taille de votre écran ou encore le nombre champs, le résultat peut être + ou moins lisible. freeDatas2HTML permet d'afficher les données autrement que sous forme de tableau pour prévoir ce type de situation.</p>
<p>Pour rappel, freeDatas2HTML s'exécute uniquement côté client, c'est-à-dire dans votre navigateur. Les donnée de votre fichier ne sont donc pas envoyées sur un serveur. En conséquence, si vous partager cette page avec d'autres personnes, elles devront elles-mêmes sélectionner le fichier pour visualiser les données. Il est évidemment possible d'indiquer un fichier à afficher par défaut. C'est ce qui est fait dans les autres exemples présentés sur ce site.</p>
<form id="userSettings">
<fieldset class="form-group">
<legend>Configuration</legend>
<label for="myFile">Sélectionnez votre fichier CSV :</label><input type="file" id="myFile" name="myFile" accept=".csv, .tsv">
</fieldset>
<div id="displayOptions">
@ -27,16 +26,10 @@
</form>
<div class="row">
<div id="filtre1" class="sm-12 md-6 lg-4 col"></div>
<div id="filtre2" class="sm-12 md-6 lg-4 col"></div>
<div id="filtre3" class="sm-12 md-6 lg-4 col"></div>
<div id="paginationOptions" class="col-12 col"></div>
<div id="search" class="sm-12 md-6 lg-6 col"></div>
</div>
<!--<h3>Nombre total de résultats : <span id="compteur"></span></h3>-->
<article id="datas">
</article>
<article id="datas"></article>
<p id="pages"></p>
<aside><p>Design basé sur <a href="https://www.getpapercss.com" target="_blank">PaperCSS</a></p></aside>
</body>

View File

@ -18,7 +18,8 @@
<div id="filtre1" class="sm-12 md-6 lg-4 col"></div>
<div id="filtre2" class="sm-12 md-6 lg-4 col"></div>
<div id="filtre3" class="sm-12 md-6 lg-4 col"></div>
<div id="paginationOptions" class="col-12 col"></div>
<div id="paginationOptions" class="sm-12 md-6 lg-6 col"></div>
<div id="search" class="sm-12 md-6 lg-6 col"></div>
</div>
<h3>Nombre total de résultats : <span id="compteur"></span></h3>

View File

@ -94,7 +94,7 @@ export class FreeDatas2HTML
return this._nbDatasValid;
}
get fields2Rend() : number[]
get fields2Rend() : number[]
{
return this._fields2Rend;
}
@ -209,6 +209,7 @@ export class FreeDatas2HTML
if(this._datasCounterElt !== undefined)
{
// Dans certains cas, il est nécessaire de rechercher de nouveau l'élément pour que l'affichage fonctionne correctement.
// Du coup, revoir intérêt de faire la même chose dans le setter ?
const searchEltInDOM=document.getElementById(this._datasCounterElt.id);
if(searchEltInDOM !== null)
searchEltInDOM.textContent=""+this._nbDatasValid;

View File

@ -1,4 +1,4 @@
import { FreeDatas2HTML, Pagination, Render, Selector, SortingField } from "./FreeDatas2HTML";
import { FreeDatas2HTML, Pagination, Render, SearchEngine, Selector, SortingField } from "./FreeDatas2HTML";
const initialise = async () =>
{
@ -23,6 +23,7 @@ const initialise = async () =>
converter.parser.setRemoteSource({ url:"http://localhost:8080/datas/elements-chimiques.csv" });
converter.datasViewElt={ id:"datas" };
await converter.run();
// Adaptation du rendu suivant la taille de l'écran
const myRender=new Render();
if(window.innerWidth < 800)
@ -66,9 +67,17 @@ const initialise = async () =>
filtre2.filter2HTML();
let filtre3=new Selector(converter, 5, { id:"filtre3"}, ",");
filtre3.filter2HTML();
// + un moteur de recherche
const mySearch=new SearchEngine(converter, { id:"search" }, [1,3,5]);
mySearch.label="Qui cherche trouve ?";
mySearch.btnTxt="Va chercher !";
mySearch.automaticSearch=true;
mySearch.nbCharsForSearch=2;
mySearch.placeholder="Tapes en NB, chef !";
mySearch.filter2HTML();
// + Injection des filtres dans le convertisseur
converter.datasFilters=[filtre1,filtre2,filtre3];
converter.datasFilters=[filtre1,filtre2,filtre3, mySearch];
// Ajout de champs permettant de classer les données
// Uniquement avec un rendu tableau (grand écran), car entêtes de colonne nécessaires
if(window.innerWidth >= 800)

View File

@ -10,9 +10,12 @@ const initialise = async () =>
const dataDisplayOptionsElt=document.getElementById("displayOptions");
if(myFile === null || myForm === null || dataDisplayOptionsElt === null || dataDisplayElt === null)
throw new Error("Certains éléments nécessaires n'ont pas été trouvés dans le DOM;");
throw new Error("Certains éléments nécessaires au fonctionnement n'ont pas été trouvés dans le DOM;");
const converter=new FreeDatas2HTML("CSV");
const myRender=new Render();
myRender.settings.allBegining="<table class='table-hover'><caption>Nombre de résultats : <span id='counter'></span></caption>";
converter.datasRender=myRender;
myFile.addEventListener("change", function(e)
{
@ -22,7 +25,7 @@ const initialise = async () =>
if(selectedFiles !== null && selectedFiles.length === 1)
{
if(selectedFiles[0].type !== "text/csv" && selectedFiles[0].type !== "text/tsv")
dataDisplayOptionsElt.innerHTML=`<p class='text-danger'>Le fichier que vous avez sélectionné ne semble pas être un fichier CSV ?</p>`;
dataDisplayOptionsElt.innerHTML=`<p class='text-danger'>Le document que vous avez sélectionné ne semble pas être un fichier CSV valide.</p>`;
else
{
const reader=new FileReader();
@ -30,17 +33,11 @@ const initialise = async () =>
{
converter.parser.datas2Parse=reader.result as string;
await converter.run();
let fieldsSelectorHTML=`<fieldset class="form-group"><legend>Quels champs souhaitez-vous afficher ?</legend>`;
let filtersSelectorHTML=`<fieldset class="form-group"><legend>Avec quels champs souhaitez-vous pouvoir filtrer vos données ?</legend>`;
for(let i=0; i < converter.fields.length; i++)
{
fieldsSelectorHTML+=`<label for="selectedField_${i}" class="paper-check"> <input type="checkbox" class="selectedFields" id="selectedField_${i}" name="selectedField_${i}" value=${i}> <span>${converter.fields[i]}</span></label>`;
filtersSelectorHTML+=`<label for="selectedFilter_${i}" class="paper-check"> <input type="checkbox" class="selectedFilters" id="selectedFilter_${i}" name="selectedFilter_${i}" value=${i}> <span>${converter.fields[i]}</span></label>`;
}
fieldsSelectorHTML+=`<label for="selectedField_${i}" class="paper-check"> <input type="checkbox" class="selectedFields" id="selectedField_${i}" name="selectedField_${i}" value=${i} checked> <span>${converter.fields[i]}</span></label>`;
fieldsSelectorHTML+=`</fieldset>`;
filtersSelectorHTML+=`</fieldset>`;
dataDisplayOptionsElt.innerHTML=fieldsSelectorHTML+filtersSelectorHTML+`<button type="submit" class="btn-success">Valider</button>`;
dataDisplayOptionsElt.innerHTML=fieldsSelectorHTML+`<button type="submit" class="btn-success">Valider</button>`;
};
reader.readAsText(selectedFiles[0]);
}
@ -50,6 +47,7 @@ const initialise = async () =>
myForm.addEventListener("submit", function(e)
{
e.preventDefault();
dataDisplayElt.innerHTML="";
const fields2Rend: number[]=[];
let checkBox: HTMLInputElement, nbSelector=0;
for(let i=0; i < converter.fields.length; i++)
@ -60,33 +58,47 @@ const initialise = async () =>
if(checkBox.checked)
fields2Rend.push(i);
}
if(nbSelector < 3)
{
checkBox=document.getElementById("selectedFilter_"+i) as HTMLInputElement;
if(checkBox !== null)
{
if(checkBox.checked)
{
nbSelector++;
let filtre1=new Selector(converter, i, { id:"filtre"+nbSelector} );
filtre1.filter2HTML();
converter.datasFilters.push(filtre1);
}
}
}
}
/// + rendre classable toutes les colonnes
/// + ajout moteur de recherche
/// + nombre de résultat
/// + rendu autre que tableau ou alors permettre scroll horizontale ?
if( fields2Rend.length === 0)
dataDisplayElt.innerHTML=`<p class='text-danger'>Vous n'avez sélectionné aucun champ à afficher !</p>`;
else
{
converter.fields2Rend=fields2Rend;
converter.datasViewElt={ id:"datas" };
converter.run();// run pour prendre les champs à afficher, mais refreshView devrait suffire !
// + Un moteur de recherche :
const mySearch=new SearchEngine(converter, { id:"search" });
mySearch.label="Qui cherche trouve ?";
mySearch.btnTxt="Va chercher !";
mySearch.automaticSearch=true;
mySearch.nbCharsForSearch=2;
mySearch.placeholder="Saisir un moins 2 caractères";
mySearch.filter2HTML();
converter.datasFilters=[mySearch];
// + Pagination :
const pagination=new Pagination(converter, { id:"pages" }, "Page à afficher :");
pagination.options={ displayElement: { id:"paginationOptions" }, values: [10,20,50,500] , name: "Choix de pagination :" };
pagination.selectedValue=10;
converter.pagination=pagination;
pagination.options2HTML();
// Actualisation de l'affichage
converter.refreshView();
// + Compteur :
converter.datasCounterElt={ id:"counter" };
converter.datasCounter2HTML();
// +Toutes les colonnes classables :
let sortingField: SortingField;
for(let i=0; i < converter.fields2Rend.length; i++)
{
sortingField=new SortingField(converter, i);
sortingField.field2HTML();
converter.datasSortingFields.push(sortingField);
}
}
});
}
@ -94,7 +106,7 @@ const initialise = async () =>
{
console.error(e);
if(document.getElementById("datas")!==null)
document.getElementById("datas")!.innerHTML="<strong>Désolé, mais un problème technique empêche l'affichage des données.</strong>";
document.getElementById("datas")!.innerHTML=`<strong>Désolé, mais un problème imprévu empêche l'affichage des données.</strong>`;
}
}
initialise();

View File

@ -111,18 +111,6 @@ describe("Tests du script central de FreeDatas2HTML", () =>
expect(converter.fields).toEqual(converter.parser.parseResults.fields);
});
it("Si le parsage s'est bien déroulé et que tous les champs doivent être affichés, leur liste 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'une liste de champs à afficher a été fournie, seuls ceux demandés doivent être transmis au moteur de rendu.", async () =>
{
converter.fields2Rend=[1,2];
await converter.run();
expect(converter.datasRender.fields).toEqual([converter.parser.parseResults.fields[1],converter.parser.parseResults.fields[2]]);
});
it("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");
@ -244,6 +232,39 @@ describe("Tests du script central de FreeDatas2HTML", () =>
expect(converter.datas2HTML).toHaveBeenCalled();
expect(converter.datasRender.datas).toEqual(converter.datas2Rend);
});
it("Si des champs à afficher n'ont pas été renseignés, tous ceux trouvés par le parserur doivent tous être transmis au moteur de rendu.", () =>
{
converter.refreshView();
expect(converter.datasRender.fields).toEqual(converter.parser.parseResults.fields);
});
it("Si dans champs à afficher ont été renseignés, ils doivent être transmis au moteur rendu", async () =>
{
converter.fields2Rend=[1,2];
await converter.run();
expect(converter.datasRender.fields).toEqual([converter.parser.parseResults.fields[1],converter.parser.parseResults.fields[2]]);
});
it("Doit appelé la fonction actualisant le compteur d'enregistrements.", () =>
{
spyOn(converter, "datasCounter2HTML");
converter.refreshView();
expect(converter.datasCounter2HTML).toHaveBeenCalled();
});
it("Si un élément du DOM est renseigné pour le compteur, il doit afficher le nombre d'enregistrements.", async () =>
{
converter.datasCounterElt={ id:"counter" };
converter.datasCounter2HTML();
converter.refreshView();
expect(document.getElementById("counter").textContent).toEqual("118");
// Y compris quand aucune donnée trouvée :
converter.parser=new ParserForCSV();
converter.parser.datas2Parse="name,firstname,city";
await converter.run();
expect(document.getElementById("counter").textContent).toEqual("0");
});
it("Doit appelé le moteur de rendu et afficher le résultat dans la page.", async () =>
{