Relecture code et tests du parseur HTML.
This commit is contained in:
parent
df2658686d
commit
036c3b3400
@ -5,13 +5,12 @@ import { RemoteSource } from "./RemoteSource";
|
|||||||
export class ParserForHTML implements Parsers
|
export class ParserForHTML implements Parsers
|
||||||
{
|
{
|
||||||
private _datasRemoteSource: RemoteSources;
|
private _datasRemoteSource: RemoteSources;
|
||||||
private _document2Parse: HTMLDocument=document;
|
private _document2Parse: HTMLDocument=document;
|
||||||
private _parseResults: ParseResults|undefined=undefined;
|
private _parseResults: ParseResults|undefined=undefined;
|
||||||
private _fieldsSelector: string="table > thead > tr > th";
|
private _fieldsSelector: string="table > thead > tr > th";
|
||||||
private _rowsSelector: string="table > tbody > tr";
|
private _rowsSelector: string="table > tbody > tr";
|
||||||
private _datasSelector: string="tr > td";
|
private _datasSelector: string="tr > td";
|
||||||
|
|
||||||
// L'instance d'une autre classe que RemoteSource peut être passée au constructeur
|
|
||||||
constructor(datasRemoteSource?: RemoteSources)
|
constructor(datasRemoteSource?: RemoteSources)
|
||||||
{
|
{
|
||||||
if(datasRemoteSource !== undefined)
|
if(datasRemoteSource !== undefined)
|
||||||
@ -81,14 +80,13 @@ export class ParserForHTML implements Parsers
|
|||||||
|
|
||||||
public async parse(): Promise<any>
|
public async parse(): Promise<any>
|
||||||
{
|
{
|
||||||
const parser=this;
|
|
||||||
const realFields: string[]=[], datas: {[index: string]:string}[]=[], parseErrors: ParseErrors[]=[];
|
const realFields: string[]=[], datas: {[index: string]:string}[]=[], parseErrors: ParseErrors[]=[];
|
||||||
|
|
||||||
// Document HTML distant ?
|
// Document HTML distant ?
|
||||||
if(parser._datasRemoteSource.url !== "")
|
if(this._datasRemoteSource.url !== "")
|
||||||
{
|
{
|
||||||
const settings: {}=parser._datasRemoteSource.getFetchSettings();
|
const settings: {}=this._datasRemoteSource.getFetchSettings();
|
||||||
const response=await fetch(parser._datasRemoteSource.url, settings);
|
const response=await fetch(this._datasRemoteSource.url, settings);
|
||||||
if (! response.ok)
|
if (! response.ok)
|
||||||
throw new Error(errors.parserRemoteFail);
|
throw new Error(errors.parserRemoteFail);
|
||||||
const responseHTML=await response.text();
|
const responseHTML=await response.text();
|
||||||
@ -96,8 +94,7 @@ export class ParserForHTML implements Parsers
|
|||||||
this._document2Parse=parserDOM.parseFromString(responseHTML, "text/html");
|
this._document2Parse=parserDOM.parseFromString(responseHTML, "text/html");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Récupérer les noms des champs qui doivent avoir été fournis
|
// Récupération du noms de champs
|
||||||
// Ils ne peuvent être une chaîne vide ou en doublon
|
|
||||||
const fields=this._document2Parse.querySelectorAll(this._fieldsSelector);
|
const fields=this._document2Parse.querySelectorAll(this._fieldsSelector);
|
||||||
if(fields.length === 0)
|
if(fields.length === 0)
|
||||||
throw new Error(errors.parserElementsNotFound+this._fieldsSelector);
|
throw new Error(errors.parserElementsNotFound+this._fieldsSelector);
|
||||||
@ -107,13 +104,12 @@ export class ParserForHTML implements Parsers
|
|||||||
if(checkField !== "" && realFields.indexOf(checkField) === -1)
|
if(checkField !== "" && realFields.indexOf(checkField) === -1)
|
||||||
realFields.push(checkField);
|
realFields.push(checkField);
|
||||||
else
|
else
|
||||||
console.error(errors.parserFieldNameFail); // lancer une exception, car risque de bugs par la suite ???
|
parseErrors.push({ row:-1, message: errors.parserFieldNameFail});
|
||||||
}
|
}
|
||||||
if(realFields.length === 0)
|
if(realFields.length === 0)
|
||||||
throw new Error(errors.parserFieldsNotFound);
|
throw new Error(errors.parserFieldsNotFound);
|
||||||
|
|
||||||
// Puis récupération des données.
|
// Puis récupération des éventuelles données.
|
||||||
// Il peut n'y avoir aucune ligne si aucune donnée trouvée.
|
|
||||||
const rows=this._document2Parse.querySelectorAll(this._rowsSelector);
|
const rows=this._document2Parse.querySelectorAll(this._rowsSelector);
|
||||||
let datasElts;
|
let datasElts;
|
||||||
for(let i=0; i < rows.length; i++)
|
for(let i=0; i < rows.length; i++)
|
||||||
@ -121,7 +117,7 @@ export class ParserForHTML implements Parsers
|
|||||||
// Les nombre de données par ligne ne devrait pas être différent du nombre de champs.
|
// Les nombre de données par ligne ne devrait pas être différent du nombre de champs.
|
||||||
datasElts=rows[i].querySelectorAll(this._datasSelector);
|
datasElts=rows[i].querySelectorAll(this._datasSelector);
|
||||||
if(datasElts.length !== realFields.length)
|
if(datasElts.length !== realFields.length)
|
||||||
parseErrors.push({ row:i, message:errors.parserMeetErrors});
|
parseErrors.push({ row:i, message:errors.parserNumberOfFieldsFail});
|
||||||
// Les chaînes vides sont par contre acceptées ici.
|
// Les chaînes vides sont par contre acceptées ici.
|
||||||
let dataObject: {[index: string]: string} = {}
|
let dataObject: {[index: string]: string} = {}
|
||||||
for(let j=0; j < datasElts.length && j < realFields.length; j++)
|
for(let j=0; j < datasElts.length && j < realFields.length; j++)
|
||||||
@ -130,9 +126,9 @@ export class ParserForHTML implements Parsers
|
|||||||
if(Object.keys(dataObject).length !== 0)
|
if(Object.keys(dataObject).length !== 0)
|
||||||
datas.push(dataObject)
|
datas.push(dataObject)
|
||||||
else
|
else
|
||||||
parseErrors.push({ row:i, message:errors.parserMeetErrors});
|
parseErrors.push({ row:i, message: errors.parserLineWithoutDatas});
|
||||||
}
|
}
|
||||||
parser._parseResults =
|
this._parseResults =
|
||||||
{
|
{
|
||||||
datas: datas,
|
datas: datas,
|
||||||
errors: parseErrors,
|
errors: parseErrors,
|
||||||
|
@ -21,9 +21,10 @@ describe("Tests du parseur HTML", () =>
|
|||||||
it("Doit avoir créé une instance du parseur.", () =>
|
it("Doit avoir créé une instance du parseur.", () =>
|
||||||
{
|
{
|
||||||
expect(parser).toBeInstanceOf(Parser);
|
expect(parser).toBeInstanceOf(Parser);
|
||||||
|
expect(parser.datasRemoteSource.url).toEqual("");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Ne doit pas accepter des valeurs vides pour les sélecteurs CSS.", () =>
|
it("Ne doit pas accepter de valeurs vides pour les sélecteurs CSS.", () =>
|
||||||
{
|
{
|
||||||
expect(() => { return parser.fieldsSelector=""; }).toThrowError(errors.parserSelectorsIsEmpty);
|
expect(() => { return parser.fieldsSelector=""; }).toThrowError(errors.parserSelectorsIsEmpty);
|
||||||
expect(() => { return parser.rowsSelector=" "; }).toThrowError(errors.parserSelectorsIsEmpty);
|
expect(() => { return parser.rowsSelector=" "; }).toThrowError(errors.parserSelectorsIsEmpty);
|
||||||
@ -47,30 +48,42 @@ describe("Tests du parseur HTML", () =>
|
|||||||
const doc=parserDOM.parseFromString(htmlString, "text/html");
|
const doc=parserDOM.parseFromString(htmlString, "text/html");
|
||||||
expect(parser.document2Parse).toEqual(doc);
|
expect(parser.document2Parse).toEqual(doc);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Si des options de connexion distante sont fournies, elles doivent être utilisées.", async () =>
|
||||||
|
{
|
||||||
|
spyOn(window, "fetch").and.callThrough();
|
||||||
|
parser.setRemoteSource({ url:"http://localhost:9876/datas/datas.html", headers: [{ key:"token", value:"1234" }, { key:"userName", value:"Toto" }], withCredentials:true });
|
||||||
|
await parser.parse();
|
||||||
|
const headers=new Headers();
|
||||||
|
headers.append("token", "1234");
|
||||||
|
headers.append("userName", "Toto");
|
||||||
|
expect(window.fetch).toHaveBeenCalledWith("http://localhost:9876/datas/datas.html", { method: "GET", headers: headers, credentials: "include" });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Extraction des données du document.", () =>
|
describe("Extraction des données du document.", () =>
|
||||||
{
|
{
|
||||||
it("Doit générer une erreur si aucun élément n'est trouvé dans le document pour les sélecteurs CSS fournis pour les noms de champs.", async () =>
|
it("Doit générer une erreur si aucun élément n'est trouvé dans le document pour les sélecteurs CSS fournis pour les noms de champs.", async () =>
|
||||||
{
|
{
|
||||||
await expectAsync(parser.parse()).toBeRejectedWith(new Error(errors.parserElementsNotFound+"table > thead > tr > th")); // valeurs par défaut, mais rien dans le DOM
|
await expectAsync(parser.parse()).toBeRejectedWith(new Error(errors.parserElementsNotFound+"table > thead > tr > th")); // = valeurs par défaut, mais rien dans le DOM
|
||||||
datasElt.innerHTML=fixtures.htmlParserDatas;
|
datasElt.innerHTML=fixtures.htmlParserDatas;
|
||||||
await expectAsync(parser.parse()).not.toBeRejectedWith(new Error(errors.parserElementsNotFound+"table > thead > tr > th"));
|
await expectAsync(parser.parse()).not.toBeRejectedWith(new Error(errors.parserElementsNotFound+"table > thead > tr > th"));
|
||||||
parser.fieldsSelector="ul#dontExist > li"; // n'existe pas dans ce qui a été injecté
|
parser.fieldsSelector="ul#dontExist > li"; // n'existe pas dans ce qui a été injecté
|
||||||
await expectAsync(parser.parse()).toBeRejectedWith(new Error(errors.parserElementsNotFound+"ul#dontExist > li"));
|
await expectAsync(parser.parse()).toBeRejectedWith(new Error(errors.parserElementsNotFound+"ul#dontExist > li"));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Les noms de champ vides ou en doublon doivent être ignorés.", async () =>
|
it("Les noms de champ vides ou en doublon doivent être ignorés et les erreurs reportées.", async () =>
|
||||||
{
|
{
|
||||||
datasElt.innerHTML="<ul><li>Champ1</li><li> </li><li>Champ2</li><li>Champ2</li></ul>";
|
datasElt.innerHTML="<ul><li>Champ1</li><li> </li><li>Champ2</li><li>Champ2</li></ul>";
|
||||||
parser.fieldsSelector="ul > li";
|
parser.fieldsSelector="ul > li";
|
||||||
await parser.parse();
|
await parser.parse();
|
||||||
expect(parser.parseResults.fields).toEqual(["Champ1","Champ2"]);
|
expect(parser.parseResults.fields).toEqual(["Champ1","Champ2"]);
|
||||||
|
expect(parser.parseResults.errors).toEqual([{ row:-1, message: errors.parserFieldNameFail}, { row:-1, message: errors.parserFieldNameFail}]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Au moins un nom de champ valide doit avoir été trouvé.", async () =>
|
it("Doit générer une erreur, si aucun nom de champ valide n'est trouvé dans le document.", async () =>
|
||||||
{
|
{
|
||||||
datasElt.innerHTML="<ul><li></li><li> </li></ul>";
|
datasElt.innerHTML="<ul><li> </li><li> </li></ul>";
|
||||||
parser.fieldsSelector="ul > li";
|
parser.fieldsSelector="ul > li";
|
||||||
await expectAsync(parser.parse()).toBeRejectedWith(new Error(errors.parserFieldsNotFound));
|
await expectAsync(parser.parse()).toBeRejectedWith(new Error(errors.parserFieldsNotFound));
|
||||||
});
|
});
|
||||||
@ -87,13 +100,13 @@ describe("Tests du parseur HTML", () =>
|
|||||||
datasElt.innerHTML=fixtures.htmlParserDatasBadFields; // un "td" manquant en ligne 0 et un en trop en ligne 1
|
datasElt.innerHTML=fixtures.htmlParserDatasBadFields; // un "td" manquant en ligne 0 et un en trop en ligne 1
|
||||||
await parser.parse();
|
await parser.parse();
|
||||||
expect(parser.parseResults.datas).toEqual([{"Z (numéro atomique)":"1","Élément":"Hydrogène", Symbole:"H", Famille:"Non-métal" }, {"Z (numéro atomique)":"2","Élément":"Hélium", Symbole:"He", Famille:"Gaz noble", "Mots-clés":"Mot-clé2" }, {"Z (numéro atomique)":"3","Élément":"Lithium", Symbole:"Li", Famille:"Métal alcalin", "Mots-clés":"Mot-clé2,Mot-clé1" }, {"Z (numéro atomique)":"4","Élément":"Béryllium", Symbole:"Be", Famille:"Métal alcalino-terreux", "Mots-clés":"Mot-clé3" }]);
|
expect(parser.parseResults.datas).toEqual([{"Z (numéro atomique)":"1","Élément":"Hydrogène", Symbole:"H", Famille:"Non-métal" }, {"Z (numéro atomique)":"2","Élément":"Hélium", Symbole:"He", Famille:"Gaz noble", "Mots-clés":"Mot-clé2" }, {"Z (numéro atomique)":"3","Élément":"Lithium", Symbole:"Li", Famille:"Métal alcalin", "Mots-clés":"Mot-clé2,Mot-clé1" }, {"Z (numéro atomique)":"4","Élément":"Béryllium", Symbole:"Be", Famille:"Métal alcalino-terreux", "Mots-clés":"Mot-clé3" }]);
|
||||||
expect(parser.parseResults.errors[0]).toEqual({row:0,message:errors.parserMeetErrors});
|
expect(parser.parseResults.errors[0]).toEqual({row:0,message:errors.parserNumberOfFieldsFail});
|
||||||
expect(parser.parseResults.errors[1]).toEqual({row:1,message:errors.parserMeetErrors});
|
expect(parser.parseResults.errors[1]).toEqual({row:1,message:errors.parserNumberOfFieldsFail});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Le fait qu'aucune donnée ne soit trouvée ne doit pas générer une erreur.", async () =>
|
it("Le fait qu'aucune donnée ne soit trouvée ne doit pas générer une erreur.", async () =>
|
||||||
{
|
{
|
||||||
datasElt.innerHTML="<table><thead><tr><th>Champ1</th><th>Champ2</th></tr></thead></table>"
|
datasElt.innerHTML="<table><thead><tr><th>Champ1</th><th>Champ2</th></tr></thead></table>";
|
||||||
await expectAsync(parser.parse()).toBeResolved();
|
await expectAsync(parser.parse()).toBeResolved();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -102,7 +115,7 @@ describe("Tests du parseur HTML", () =>
|
|||||||
datasElt.innerHTML=fixtures.htmlParserDatasEmptyLine; // avant dernière ligne sans "td", "Mots-clé" vide pour la 1ière ligne.
|
datasElt.innerHTML=fixtures.htmlParserDatasEmptyLine; // avant dernière ligne sans "td", "Mots-clé" vide pour la 1ière ligne.
|
||||||
await parser.parse();
|
await parser.parse();
|
||||||
expect(parser.parseResults.datas).toEqual([{"Z (numéro atomique)":"1","Élément":"Hydrogène", Symbole:"H", Famille:"Non-métal", "Mots-clés":"" }, {"Z (numéro atomique)":"2","Élément":"Hélium", Symbole:"He", Famille:"Gaz noble", "Mots-clés":"Mot-clé2" }, {"Z (numéro atomique)":"3","Élément":"Lithium", Symbole:"Li", Famille:"Métal alcalin", "Mots-clés":"Mot-clé2,Mot-clé1" }, {"Z (numéro atomique)":"4","Élément":"Béryllium", Symbole:"Be", Famille:"Métal alcalino-terreux", "Mots-clés":"Mot-clé3" }]);
|
expect(parser.parseResults.datas).toEqual([{"Z (numéro atomique)":"1","Élément":"Hydrogène", Symbole:"H", Famille:"Non-métal", "Mots-clés":"" }, {"Z (numéro atomique)":"2","Élément":"Hélium", Symbole:"He", Famille:"Gaz noble", "Mots-clés":"Mot-clé2" }, {"Z (numéro atomique)":"3","Élément":"Lithium", Symbole:"Li", Famille:"Métal alcalin", "Mots-clés":"Mot-clé2,Mot-clé1" }, {"Z (numéro atomique)":"4","Élément":"Béryllium", Symbole:"Be", Famille:"Métal alcalino-terreux", "Mots-clés":"Mot-clé3" }]);
|
||||||
expect(parser.parseResults.errors[0]).toEqual({row:3,message:errors.parserMeetErrors});
|
expect(parser.parseResults.errors[1]).toEqual({row:3,message:errors.parserLineWithoutDatas});// errors[0] = erreur nombre de champs 1ère ligne
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Si le code HTML fourni est ok, aucune erreur de lecture ne doit être reportée.", async () =>
|
it("Si le code HTML fourni est ok, aucune erreur de lecture ne doit être reportée.", async () =>
|
||||||
@ -112,6 +125,5 @@ describe("Tests du parseur HTML", () =>
|
|||||||
expect(parser.parseResults.datas).toEqual([{"Z (numéro atomique)":"1","Élément":"Hydrogène", Symbole:"H", Famille:"Non-métal", "Mots-clés":"" }, {"Z (numéro atomique)":"2","Élément":"Hélium", Symbole:"He", Famille:"Gaz noble", "Mots-clés":"Mot-clé2" }, {"Z (numéro atomique)":"3","Élément":"Lithium", Symbole:"Li", Famille:"Métal alcalin", "Mots-clés":"Mot-clé2,Mot-clé1" }, {"Z (numéro atomique)":"4","Élément":"Béryllium", Symbole:"Be", Famille:"Métal alcalino-terreux", "Mots-clés":"Mot-clé3" }]);
|
expect(parser.parseResults.datas).toEqual([{"Z (numéro atomique)":"1","Élément":"Hydrogène", Symbole:"H", Famille:"Non-métal", "Mots-clés":"" }, {"Z (numéro atomique)":"2","Élément":"Hélium", Symbole:"He", Famille:"Gaz noble", "Mots-clés":"Mot-clé2" }, {"Z (numéro atomique)":"3","Élément":"Lithium", Symbole:"Li", Famille:"Métal alcalin", "Mots-clés":"Mot-clé2,Mot-clé1" }, {"Z (numéro atomique)":"4","Élément":"Béryllium", Symbole:"Be", Famille:"Métal alcalino-terreux", "Mots-clés":"Mot-clé3" }]);
|
||||||
expect(parser.parseResults.errors.length).toEqual(0);
|
expect(parser.parseResults.errors.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
Loading…
Reference in New Issue
Block a user