Ajout du script de tests pour le parseur de CSV.

This commit is contained in:
Fabrice PENHOËT 2021-10-01 13:12:45 +02:00
parent e068aee5aa
commit 0f2543a95e
5 changed files with 188 additions and 21 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "freedatas2html", "name": "freedatas2html",
"version": "0.6.0", "version": "0.6.1",
"description": "Visualization of data from various sources (CSV, API, HTML...) with filters, classification, pagination, etc.", "description": "Visualization of data from various sources (CSV, API, HTML...) with filters, classification, pagination, etc.",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -65,8 +65,8 @@ export interface ParseResults
} }
export interface Parsers export interface Parsers
{ {
datasRemoteSource: RemoteSource|undefined; datasRemoteSource: RemoteSource;
datas2Parse:string|undefined; datas2Parse:string;
parseResults:ParseResults|undefined; parseResults:ParseResults|undefined;
parse(): Promise<void>; parse(): Promise<void>;
} }

View File

@ -2,7 +2,7 @@ const Papa = require("papaparse");
const errors = require("./errors.js"); const errors = require("./errors.js");
import { ParseResults, Parsers, RemoteSource } from "./freeDatas2HTMLInterfaces"; import { ParseResults, Parsers, RemoteSource } from "./freeDatas2HTMLInterfaces";
interface papaParseOptions interface PapaParseOptions
{ {
delimiter: string; delimiter: string;
newline: string; newline: string;
@ -14,16 +14,24 @@ interface papaParseOptions
fastMode: boolean|undefined; fastMode: boolean|undefined;
transform?(value: string): string; transform?(value: string): string;
} }
interface PrivatePapaParseOptions
{
header: boolean; // nécessaire pour obtenir le nom des champs
download: boolean;
downloadRequestHeaders: undefined| { [index: string]:string|boolean|number } ;
skipEmptyLines: string;
withCredentials: boolean|undefined;
}
export class ParserForCSV implements Parsers export class ParserForCSV implements Parsers
{ {
private _datasRemoteSource: RemoteSource|undefined=undefined; private _datasRemoteSource: RemoteSource={ url:"" };
private _datas2Parse:string|undefined=undefined; private _datas2Parse:string="";
private _parseResults:ParseResults|undefined=undefined; private _parseResults:ParseResults|undefined=undefined;
// Ouverture de certaines options de Papa Parse : // Ouverture de certaines options de Papa Parse :
// cf. https://www.papaparse.com/docs#config // cf. https://www.papaparse.com/docs#config
public options: papaParseOptions = public options: PapaParseOptions =
{ {
delimiter: "", delimiter: "",
newline: "", newline: "",
@ -35,7 +43,17 @@ export class ParserForCSV implements Parsers
fastMode: undefined, fastMode: undefined,
transform: undefined transform: undefined
} }
// Options de Papa Parse ne pouvant être modifées de l'extérieur
private _privateOptions: PrivatePapaParseOptions =
{
header: true, // nécessaire pour obtenir le nom des champs
download: false,
downloadRequestHeaders: undefined,
skipEmptyLines:"greedy",
withCredentials: undefined
}
// Revoir tous les protocoles possibles pour une source distante (http(s)://.. , ftp..)
set datasRemoteSource(source: RemoteSource) set datasRemoteSource(source: RemoteSource)
{ {
if(source.url.trim().length === 0) if(source.url.trim().length === 0)
@ -47,6 +65,11 @@ export class ParserForCSV implements Parsers
} }
} }
get datasRemoteSource() : RemoteSource
{
return this._datasRemoteSource;
}
set datas2Parse(datas: string) set datas2Parse(datas: string)
{ {
if(datas.trim().length === 0) if(datas.trim().length === 0)
@ -55,11 +78,21 @@ export class ParserForCSV implements Parsers
this._datas2Parse=datas.trim(); this._datas2Parse=datas.trim();
} }
get datas2Parse() : string
{
return this._datas2Parse;
}
get parseResults() : ParseResults|undefined get parseResults() : ParseResults|undefined
{ {
return this._parseResults; return this._parseResults;
} }
get privateOptions() : any
{
return this._privateOptions;
}
// async dans le cas d'une source distante // async dans le cas d'une source distante
// Et création d'une Promise car PapaParse utilise une fonction callback. // Et création d'une Promise car PapaParse utilise une fonction callback.
public async parse(): Promise<any> public async parse(): Promise<any>
@ -67,20 +100,20 @@ export class ParserForCSV implements Parsers
const parser=this, options=this.options; const parser=this, options=this.options;
return new Promise((resolve,reject) => return new Promise((resolve,reject) =>
{ {
let parseContent="", parseDownload=false, parseDownloadRequestHeaders: any=undefined, parseWithCredentials: any=undefined; let parseContent="";
if(parser._datasRemoteSource !== undefined) if(parser._datasRemoteSource.url !== "")
{ {
parseContent=parser._datasRemoteSource.url; parseContent=parser._datasRemoteSource.url;
parseDownload=true; this._privateOptions.download=true;
parseWithCredentials=parser._datasRemoteSource.withCredentials; // undefined ok pour PapaParse this._privateOptions.withCredentials=parser._datasRemoteSource.withCredentials;
if(parser._datasRemoteSource.headers !== undefined) if(parser._datasRemoteSource.headers !== undefined)
{ {
parseDownloadRequestHeaders={}; this._privateOptions.downloadRequestHeaders={};
for (let i in parser._datasRemoteSource.headers) for (let i in parser._datasRemoteSource.headers)
parseDownloadRequestHeaders[parser._datasRemoteSource.headers[Number(i)].key]=parser._datasRemoteSource.headers[Number(i)].value; this._privateOptions.downloadRequestHeaders[""+parser._datasRemoteSource.headers[Number(i)].key+""]=parser._datasRemoteSource.headers[Number(i)].value;
} }
} }
else if(parser._datas2Parse !== undefined) else if(parser._datas2Parse !== "")
parseContent=parser._datas2Parse; parseContent=parser._datas2Parse;
else else
reject(new Error(errors.parserNeedSource)); reject(new Error(errors.parserNeedSource));
@ -91,7 +124,7 @@ export class ParserForCSV implements Parsers
newline: options.newline, newline: options.newline,
quoteChar: options.quoteChar, quoteChar: options.quoteChar,
escapeChar: options.escapeChar, escapeChar: options.escapeChar,
header: true, // nécessaire pour obtenir le nom des champs header: true,
transformHeader: options.transformHeader, transformHeader: options.transformHeader,
preview: options.preview, preview: options.preview,
comments: options.comments, comments: options.comments,
@ -116,12 +149,12 @@ export class ParserForCSV implements Parsers
resolve(true); resolve(true);
} }
}, },
download: parseDownload, download: this._privateOptions.download,
downloadRequestHeaders: parseDownloadRequestHeaders, downloadRequestHeaders: this._privateOptions.downloadRequestHeaders,
skipEmptyLines:"greedy", skipEmptyLines:"greedy",
fastMode: options.fastMode, fastMode: options.fastMode,
withCredentials: parseWithCredentials, withCredentials: this._privateOptions.withCredentials,
transform: options.transform, transform: options.transform
}); });
}); });
} }

