Moved the factories from the @woocommerce/api package into the @woocommerce/e2e-utils package

This commit is contained in:
Christopher Allford 2020-09-21 13:14:26 -07:00
parent b962c10cee
commit 5297b27c79
12 changed files with 4514 additions and 180 deletions

View File

@ -714,12 +714,6 @@
"@types/node": "*"
}
},
"@types/faker": {
"version": "4.1.12",
"resolved": "https://registry.npmjs.org/@types/faker/-/faker-4.1.12.tgz",
"integrity": "sha512-0MEyzJrLLs1WaOCx9ULK6FzdCSj2EuxdSP9kvuxxdBEGujZYUOZ4vkPXdgu3dhyg/pOdn7VCatelYX7k0YShlA==",
"dev": true
},
"@types/graceful-fs": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz",
@ -1848,11 +1842,6 @@
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"dev": true
},
"faker": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/faker/-/faker-4.1.0.tgz",
"integrity": "sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8="
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -1899,14 +1888,6 @@
"path-exists": "^4.0.0"
}
},
"fishery": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fishery/-/fishery-1.0.0.tgz",
"integrity": "sha512-DLQtxcSPlLQYY6J0tL/dl7DfPhrULHCAO6fFDGnrXqA830J6AW124fHarYOLnfvcSXNBEooBS/g65N/HecQYjQ==",
"requires": {
"lodash.merge": "^4.6.2"
}
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
@ -3113,11 +3094,6 @@
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
"dev": true
},
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
},
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",

View File

@ -34,13 +34,10 @@
"dependencies": {
"axios": "0.19.2",
"create-hmac": "1.1.7",
"faker": "4.1.0",
"fishery": "1.0.0",
"oauth-1.0a": "2.2.6"
},
"devDependencies": {
"@types/create-hmac": "1.1.0",
"@types/faker": "4.1.12",
"@types/jest": "25.2.1",
"@types/moxios": "^0.4.9",
"@types/node": "13.13.5",

View File

@ -1,21 +0,0 @@
import { AsyncFactory } from '../../framework/async-factory';
import { SimpleProduct } from '../../models';
import Mock = jest.Mock;
import { simpleProductFactory } from '../simple-product';
describe( 'simpleProductFactory', () => {
let mockCreator: Mock;
let factory: AsyncFactory< SimpleProduct >;
beforeEach( () => {
mockCreator = jest.fn();
factory = simpleProductFactory( mockCreator );
} );
it( 'should build', () => {
const model = factory.build( { name: 'Test Product' } );
expect( model ).toMatchObject( { name: 'Test Product' } );
expect( parseFloat( model.regularPrice ) ).toBeGreaterThan( 0.0 );
} );
} );

View File

@ -1,22 +0,0 @@
import { AsyncFactory } from '../framework/async-factory';
import { commerce } from 'faker/locale/en';
import { SimpleProduct } from '../models';
import { CreateFn } from '../framework/model-repository';
/**
* Creates a new factory for creating models.
*
* @param {Function} creator The function we will use for creating models.
* @return {AsyncFactory} The factory for creating models.
*/
export function simpleProductFactory( creator: CreateFn< SimpleProduct > ): AsyncFactory< SimpleProduct > {
return new AsyncFactory< SimpleProduct >(
( { params } ) => {
return new SimpleProduct( {
name: params.name ?? commerce.productName(),
regularPrice: params.regularPrice ?? commerce.price(),
} );
},
creator,
);
}

View File

@ -1,47 +0,0 @@
import { Model } from '../../models/model';
import { AsyncFactory } from '../async-factory';
class DummyModel extends Model {
public name: string = '';
public constructor( partial?: Partial< DummyModel > ) {
super();
Object.assign( this, partial );
}
}
describe( 'AsyncFactory', () => {
let factory: AsyncFactory< DummyModel >;
beforeEach( () => {
let sequence = 1;
factory = new AsyncFactory< DummyModel >(
( { params } ) => {
const model = new DummyModel();
model.name = params.name ?? '';
return model;
},
( model ) => {
return Promise.resolve( new DummyModel( { id: sequence++, name: model.name } ) );
},
);
} );
it( 'should create', async () => {
const model = await factory.create( { name: 'test-name' } );
expect( model ).toHaveProperty( 'id', 1 );
expect( model ).toHaveProperty( 'name', 'test-name' );
} );
it( 'should create many', async () => {
const models = await factory.createList( 2, { name: 'test-name' } );
expect( models ).toHaveLength( 2 );
expect( models[ 0 ] ).toHaveProperty( 'id', 1 );
expect( models[ 0 ] ).toHaveProperty( 'name', 'test-name' );
expect( models[ 1 ] ).toHaveProperty( 'id', 2 );
expect( models[ 1 ] ).toHaveProperty( 'name', 'test-name' );
} );
} );

View File

@ -1,47 +0,0 @@
import { BuildOptions, DeepPartial, Factory } from 'fishery';
import { GeneratorFnOptions } from 'fishery/dist/types';
export class AsyncFactory< T, I = any > extends Factory< T, I > {
private readonly creator: ( model: T ) => Promise< T >;
/**
* Creates a new factory instance.
*
* @param {Function} generator The factory's generator function.
* @param {Function} creator The factory's creation function.
*/
public constructor( generator: ( opts: GeneratorFnOptions< T, I > ) => T, creator: ( model: T ) => Promise< T > ) {
super( generator );
this.creator = creator;
}
/**
* Create an object using your factory
*
* @param {DeepPartial} params The parameters that should populate the object.
* @param {BuildOptions} options The options to be used in the builder.
* @return {Promise} Resolves to the created model.
*/
public create( params?: DeepPartial< T >, options?: BuildOptions< T, I > ): Promise< T > {
const model = this.build( params, options );
return this.creator( model );
}
/**
* Create an array of objects using your factory
*
* @param {number} number The number of models to create.
* @param {DeepPartial} params The parameters that should populate the object.
* @param {BuildOptions} options The options to be used in the builder.
* @return {Promise} Resolves to the created models.
*/
public createList( number: number, params?: DeepPartial< T >, options?: BuildOptions< T, I > ): Promise< T[] > {
const models = this.buildList( number, params, options );
const promises: Promise< T >[] = [];
for ( const model of models ) {
promises.push( this.create( model ) );
}
return Promise.all( promises );
}
}

View File

@ -1,8 +1,6 @@
import { AbstractProduct } from './abstract-product';
import { HTTPClient } from '../../http';
import { ModelRepository } from '../../framework/model-repository';
import { AsyncFactory } from '../../framework/async-factory';
import { simpleProductFactory } from '../../factories/simple-product';
import { simpleProductRESTRepository } from '../../repositories/rest/simple-product';
/**
@ -23,14 +21,4 @@ export class SimpleProduct extends AbstractProduct {
public static restRepository( httpClient: HTTPClient ): ModelRepository< SimpleProduct > {
return simpleProductRESTRepository( httpClient );
}
/**
* Creates a new factory instance.
*
* @param {ModelRepository} repository The repository to use for creation.
* @return {AsyncFactory} The new factory instance.
*/
public static factory( repository: ModelRepository< SimpleProduct > ): AsyncFactory< SimpleProduct > {
return simpleProductFactory( ( data ) => repository.create( data ) );
}
}

