From aada873cf845f4e0ac1b6231af7f0de651036667 Mon Sep 17 00:00:00 2001 From: Jiexi Luan Date: Fri, 23 Jun 2023 11:59:01 -0700 Subject: [PATCH] Dry specs into loop --- src/PollingBlockTracker.test.ts | 404 +++++++++++------------------- src/SubscribeBlockTracker.test.ts | 37 +-- tests/buildScenarios.ts | 53 ++++ 3 files changed, 222 insertions(+), 272 deletions(-) create mode 100644 tests/buildScenarios.ts diff --git a/src/PollingBlockTracker.test.ts b/src/PollingBlockTracker.test.ts index de33e298..0402fb8c 100644 --- a/src/PollingBlockTracker.test.ts +++ b/src/PollingBlockTracker.test.ts @@ -2,6 +2,7 @@ import EMPTY_FUNCTION from '../tests/emptyFunction'; import recordCallsToSetTimeout from '../tests/recordCallsToSetTimeout'; import { withPollingBlockTracker } from '../tests/withBlockTracker'; import buildDeferred from '../tests/buildDeferred'; +import { buildBlockNumberCachedScenarios } from '../tests/buildScenarios'; import { PollingBlockTracker } from '.'; interface Sync { @@ -835,261 +836,148 @@ describe('PollingBlockTracker', () => { ); }); - describe('after a block number is cached', () => { - it('should return the fetched block number if the fetched block number is greater than the current block number', async () => { - recordCallsToSetTimeout(); - - await withPollingBlockTracker( - { - provider: { - stubs: [ - { - methodName: 'eth_blockNumber', - response: { - result: '0x0', - }, - }, - { - methodName: 'eth_blockNumber', - response: { - result: '0x1', - }, - }, - ], + describe.each([ + { + description: 'no options', + options: {}, + gt: { + returnDescription: 'fetched', + updateDescription: 'should', + result: '0x1', + }, + lt: { + returnDescription: 'current', + updateDescription: 'should not', + result: '0x1', + }, + eq: { + returnDescription: 'current', + updateDescription: 'should not', + result: '0x0', + }, + }, + { + description: '`usePastBlocks: false`', + options: { usePastBlocks: false }, + gt: { + returnDescription: 'fetched', + updateDescription: 'should', + result: '0x1', + }, + lt: { + returnDescription: 'current', + updateDescription: 'should not', + result: '0x1', + }, + eq: { + returnDescription: 'current', + updateDescription: 'should not', + result: '0x0', + }, + }, + { + description: '`usePastBlocks: true`', + options: { usePastBlocks: true }, + gt: { + returnDescription: 'fetched', + updateDescription: 'should', + result: '0x1', + }, + lt: { + returnDescription: 'fetched', + updateDescription: 'should', + result: '0x0', + }, + eq: { + returnDescription: 'current', + updateDescription: 'should not', + result: '0x0', + }, + }, + ] as const)( + 'after a block number is cached if the block tracker was initialized with $description', + ({ options, gt, lt, eq }) => { + it.each( + buildBlockNumberCachedScenarios({ + gt: { + ...gt, + description: gt.returnDescription, }, - }, - async ({ blockTracker }) => { - const blockNumber1 = await blockTracker.checkForLatestBlock(); - expect(blockNumber1).toStrictEqual('0x0'); - const blockNumber2 = await blockTracker.checkForLatestBlock(); - expect(blockNumber2).toStrictEqual('0x1'); - }, - ); - }); - - it('should update the current block number if the fetched block number is greater than the current block number', async () => { - recordCallsToSetTimeout(); - - await withPollingBlockTracker( - { - provider: { - stubs: [ - { - methodName: 'eth_blockNumber', - response: { - result: '0x0', - }, - }, - { - methodName: 'eth_blockNumber', - response: { - result: '0x1', - }, - }, - ], + lt: { + ...lt, + description: lt.returnDescription, }, - }, - async ({ blockTracker }) => { - await blockTracker.checkForLatestBlock(); - await blockTracker.checkForLatestBlock(); - const currentBlockNumber = blockTracker.getCurrentBlock(); - expect(currentBlockNumber).toStrictEqual('0x1'); - }, - ); - }); - - it('should return the current block number if the fetched block number is less than the current block number', async () => { - recordCallsToSetTimeout(); - - await withPollingBlockTracker( - { - provider: { - stubs: [ - { - methodName: 'eth_blockNumber', - response: { - result: '0x1', - }, - }, - { - methodName: 'eth_blockNumber', - response: { - result: '0x0', - }, - }, - ], + eq: { + ...eq, + description: eq.returnDescription, }, - }, - async ({ blockTracker }) => { - const blockNumber1 = await blockTracker.checkForLatestBlock(); - expect(blockNumber1).toStrictEqual('0x1'); - const blockNumber2 = await blockTracker.checkForLatestBlock(); - expect(blockNumber2).toStrictEqual('0x1'); - }, - ); - }); + }), + )( + 'should return the $description block number if $scenario', + async ({ blockNumbers, result }) => { + recordCallsToSetTimeout(); - it('should not update the current block number if the fetched block number is less than the current block number', async () => { - recordCallsToSetTimeout(); - - await withPollingBlockTracker( - { - provider: { - stubs: [ - { - methodName: 'eth_blockNumber', - response: { - result: '0x1', - }, - }, - { - methodName: 'eth_blockNumber', - response: { - result: '0x0', - }, + await withPollingBlockTracker( + { + provider: { + stubs: blockNumbers.map((blockNumber) => ({ + methodName: 'eth_blockNumber', + response: { result: blockNumber }, + })), }, - ], - }, - }, - async ({ blockTracker }) => { - await blockTracker.checkForLatestBlock(); - await blockTracker.checkForLatestBlock(); - const currentBlockNumber = blockTracker.getCurrentBlock(); - expect(currentBlockNumber).toStrictEqual('0x1'); + blockTracker: options, + }, + async ({ blockTracker }) => { + await blockTracker.checkForLatestBlock(); + const lastestBlockNumber = + await blockTracker.checkForLatestBlock(); + expect(lastestBlockNumber).toStrictEqual(result); + }, + ); }, ); - }); - }); - - describe('after a block number is cached if the block tracker was initialized with `usePastBlocks: true`', () => { - it('should return the fetched block number if the fetched block number is greater than the current block number', async () => { - recordCallsToSetTimeout(); - await withPollingBlockTracker( - { - provider: { - stubs: [ - { - methodName: 'eth_blockNumber', - response: { - result: '0x0', - }, - }, - { - methodName: 'eth_blockNumber', - response: { - result: '0x1', - }, - }, - ], + it.each( + buildBlockNumberCachedScenarios({ + gt: { + ...gt, + description: gt.updateDescription, }, - blockTracker: { usePastBlocks: true }, - }, - async ({ blockTracker }) => { - const blockNumber1 = await blockTracker.checkForLatestBlock(); - expect(blockNumber1).toStrictEqual('0x0'); - const blockNumber2 = await blockTracker.checkForLatestBlock(); - expect(blockNumber2).toStrictEqual('0x1'); - }, - ); - }); - - it('should update the current block number if the fetched block number is greater than the current block number', async () => { - recordCallsToSetTimeout(); - - await withPollingBlockTracker( - { - provider: { - stubs: [ - { - methodName: 'eth_blockNumber', - response: { - result: '0x0', - }, - }, - { - methodName: 'eth_blockNumber', - response: { - result: '0x1', - }, - }, - ], + lt: { + ...lt, + description: lt.updateDescription, }, - blockTracker: { usePastBlocks: true }, - }, - async ({ blockTracker }) => { - await blockTracker.checkForLatestBlock(); - await blockTracker.checkForLatestBlock(); - const currentBlockNumber = blockTracker.getCurrentBlock(); - expect(currentBlockNumber).toStrictEqual('0x1'); - }, - ); - }); - - it('should return the fetched block number if the fetched block number is less than the current block number', async () => { - recordCallsToSetTimeout(); - - await withPollingBlockTracker( - { - provider: { - stubs: [ - { - methodName: 'eth_blockNumber', - response: { - result: '0x1', - }, - }, - { - methodName: 'eth_blockNumber', - response: { - result: '0x0', - }, - }, - ], + eq: { + ...eq, + description: eq.updateDescription, }, - blockTracker: { usePastBlocks: true }, - }, - async ({ blockTracker }) => { - const blockNumber1 = await blockTracker.checkForLatestBlock(); - expect(blockNumber1).toStrictEqual('0x1'); - const blockNumber2 = await blockTracker.checkForLatestBlock(); - expect(blockNumber2).toStrictEqual('0x0'); - }, - ); - }); + }), + )( + '$description update the current block number if $scenario', + async ({ blockNumbers, result }) => { + recordCallsToSetTimeout(); - it('should update the current block number if the fetched block number is less than the current block number', async () => { - recordCallsToSetTimeout(); - - await withPollingBlockTracker( - { - provider: { - stubs: [ - { - methodName: 'eth_blockNumber', - response: { - result: '0x1', - }, - }, - { - methodName: 'eth_blockNumber', - response: { - result: '0x0', - }, + await withPollingBlockTracker( + { + provider: { + stubs: blockNumbers.map((blockNumber) => ({ + methodName: 'eth_blockNumber', + response: { result: blockNumber }, + })), }, - ], - }, - blockTracker: { usePastBlocks: true }, - }, - async ({ blockTracker }) => { - await blockTracker.checkForLatestBlock(); - await blockTracker.checkForLatestBlock(); - const currentBlockNumber = blockTracker.getCurrentBlock(); - expect(currentBlockNumber).toStrictEqual('0x0'); + blockTracker: options, + }, + async ({ blockTracker }) => { + await blockTracker.checkForLatestBlock(); + await blockTracker.checkForLatestBlock(); + const currentBlockNumber = blockTracker.getCurrentBlock(); + expect(currentBlockNumber).toStrictEqual(result); + }, + ); }, ); - }); - }); + }, + ); }); METHODS_TO_ADD_LISTENER.forEach((methodToAddListener) => { @@ -1629,16 +1517,18 @@ describe('PollingBlockTracker', () => { result: ['0x0'], }, }, - ] as const)( + ])( 'after a block number is cached if the block tracker was initialized with $description', ({ options, gt, lt, eq }) => { - it.each([ - [gt.description, 'greater than', ['0x0', '0x1'], gt.result], - [lt.description, 'less than', ['0x1', '0x0'], lt.result], - [eq.description, 'equal to', ['0x0', '0x0'], eq.result], - ] as const)( - '%s emit "latest" if the fetched blocked number is %s the current block number', - async (_, __, blockNumbers, result) => { + it.each( + buildBlockNumberCachedScenarios({ + gt, + lt, + eq, + }), + )( + '$description emit "latest" if $scenario', + async ({ blockNumbers, result }) => { const setTimeoutRecorder = recordCallsToSetTimeout({ numAutomaticCalls: 1, }); @@ -2198,16 +2088,18 @@ describe('PollingBlockTracker', () => { result: [{ oldBlock: null, newBlock: '0x0' }], }, }, - ] as const)( + ])( 'after a block number is cached if the block tracker was initialized with $description', ({ options, gt, lt, eq }) => { - it.each([ - [gt.description, 'greater than', ['0x0', '0x1'], gt.result], - [lt.description, 'less than', ['0x1', '0x0'], lt.result], - [eq.description, 'equal to', ['0x0', '0x0'], eq.result], - ] as const)( - '%s emit "sync" if the fetched blocked number is %s the current block number', - async (_, __, blockNumbers, result) => { + it.each( + buildBlockNumberCachedScenarios({ + gt, + lt, + eq, + }), + )( + '$description emit "sync" if $scenario', + async ({ blockNumbers, result }) => { const setTimeoutRecorder = recordCallsToSetTimeout({ numAutomaticCalls: 1, }); diff --git a/src/SubscribeBlockTracker.test.ts b/src/SubscribeBlockTracker.test.ts index a802a77f..fbf98cc4 100644 --- a/src/SubscribeBlockTracker.test.ts +++ b/src/SubscribeBlockTracker.test.ts @@ -2,6 +2,7 @@ import EMPTY_FUNCTION from '../tests/emptyFunction'; import recordCallsToSetTimeout from '../tests/recordCallsToSetTimeout'; import { withSubscribeBlockTracker } from '../tests/withBlockTracker'; import buildDeferred from '../tests/buildDeferred'; +import { buildBlockNumberCachedScenarios } from '../tests/buildScenarios'; import { SubscribeBlockTracker } from '.'; interface Sync { @@ -1199,16 +1200,18 @@ describe('SubscribeBlockTracker', () => { result: ['0x0'], }, }, - ] as const)( + ])( 'after a block number is cached if the block tracker was initialized with $description', ({ options, gt, lt, eq }) => { - it.each([ - [gt.description, 'greater than', ['0x0', '0x1'], gt.result], - [lt.description, 'less than', ['0x1', '0x0'], lt.result], - [eq.description, 'equal to', ['0x0', '0x0'], eq.result], - ] as const)( - '%s emit "latest" if the published blocked number is %s the current block number', - async (_, __, blockNumbers, result) => { + it.each( + buildBlockNumberCachedScenarios({ + gt, + lt, + eq, + }), + )( + '$description emit "latest" if $scenario', + async ({ blockNumbers, result }) => { recordCallsToSetTimeout(); await withSubscribeBlockTracker( @@ -1769,16 +1772,18 @@ describe('SubscribeBlockTracker', () => { result: [{ oldBlock: null, newBlock: '0x0' }], }, }, - ] as const)( + ])( 'after a block number is cached if the block tracker was initialized with $description', ({ options, gt, lt, eq }) => { - it.each([ - [gt.description, 'greater than', ['0x0', '0x1'], gt.result], - [lt.description, 'less than', ['0x1', '0x0'], lt.result], - [eq.description, 'equal to', ['0x0', '0x0'], eq.result], - ] as const)( - '%s emit "sync" if the published blocked number is %s the current block number', - async (_, __, blockNumbers, result) => { + it.each( + buildBlockNumberCachedScenarios({ + gt, + lt, + eq, + }), + )( + '$description emit "sync" if $scenario', + async ({ blockNumbers, result }) => { recordCallsToSetTimeout(); await withSubscribeBlockTracker( diff --git a/tests/buildScenarios.ts b/tests/buildScenarios.ts new file mode 100644 index 00000000..74787916 --- /dev/null +++ b/tests/buildScenarios.ts @@ -0,0 +1,53 @@ +interface BlockNumberCachedOption { + description: string; + result: T; +} + +interface BlockNumberCachedOptions { + gt: BlockNumberCachedOption; + lt: BlockNumberCachedOption; + eq: BlockNumberCachedOption; +} + +interface BlockNumberCachedScenario { + description: string; + result: T; + scenario: string; + blockNumbers: string[]; +} + +/** + * Builds arguments to use in loops that cover test + * cases where an existing block number in cache and a new + * block number number is being processed. + * + * @param options - The options. + * @param options.gt - The option for the 'greater than' scenario. + * @param options.lt - The option for the 'less than' scenario. + * @param options.eq - The option for the 'equal to' scenario. + * @returns Array of objects to be used in test loops. + */ +export const buildBlockNumberCachedScenarios = ( + options: BlockNumberCachedOptions, +): BlockNumberCachedScenario[] => { + return [ + { + ...options.gt, + scenario: + 'the received block number is greater than the current block number', + blockNumbers: ['0x0', '0x1'], + }, + { + ...options.lt, + scenario: + 'the received block number is less than the current block number', + blockNumbers: ['0x1', '0x0'], + }, + { + ...options.eq, + scenario: + 'the received block number is equal to the current block number', + blockNumbers: ['0x0', '0x0'], + }, + ]; +};