View File

@ -2,7 +2,7 @@ import { FreeDatas2HTML, Render} from "../src/freeDatas2HTML";
const errors=require("../src/errors.js"); const errors=require("../src/errors.js");
const fixtures=require("./fixtures.js"); const fixtures=require("./fixtures.js");
/// Tests à revoir pour ne pas dépendre du bon fonctionnement de Parser et Render (mock...) /// Tests à revoir pour ne pas dépendre du bon fonctionnement de Parser et Render.
describe("Test du script central de FreeDatas2HTML", () => describe("Test du script central de FreeDatas2HTML", () =>
{ {

134
tests/parserForCSVSpec.ts Normal file
View File

@ -0,0 +1,134 @@
const Papa = require("papaparse");
import { RemoteSource } from "../src/freeDatas2HTMLInterfaces";
import { ParserForCSV as Parser } from "../src/freeDatas2HTMLParserForCSV";
const errors=require("../src/errors.js");
// Pas de test de Papa Parse, car module externe
// Mais tests d'instanciation et configuration de la classe l'utilisant
describe("Tests du parseur de CSV", () =>
{
let parser: Parser;
let papaParseOptions: {};
beforeEach( () =>
{
parser=new Parser();
papaParseOptions =
{
delimiter: "",
newline: "",
quoteChar: '"',
escapeChar: '"',
header: true,
transformHeader: function(field: string, index: number): string { return field.trim() },
preview: 0,
comments: "",
complete: function(results :any)
{
console.log(results);// peut importe cette partie pour les tests
},
download: undefined,
downloadRequestHeaders: undefined,
skipEmptyLines:"greedy",
fastMode: undefined,
withCredentials: undefined,
transform: undefined,
}
});
it("Doit avoir créé une instance du Parser", () =>
{
expect(parser).toBeInstanceOf(Parser);
});
it("Doit générer une erreur si l'url fournie pour importer les données est une chaîne vide.", () =>
{
expect(() => { return parser.datasRemoteSource= { url:"" } }).toThrowError(errors.parserNeedUrl);
expect(() => { return parser.datasRemoteSource= { url:" " } }).toThrowError(errors.parserNeedUrl);
});
it("Doit accepter des paramètres valides pour la source de données distante.", () =>
{
let myRemoteSource: RemoteSource={ url:"zz" };
parser.datasRemoteSource=myRemoteSource;
expect(parser.datasRemoteSource).toEqual(myRemoteSource);
myRemoteSource={ url:"zz", headers: [ { key:"test", value: "coucou"}, { key:"test2", value:"coucou2"}], withCredentials:true };
parser.datasRemoteSource=myRemoteSource;
expect(parser.datasRemoteSource).toEqual(myRemoteSource);
});
it("Doit générer une erreur si la chaîne de données à parser est vide.", () =>
{
expect(() => { return parser. datas2Parse= "" }).toThrowError(errors.parserNeedDatas);
expect(() => { return parser. datas2Parse= " " }).toThrowError(errors.parserNeedDatas);
});
it("Doit accepter toute chaîne de caractères non vide pour les données à parser.", () =>
{
parser. datas2Parse="datas";
expect(parser.datas2Parse).toEqual("datas");
});
it("Doit générer une erreur si le parseur est lancé sans source de données fournie.", async () =>
{
await expectAsync(parser.parse()).toBeRejectedWith(new Error(errors.parserNeedSource));
});
it("Si les données sont directement fournies, cela doit être pris en compte dans les options passées à Papa Parse.", () =>
{
// Idéalement il faudrait tester les paramètres passés à PapaParse
// Mais semble impossible à cause des fonctions callback ?
spyOn(Papa, "parse");
parser.datas2Parse="datas";
parser.parse();
expect(parser.privateOptions).toEqual(
{
header: true,
download: false,
downloadRequestHeaders: undefined,
skipEmptyLines:"greedy",
withCredentials: undefined
});
});
it("Si une ressource distante est fournie, cela doit être pris en compte dans les options passées à Papa Parse.", () =>
{
// Même remarque, test précédent
spyOn(Papa, "parse");
let myRemoteSource: RemoteSource={ url:"http://localhost:9876/datas/datas1.csv", withCredentials:true };
parser.datasRemoteSource=myRemoteSource;
parser.parse();
expect(parser.privateOptions).toEqual(
{
header: true,
download: true,
downloadRequestHeaders: undefined,
skipEmptyLines: "greedy",
withCredentials: true
});
myRemoteSource={ url:"http://localhost:9876/datas/datas1.csv", headers: [ { key:"test", value: "coucou"}, { key:"test2", value:"coucou2"}] , withCredentials:false };
parser.datasRemoteSource=myRemoteSource;
parser.parse();
expect(parser.privateOptions).toEqual(
{
header: true,
download: true,
downloadRequestHeaders: { test:"coucou", test2:"coucou2"},
skipEmptyLines: "greedy",
withCredentials: false
});
expect(Papa.parse).toHaveBeenCalledTimes(2);
});
it("Si le parseur a été appelé avec les données nécessaires, des résultats doivent être enregistrés.", async () =>
{
parser.datasRemoteSource={ url:"http://localhost:9876/datas/datas1.csv" };
await parser.parse();
expect(parser.parseResults).not.toBeUndefined();
// Y compris si données fournies bidon :
parser=new Parser();
parser.datas2Parse="datas";
await parser.parse();
expect(parser.parseResults).not.toBeUndefined();
});
});