CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-openzeppelin--test-helpers

JavaScript testing helpers for Ethereum smart contract development with assertions, event verification, balance tracking, and time manipulation.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

time-manipulation.mddocs/

Time Manipulation

Blockchain time and block manipulation utilities for testing time-dependent contract behavior in development networks. Essential for testing time locks, vesting schedules, and other temporal smart contract logic.

Capabilities

Block Advancement

Mine new blocks to advance the blockchain state.

/**
 * Mine one block on the blockchain
 * @returns {Promise<void>}
 */
function time.advanceBlock();

/**
 * Advance blockchain to a specific block number
 * @param {BN|number|string} target - Target block number
 * @returns {Promise<void>}
 */
async function time.advanceBlockTo(target);

Usage Examples:

const { time, BN } = require('@openzeppelin/test-helpers');

// Mine a single block
await time.advanceBlock();

// Advance to specific block (careful with large jumps!)
const targetBlock = await time.latestBlock().add(new BN('10'));
await time.advanceBlockTo(targetBlock);

Time Queries

Get current blockchain time and block information.

/**
 * Get the timestamp of the latest block in seconds
 * @returns {Promise<BN>} - Block timestamp as BigNumber
 */
async function time.latest();

/**
 * Get the latest block number
 * @returns {Promise<BN>} - Block number as BigNumber
 */
async function time.latestBlock();

Usage Examples:

// Get current block timestamp
const now = await time.latest();
console.log('Current time:', now.toString());

// Get current block number
const blockNumber = await time.latestBlock();
console.log('Current block:', blockNumber.toString());

// Compare timestamps
const deadline = now.add(time.duration.days(7));
expect(deadline).to.be.bignumber.greaterThan(now);

Time Advancement

Manipulate blockchain time for testing time-dependent functionality.

/**
 * Increase blockchain time by a specific duration
 * @param {BN|number|string} duration - Duration in seconds to increase
 * @returns {Promise<void>}
 */
async function time.increase(duration);

/**
 * Increase blockchain time to a specific target timestamp
 * @param {BN|number|string} target - Target timestamp in seconds
 * @returns {Promise<void>}
 */
async function time.increaseTo(target);

Usage Examples:

const { time } = require('@openzeppelin/test-helpers');

// Increase time by 1 hour
await time.increase(time.duration.hours(1));

// Jump to specific future time
const futureTime = (await time.latest()).add(time.duration.days(30));
await time.increaseTo(futureTime);

// Test time-locked function
it('should allow withdrawal after lock period', async function () {
  // Lock funds for 1 week
  await this.contract.lockFunds({ from: user });
  
  // Try to withdraw immediately (should fail)
  await expectRevert(
    this.contract.withdraw({ from: user }),
    'Funds are still locked'
  );
  
  // Advance time by 1 week
  await time.increase(time.duration.weeks(1));
  
  // Now withdrawal should succeed
  await this.contract.withdraw({ from: user });
});

Duration Utilities

Convenient time duration conversion utilities.

const time.duration = {
  /**
   * Convert seconds to BigNumber
   * @param {number|string} val - Value in seconds
   * @returns {BN} - Duration as BigNumber
   */
  seconds: (val) => BN,
  
  /**
   * Convert minutes to seconds as BigNumber
   * @param {number|string} val - Value in minutes
   * @returns {BN} - Duration in seconds as BigNumber
   */
  minutes: (val) => BN,
  
  /**
   * Convert hours to seconds as BigNumber
   * @param {number|string} val - Value in hours
   * @returns {BN} - Duration in seconds as BigNumber
   */
  hours: (val) => BN,
  
  /**
   * Convert days to seconds as BigNumber
   * @param {number|string} val - Value in days
   * @returns {BN} - Duration in seconds as BigNumber
   */
  days: (val) => BN,
  
  /**
   * Convert weeks to seconds as BigNumber
   * @param {number|string} val - Value in weeks
   * @returns {BN} - Duration in seconds as BigNumber
   */
  weeks: (val) => BN,
  
  /**
   * Convert years to seconds as BigNumber (365 days)
   * @param {number|string} val - Value in years
   * @returns {BN} - Duration in seconds as BigNumber
   */
  years: (val) => BN,
};

Usage Examples:

// Duration calculations
const oneHour = time.duration.hours(1);
const oneDay = time.duration.days(1);
const oneWeek = time.duration.weeks(1);
const oneYear = time.duration.years(1);

console.log('1 hour =', oneHour.toString(), 'seconds');
console.log('1 day =', oneDay.toString(), 'seconds');
console.log('1 week =', oneWeek.toString(), 'seconds');
console.log('1 year =', oneYear.toString(), 'seconds');

// Combining durations
const lockPeriod = time.duration.days(30).add(time.duration.hours(12));
await time.increase(lockPeriod);

Comprehensive Testing Example

const { time, expectRevert, BN } = require('@openzeppelin/test-helpers');

contract('TimeLock', function ([owner, beneficiary]) {
  beforeEach(async function () {
    this.lockDuration = time.duration.days(30);
    this.releaseTime = (await time.latest()).add(this.lockDuration);
    
    this.timeLock = await TimeLock.new(
      beneficiary,
      this.releaseTime,
      { from: owner }
    );
  });

  it('should not allow release before time', async function () {
    await expectRevert(
      this.timeLock.release(),
      'TimeLock: current time is before release time'
    );
  });

  it('should allow release after time', async function () {
    // Fast forward to release time
    await time.increaseTo(this.releaseTime);
    
    // Should now be able to release
    await this.timeLock.release();
  });

  it('should handle gradual vesting', async function () {
    const vestingStart = await time.latest();
    const vestingDuration = time.duration.days(100);
    
    // Check vesting at different points
    await time.increaseTo(vestingStart.add(time.duration.days(25)));
    let vestedAmount = await this.vestingContract.vestedAmount(beneficiary);
    expect(vestedAmount).to.be.bignumber.equal(new BN('25')); // 25% vested
    
    await time.increaseTo(vestingStart.add(time.duration.days(50)));
    vestedAmount = await this.vestingContract.vestedAmount(beneficiary);
    expect(vestedAmount).to.be.bignumber.equal(new BN('50')); // 50% vested
    
    await time.increaseTo(vestingStart.add(vestingDuration));
    vestedAmount = await this.vestingContract.vestedAmount(beneficiary);
    expect(vestedAmount).to.be.bignumber.equal(new BN('100')); // 100% vested
  });
});

Important Notes

Performance Warning

The advanceBlockTo function will show a warning when advancing many blocks (5+ seconds), as this can slow down tests significantly.

Precision Limitations

Time manipulation is subject to blockchain precision limitations. Design tests to tolerate small time fluctuations when using increaseTo.

Provider Compatibility

Time manipulation requires a development blockchain that supports:

  • evm_increaseTime RPC method
  • evm_mine RPC method

Compatible with:

  • Ganache
  • Hardhat Network
  • Truffle Develop

Block vs Time

Remember that advancing time also mines a block. Some contracts may depend on block numbers rather than timestamps.

// Advance time without mining extra blocks
await time.increase(time.duration.hours(1));

// This will mine one additional block after time increase
// Current block number = previous + 1

Install with Tessl CLI

npx tessl i tessl/npm-openzeppelin--test-helpers

docs

advanced-features.md

balance-tracking.md

constants-utilities.md

event-testing.md

index.md

revert-testing.md

time-manipulation.md

tile.json