File diff suppressed because it is too large Load Diff

View File

@ -11,8 +11,10 @@
"main": "build/index.js",
"module": "build-module/index.js",
"dependencies": {
"@woocommerce/api": "file:../api",
"@wordpress/e2e-test-utils": "4.6.0",
"@woocommerce/api": "file:../api"
"faker": "^5.1.0",
"fishery": "^1.0.1"
},
"publishConfig": {
"access": "public"

View File

@ -1,16 +1,17 @@
import { HTTPClientFactory } from '@woocommerce/api';
const config = require( 'config' );
import { HTTPClientFactory, SimpleProduct } from '@woocommerce/api';
const httpClient = HTTPClientFactory.withBasicAuth(
config.get( 'url' ) + '/wp-json',
config.get( 'users.admin.username' ),
config.get( 'users.admin.password' ),
);
import { simpleProductFactory } from './factories/simple-product';
const factories = {
products: {
simple: SimpleProduct.factory( SimpleProduct.restRepository( httpClient ) ),
simple: simpleProductFactory( httpClient ),
},
};

View File

@ -0,0 +1,41 @@
import { Factory } from 'fishery';
/**
* A temporary class until Fishery includes better async support.
*/
export class AsyncFactory extends Factory {
constructor( generator, creator ) {
super( generator );
this.creator = creator;
}
/**
* Create an object using your factory
*
* @param {*} params The parameters that should populate the object.
* @param {*} options The options to be used in the builder.
* @return {Promise} Resolves to the created model.
*/
create( params, options ) {
const model = this.build( params, options );
return this.creator( model );
}
/**
* Create an array of objects using your factory
*
* @param {number} number The number of models to create.
* @param {*} params The parameters that should populate the object.
* @param {*} options The options to be used in the builder.
* @return {Promise} Resolves to the created models.
*/
createList( number, params, options ) {
const models = this.buildList( number, params, options );
const promises = [];
for ( const model of models ) {
promises.push( this.creator( model ) );
}
return Promise.all( promises );
}
}

View File

@ -0,0 +1,23 @@
import { SimpleProduct } from '@woocommerce/api';
import { AsyncFactory } from './async-factory';
import faker from 'faker/locale/en';
/**
* Creates a new factory for creating models.
*
* @param {HTTPClient} httpClient The HTTP client we will give the repository.
* @return {AsyncFactory} The factory for creating models.
*/
export function simpleProductFactory( httpClient ) {
const repository = SimpleProduct.restRepository( httpClient );
return new AsyncFactory(
( { params } ) => {
return new SimpleProduct( {
name: params.name ?? faker.commerce.productName(),
regularPrice: params.regularPrice ?? faker.commerce.price(),
} );
},
( params ) => repository.create( params ),
);
}