import { Option } from '@flood/element-report' ; import { Feeder , FeedFilterFunction } from './Feeder' ; import { FileType , Loader , NullLoader } from './Loader' ; /**
 * A `TestDataFactory` is available to be imported into your test script as `TestData`. Use this to load a <[TestDataSource]> which provides new test data to each iteration of your test.
 *
 * TODO
 * Files should be uploaded to ...
 */ export interface TestDataFactory { param objects fromData < TRow > ( objects ) : TestDataSource < TRow > ; param filename param separator fromCSV < TRow > ( filename , separator ) : TestDataSource < TRow > ; param filename fromJSON < TRow > ( filename ) : TestDataSource < TRow > ; } /**
 * TestDataSource is the instance returned by <[TestDataFactory]>'s methods.
 *
 * Call TestDataSource's methods to configure your data source:
 *
 * ```typescript
 * import { step, Browser, TestData, TestSettings } from '@flood/element'
 * export const settings: TestSettings = {
 *   loopCount: -1
 * }
 *
 * interface Row {
 *   username: string
 *   userID: number
 * }
 * TestData.fromCSV<Row>('users.csv')
 *   .circular(false) // Switch off circular data iteration.
 *                    // By default, when the end of the data is reached, it wraps to the beginning.
 *   .shuffle()       // Shuffle the data
 *
 * export default () => {
 *    step('Step 1', async (browser: Browser, row: Row) => {
 *      // for each loop, a different line from user.csv will be available as `row`
 *    })
 * }
 * ```
 */ export class TestDataSource < T > { internal public instanceID : string ; internal private loaders : Loader < T > [ ] ; constructor ( loader ) { this . loaders = [ loader ] ; } private static _instance : TestDataSource < any > ; public static getInstance ( ) { return this . _instance || ( this . _instance = new TestDataSource < any > ( new NullLoader ( ) ) ) ; } public addLoader ( loader ) { this . loaders . push ( loader ) ; return this ; } internal public setInstanceID ( id ) { Feeder . getInstance ( ) . instanceID = id ; } param name public as ( name ) { const loader = this . loaders [ this . loaders . length - 1 ] ; Feeder . getInstance ( ) . configLoaderName ( name , loader . loaderName ) ; loader . asName ( name ) ; return this ; } internal public async load ( ) { const loaderCheck = [ ] ; await Promise . all ( this . loaders . map ( ( loader ) => { if ( loader . type ( ) === FileType . NULL ) return ; loaderCheck . push ( { type : loader . type ( ) , alias : loader . loaderName } ) ; const invalidLoader = loaderCheck . reduce ( ( invalidMsg , lc ) => { if ( lc . type !== loader . type ( ) && lc . alias === loader . loaderName ) { invalidMsg = 'Data files imported using different methods cannot have the same alias' ; } if ( loader . type ( ) === FileType . DATA && lc . type !== FileType . DATA && loader . loaderName === '' ) { invalidMsg = 'Alias name of the data imported using fromData() must be specified by using as()' ; } return invalidMsg ; } , '' ) ; if ( invalidLoader ) { throw Error ( invalidLoader ) ; } return loader . load ( ) ; } ) ) ; const feeder = Feeder . getInstance ( ) ; this . loaders . map ( ( loader ) => { feeder . append ( loader . lines , loader . loaderName , loader . type ( ) ) ; } ) ; } /**
     * clear all loader data
     */ public clear ( ) { this . loaders = [ ] ; Feeder . getInstance ( ) . clear ( ) ; } param circular public circular ( circular = true ) { Feeder . getInstance ( ) . circular ( circular , this . loaders [ this . loaders . length - 1 ] . loaderName ) ; return this ; } param shuffle public shuffle ( shuffle = true ) { Feeder . getInstance ( ) . shuffle ( shuffle , this . loaders [ this . loaders . length - 1 ] . loaderName ) ; return this ; } param func public filter ( func ) { Feeder . getInstance ( ) . filter ( func , this . loaders [ this . loaders . length - 1 ] . loaderName ) ; return this ; } public isLoaded ( ) { return this . loaders . every ( ( loader ) => loader . isLoaded ) ; } public isSet ( ) { return this . loaders . every ( ( loader ) => loader . isSet ) ; } public get multiple ( ) : boolean { return this . loaders . length > 0 ; } internal public feed ( ) { if ( ! this . isLoaded ) throw new Error ( `Test data has not been loaded yet!` ) ; return Feeder . getInstance ( ) . feed ( ) ; } internal public peek ( ) { if ( ! this . isLoaded ) throw new Error ( `Test data has not been loaded yet!` ) ; return Feeder . getInstance ( ) . peek ( ) ; } internal public get size ( ) : number { return Feeder . getInstance ( ) . size ; } internal public get isComplete ( ) : boolean { return Feeder . getInstance ( ) . isComplete ; } internal public get isEmpty ( ) : boolean { return Feeder . getInstance ( ) . isEmpty ; } internal public get isStart ( ) : boolean { return Feeder . getInstance ( ) . isStart ; } internal public toString ( ) { if ( this . isSet ( ) ) { return [ Feeder . getInstance ( ) . toString ( ) , this . loaders . map ( ( loader ) => loader . toString ( ) ) ] . filter ( ( x ) => x . length ) . join ( ', ' ) ; } else { return 'no test data' ; } } }