From 3cf48a831b9812845e9c2543419a347648c84e83 Mon Sep 17 00:00:00 2001 From: Lawrence Forman Date: Sun, 28 Jul 2019 13:23:47 -0400 Subject: [PATCH] `@0x/contracts-test-utils`: Export a custom `describe()` instead of extending Mocha's ambient declarations. `@0x/contracts-exchange`: Use `describe.optional` instead of `blockchainTests.optional` in `test/fill_order.ts`. --- contracts/exchange/test/fill_order.ts | 4 +- contracts/test-utils/src/index.ts | 2 +- contracts/test-utils/src/mocha_blockchain.ts | 237 ++++++++++-------- contracts/test-utils/test/mocha_blockchain.ts | 12 +- 4 files changed, 140 insertions(+), 115 deletions(-) diff --git a/contracts/exchange/test/fill_order.ts b/contracts/exchange/test/fill_order.ts index f0d5a15e20..6ce16af5b4 100644 --- a/contracts/exchange/test/fill_order.ts +++ b/contracts/exchange/test/fill_order.ts @@ -1,4 +1,4 @@ -import { blockchainTests } from '@0x/contracts-test-utils'; +import { blockchainTests, describe } from '@0x/contracts-test-utils'; import * as _ from 'lodash'; import { @@ -664,7 +664,7 @@ blockchainTests.resets('FillOrder Tests', ({ web3Wrapper, txDefaults }) => { } }); - blockchainTests.optional('Combinatorially generated fills orders', () => { + describe.optional('Combinatorially generated fills orders', () => { const allFillScenarios = FillOrderCombinatorialUtils.generateFillOrderCombinations(); for (const fillScenario of allFillScenarios) { const description = `Combinatorial OrderFill: ${JSON.stringify(fillScenario)}`; diff --git a/contracts/test-utils/src/index.ts b/contracts/test-utils/src/index.ts index caa36b10eb..3abd3f6070 100644 --- a/contracts/test-utils/src/index.ts +++ b/contracts/test-utils/src/index.ts @@ -45,5 +45,5 @@ export { Token, TransactionDataParams, } from './types'; -export { blockchainTests, BlockchainTestsEnvironment } from './mocha_blockchain'; +export { blockchainTests, BlockchainTestsEnvironment, describe } from './mocha_blockchain'; export { chaiSetup, expect } from './chai_setup'; diff --git a/contracts/test-utils/src/mocha_blockchain.ts b/contracts/test-utils/src/mocha_blockchain.ts index 3bf4240271..bc63763aed 100644 --- a/contracts/test-utils/src/mocha_blockchain.ts +++ b/contracts/test-utils/src/mocha_blockchain.ts @@ -11,34 +11,49 @@ import { provider, txDefaults, web3Wrapper } from './web3_wrapper'; // tslint:disable: no-namespace only-arrow-functions no-unbound-method -// Extend Mocha ambient definitions. -declare global { - export namespace Mocha { - type BlockchainSuiteCallback = (this: ISuiteCallbackContext, env: BlockchainTestsEnvironment) => void; - type SuiteCallback = (this: ISuiteCallbackContext) => void; - type BlockchainContextDefinitionCallback = (description: string, callback: BlockchainSuiteCallback) => T; - type ContextDefinitionCallback = (description: string, callback: SuiteCallback) => T; - - interface BlockchainContextDefinition { - resets: { - only: BlockchainContextDefinitionCallback; - skip: BlockchainContextDefinitionCallback; - optional: BlockchainContextDefinitionCallback; - (description: string, callback: BlockchainSuiteCallback): ISuite; - }; - only: BlockchainContextDefinitionCallback; - skip: BlockchainContextDefinitionCallback; - optional: BlockchainContextDefinitionCallback; - (description: string, callback: BlockchainSuiteCallback): ISuite; - } - } +export type ISuite = Mocha.ISuite; +export type ISuiteCallbackContext = Mocha.ISuiteCallbackContext; +export type SuiteCallback = (this: ISuiteCallbackContext) => void; +export type ContextDefinitionCallback = (description: string, callback: SuiteCallback) => T; +export type BlockchainSuiteCallback = (this: ISuiteCallbackContext, env: BlockchainTestsEnvironment) => void; +export type BlockchainContextDefinitionCallback = (description: string, callback: BlockchainSuiteCallback) => T; +export interface ContextDefinition extends Mocha.IContextDefinition { + optional: ContextDefinitionCallback; } /** - * Describes the test environment prepared by `blockchainTests()`. + * Interface for `blockchainTests()`. */ -export class BlockchainTestsEnvironment { - private static _instance: BlockchainTestsEnvironment | undefined; +export interface BlockchainContextDefinition { + resets: { + only: BlockchainContextDefinitionCallback; + skip: BlockchainContextDefinitionCallback; + optional: BlockchainContextDefinitionCallback; + (description: string, callback: BlockchainSuiteCallback): ISuite; + }; + only: BlockchainContextDefinitionCallback; + skip: BlockchainContextDefinitionCallback; + optional: BlockchainContextDefinitionCallback; + (description: string, callback: BlockchainSuiteCallback): ISuite; +} + +/** + * Describes the environment object passed into the `blockchainTests()` callback. + */ +export interface BlockchainTestsEnvironment { + blockchainLifecycle: BlockchainLifecycle; + provider: Web3ProviderEngine; + txDefaults: Partial; + web3Wrapper: Web3Wrapper; + getChainIdAsync(): Promise; + getAccountAddressesAsync(): Promise; +} + +/** + * Concret implementation of `BlockchainTestsEnvironment`. + */ +export class BlockchainTestsEnvironmentSingleton { + private static _instance: BlockchainTestsEnvironmentSingleton | undefined; public blockchainLifecycle: BlockchainLifecycle; public provider: Web3ProviderEngine; @@ -46,16 +61,16 @@ export class BlockchainTestsEnvironment { public web3Wrapper: Web3Wrapper; // Create or retrieve the singleton instance of this class. - public static create(): BlockchainTestsEnvironment { - if (BlockchainTestsEnvironment._instance === undefined) { - BlockchainTestsEnvironment._instance = new BlockchainTestsEnvironment(); + public static create(): BlockchainTestsEnvironmentSingleton { + if (BlockchainTestsEnvironmentSingleton._instance === undefined) { + BlockchainTestsEnvironmentSingleton._instance = new BlockchainTestsEnvironmentSingleton(); } - return BlockchainTestsEnvironment._instance; + return BlockchainTestsEnvironmentSingleton._instance; } // Get the singleton instance of this class. - public static getInstance(): BlockchainTestsEnvironment | undefined { - return BlockchainTestsEnvironment._instance; + public static getInstance(): BlockchainTestsEnvironmentSingleton | undefined { + return BlockchainTestsEnvironmentSingleton._instance; } public async getChainIdAsync(): Promise { @@ -74,99 +89,99 @@ export class BlockchainTestsEnvironment { } } +// The original `describe()` global provided by mocha. +const mochaDescribe = (global as any).describe as Mocha.IContextDefinition; + +/** + * An augmented version of Mocha's `describe()`. + */ +export const describe = _.assign(mochaDescribe, { + optional(description: string, callback: SuiteCallback): ISuite | void { + const describeCall = process.env.TEST_ALL ? mochaDescribe : mochaDescribe.skip; + return describeCall(description, callback); + }, +}) as ContextDefinition; + +/** + * Like mocha's `describe()`, but sets up a blockchain environment on first call. + */ +export const blockchainTests: BlockchainContextDefinition = _.assign( + function(description: string, callback: BlockchainSuiteCallback): ISuite { + return defineBlockchainSuite(description, callback, describe); + }, + { + only(description: string, callback: BlockchainSuiteCallback): ISuite { + return defineBlockchainSuite(description, callback, describe.only); + }, + skip(description: string, callback: BlockchainSuiteCallback): void { + return defineBlockchainSuite(description, callback, describe.skip); + }, + optional(description: string, callback: BlockchainSuiteCallback): ISuite | void { + return defineBlockchainSuite(description, callback, process.env.TEST_ALL ? describe : describe.skip); + }, + resets: _.assign( + function(description: string, callback: BlockchainSuiteCallback): ISuite { + return defineBlockchainSuite(description, callback, function( + _description: string, + _callback: SuiteCallback, + ): ISuite { + return defineResetsSuite(_description, _callback, describe); + }); + }, + { + only(description: string, callback: BlockchainSuiteCallback): ISuite { + return defineBlockchainSuite(description, callback, function( + _description: string, + _callback: SuiteCallback, + ): ISuite { + return defineResetsSuite(_description, _callback, describe.only); + }); + }, + skip(description: string, callback: BlockchainSuiteCallback): void { + return defineBlockchainSuite(description, callback, function( + _description: string, + _callback: SuiteCallback, + ): void { + return defineResetsSuite(_description, _callback, describe.skip); + }); + }, + optional(description: string, callback: BlockchainSuiteCallback): ISuite | void { + return defineBlockchainSuite(description, callback, function( + _description: string, + _callback: SuiteCallback, + ): ISuite | void { + return defineResetsSuite(_description, _callback, describe.optional); + }); + }, + }, + ), + }, +) as BlockchainContextDefinition; + function defineBlockchainSuite( description: string, - callback: Mocha.BlockchainSuiteCallback, - describeCall: Mocha.ContextDefinitionCallback, + callback: BlockchainSuiteCallback, + describeCall: ContextDefinitionCallback, ): T { - const env = BlockchainTestsEnvironment.create(); - return describeCall(description, function(this: Mocha.ISuiteCallbackContext): void { - before( - async (): Promise => { - return env.blockchainLifecycle.startAsync(); - }, - ); - before( - async (): Promise => { - return env.blockchainLifecycle.revertAsync(); - }, - ); + const env = BlockchainTestsEnvironmentSingleton.create(); + return describeCall(description, function(this: ISuiteCallbackContext): void { + before(async () => env.blockchainLifecycle.startAsync()); + before(async () => env.blockchainLifecycle.revertAsync()); callback.call(this, env); }); } function defineResetsSuite( description: string, - callback: Mocha.SuiteCallback, - describeCall: Mocha.ContextDefinitionCallback, + callback: SuiteCallback, + describeCall: ContextDefinitionCallback, ): T { - return describeCall(description, function(this: Mocha.ISuiteCallbackContext): void { - const env = BlockchainTestsEnvironment.getInstance(); + return describeCall(description, function(this: ISuiteCallbackContext): void { + const env = BlockchainTestsEnvironmentSingleton.getInstance(); if (env !== undefined) { - beforeEach(async () => { - return env.blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - return env.blockchainLifecycle.revertAsync(); - }); + beforeEach(async () => env.blockchainLifecycle.startAsync()); + afterEach(async () => env.blockchainLifecycle.revertAsync()); } callback.call(this); }); } - -/** - * Like mocha's `describe()`, but sets up a BlockchainLifecycle and Web3Wrapper. - */ -export const blockchainTests: Mocha.BlockchainContextDefinition = _.assign( - function(description: string, callback: Mocha.BlockchainSuiteCallback): Mocha.ISuite { - return defineBlockchainSuite(description, callback, describe); - }, - { - only(description: string, callback: Mocha.BlockchainSuiteCallback): Mocha.ISuite { - return defineBlockchainSuite(description, callback, describe.only); - }, - skip(description: string, callback: Mocha.BlockchainSuiteCallback): void { - return defineBlockchainSuite(description, callback, describe.skip); - }, - optional(description: string, callback: Mocha.BlockchainSuiteCallback): Mocha.ISuite | void { - return defineBlockchainSuite(description, callback, process.env.TEST_ALL ? describe : describe.skip); - }, - resets: _.assign( - function(description: string, callback: Mocha.BlockchainSuiteCallback): Mocha.ISuite { - return defineBlockchainSuite(description, callback, function( - _description: string, - _callback: Mocha.SuiteCallback, - ): Mocha.ISuite { - return defineResetsSuite(_description, _callback, describe); - }); - }, - { - only(description: string, callback: Mocha.BlockchainSuiteCallback): Mocha.ISuite { - return defineBlockchainSuite(description, callback, function( - _description: string, - _callback: Mocha.SuiteCallback, - ): Mocha.ISuite { - return defineResetsSuite(_description, _callback, describe.only); - }); - }, - skip(description: string, callback: Mocha.BlockchainSuiteCallback): void { - return defineBlockchainSuite(description, callback, function( - _description: string, - _callback: Mocha.SuiteCallback, - ): void { - return defineResetsSuite(_description, _callback, describe.skip); - }); - }, - optional(description: string, callback: Mocha.BlockchainSuiteCallback): Mocha.ISuite | void { - const describeCall = process.env.TEST_ALL ? describe : describe.skip; - return defineBlockchainSuite(description, callback, function( - _description: string, - _callback: Mocha.SuiteCallback, - ): Mocha.ISuite | void { - return defineResetsSuite(_description, _callback, describeCall); - }); - }, - }, - ), - }, -) as Mocha.BlockchainContextDefinition; diff --git a/contracts/test-utils/test/mocha_blockchain.ts b/contracts/test-utils/test/mocha_blockchain.ts index e4c2f35038..bf21bbe41d 100644 --- a/contracts/test-utils/test/mocha_blockchain.ts +++ b/contracts/test-utils/test/mocha_blockchain.ts @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as process from 'process'; -import { blockchainTests, constants, expect } from '../src'; +import { blockchainTests, constants, describe, expect } from '../src'; blockchainTests('mocha blockchain extensions', env => { describe('blockchainTests()', () => { @@ -79,6 +79,16 @@ blockchainTests('mocha blockchain extensions', env => { require('./subtests/mocha_blockchain_1').append(env); }); }); + + describe('describe extensions', () => { + describe('modifiers', () => { + describe.optional('optional', () => { + it('only runs this with `TEST_ALL` environment flag set', () => { + expect(process.env.TEST_ALL).to.be.ok(''); + }); + }); + }); + }); }); function createHookedObject(obj: any, handler: (name: string) => void, methods: string[]): any {