vendredi 8 décembre 2017

Mocking AngularFire2 with Jest for library component in Typescript

I am trying to create a library class in my project to work with AngularFire2 (and Firebase) that can return data in our data format. We have various options to store the data, and AngularFire2 is what I am now trying to support.

I use a base class to handle the different formats:

  • JSON data from an HTTP call
  • SQL data direct

and I am now trying to add Firebase support.

The idea is that the data providers in my application do not need to understand the source of the data. The data providers will always return the data in our internal structures.

In the DataProvider abstract base class, there are calls to the protected functions of the data provider to parse common data into the application data structure. This all works great, except I do not know how to mock the AngularFire2 libraries to ensure my data is parsing correctly when returned into the base class.

For JSON, it is simple to have a mock of the response from the HTTP call that returns JSON, then my tests can validate that given a certain block of JSON (or errors) the base data provider class parses the information correctly.

All my Ionic data providers will then extend from this base class.

Base Class - data-provider.ts

import { Injectable } from '@angular/core';
...
@Injectable()
export abstract class DataProvider {
    private DataSource:any;

    constructor() { }

    // Functions are here to set the data source, work with the various sources etc.
    ...

    // This needs to be defined in extending class to transfer JSON data (OneDataRecord) into the structure to return
    protected abstract ParseData(OneDataRecord: string): boolean;

    // This controls getting the data from the proper source 
    protected GetData(Location:string, KeyId?:string): string {
        let JSON:string;
        if( DataSource instanceof HTTPClient) {
            JSON = GetHTTPClientData(Location, KeyId);
        } else if ( DataSource instanceof SQLEngine ) {
            JSON = GetSQLEngineData(Location, KeyId);
        } else if ( DataSource instanceof AngularFireDatabase ) {
            JSON = GetAngularFireData(Location, KeyId);
        }
        return JSON;
    }
}

There is then a data provider that extends the class and processes the data

import { Injectable } from '@angular/core';
import { DataProvider } from './data-provider';
import { Team } from './team';
...
@Injectable()
export TeamDataProvider class DataProvider {
    private TeamData_: Team[]
    private TeamStructure: Team = new Team();

    constructor() { 
        ...
    }

    // Functions are here to be the data provider
    ...

    // This is called to get the data from external source (DataProvider base class and then parse JSON)
    LoadTeamData(DataKey?:string ): Observable<Team[]> {
        let JSON:string = super.GetData(this.TeamStructure.Location, DataKey);
        // Loop through JSON to call ParseData with each JSON record to be parsed   
        ...
    }

    // Parse the common data returned into the internal format.  This function knows the structure of the JSON record
    protected ParseData(OneDataRecord: string): boolean
    {
        // Create Team from OneDataRecord by looping through JSON
        ...
    }
}

My problem is in trying to mock the data for the abstract DataProvider class. While I can create a quick dummy easy enough, I want to ensure that parsing the AngularFire data works. When accessing the properties of the data, I have to get the data from the payload.val().XXXX (where XXXX is the property). I do not know how to create this so I can get to the JSON format. The firebase.database.DataSnapshot seems to have a toJSON() method, but I cannot get to it from AngularFire2 5.0.

I am trying to find a way to create a fake data set that could be used to then test that I am parsing the data correctly. I know I can forEach through and parse the data:

forEach(res => res.forEach( OneRecord => this.ParseData(OneRecord)))

I am able to parse the data knowing the format:

OneRecord.payload.val().Name;  // Team Name
OneRecord.payload.val().City   // Team home city
...    

But I want to be able to create this static object without needing to call AngularFire so I can build different data to test with. I cannot seem to put the JSON structure into the payload.val().

TestOneRecord = new DatabaseSnapshot()  // This does not work

I would like to simply be able to do:

TestOneRecord.payload.val().Description = "Team 1";
TestOneRecord.payload.val().City = "My City";

Aucun commentaire:

Enregistrer un commentaire