Skip to content
This repository has been archived by the owner on Nov 5, 2024. It is now read-only.

Commit

Permalink
Add getTimestampOffset/setTimestampOffset utilities (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
refi93 authored Jul 7, 2022
1 parent 268f825 commit 3fc34f3
Show file tree
Hide file tree
Showing 30 changed files with 571 additions and 227 deletions.
5 changes: 5 additions & 0 deletions .changeset/long-hairs-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@onflow/flow-js-testing": minor
---

Add getTimeOffset/setTimeOffset utilities, allowing to advance the time while testing smart-contracts
13 changes: 13 additions & 0 deletions cadence/contracts/FlowManager.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub contract FlowManager {

/// Environment Manager
pub event BlockOffsetChanged(offset: UInt64)
pub event TimestampOffsetChanged(offset: UFix64)

pub struct MockBlock {
pub let id: [UInt8; 32]
Expand All @@ -62,24 +63,36 @@ pub contract FlowManager {
emit FlowManager.BlockOffsetChanged(offset: offset)
}

pub fun setTimestampOffset(_ offset: UFix64){
self.timestampOffset = offset
emit FlowManager.TimestampOffsetChanged(offset: offset)
}

pub fun getBlockHeight(): UInt64 {
var block = getCurrentBlock()
return block.height + self.blockOffset
}

pub fun getBlockTimestamp(): UFix64 {
var block = getCurrentBlock()
return block.timestamp + self.timestampOffset
}

pub fun getBlock(): MockBlock {
var block = getCurrentBlock()
let mockBlock = MockBlock(block.id, block.height, block.view, block.timestamp);
return mockBlock
}

pub var blockOffset: UInt64;
pub var timestampOffset: UFix64;


// Initialize contract
init(){
// Environment defaults
self.blockOffset = 0;
self.timestampOffset = 0.0;

// Account Manager initialization
let accountManager = Mapper()
Expand Down
5 changes: 5 additions & 0 deletions cadence/scripts/get-timestamp-offset.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import FlowManager from 0x01

pub fun main():UFix64 {
return FlowManager.timestampOffset
}
7 changes: 7 additions & 0 deletions cadence/transactions/set-timestamp-offset.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import FlowManager from 0x01

transaction(offset: UFix64){
prepare(signer:AuthAccount){
FlowManager.setTimestampOffset(offset)
}
}
10 changes: 10 additions & 0 deletions dev-test/cadence/scripts/read-mocked-timestamp-offset.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import FlowManager from 0x01

pub fun main(): UFix64 {
let mockedTimestamp = FlowManager.getBlockTimestamp();
let realTimestamp = getCurrentBlock().timestamp;
log("Mocked Height: ".concat(mockedTimestamp.toString()))
log("Real Height: ".concat(realTimestamp.toString()))

return mockedTimestamp - realTimestamp;
}
96 changes: 96 additions & 0 deletions dev-test/utilities.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
sendTransaction,
getBlockOffset,
setBlockOffset,
getTimestampOffset,
setTimestampOffset,
} from "../src";
import { extractParameters } from "../src/interaction";
import { importExists, builtInMethods, playgroundImport } from "../src/transformers";
Expand Down Expand Up @@ -111,6 +113,100 @@ describe("block height offset utilities", () => {
});
});

describe("timestamp offset", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const base = path.resolve(__dirname, "../cadence");
const port = 8085;
await init({ base },);
return emulator.start(port);
});

// Stop emulator, so it could be restarted
afterEach(async () => {
return emulator.stop();
});

it("should return zero offset", async () => {
const [zeroOffset] = await executeScript("get-timestamp-offset");
expect(zeroOffset).toBe("0.00000000");
});

it("should update offset", async () => {
const manager = await getServiceAddress();
const [zeroOffset] = await executeScript("get-timestamp-offset");
expect(zeroOffset).toBe("0.00000000");

const offset = 42;
await shallPass(sendTransaction("set-timestamp-offset", [manager], [offset]));
const [newOffset] = await executeScript("get-timestamp-offset");
expect(newOffset).toBe("42.00000000");
});

it("should read offset with utility method", async () => {
// CadUt version of sending transactions and execution scripts don't have
// import resolver built in, so we need to provide addressMap to it
const FlowManager = await getManagerAddress();
const addressMap = { FlowManager };

const [offSet] = await getTimestampOffset({ addressMap });

expect(offSet).toBe(0);

});

it("should update offset with utility method", async () => {
// CadUt version of sending transactions and execution scripts don't have
// import resolver built in, so we need to provide addressMap to it
const FlowManager = await getManagerAddress();
const addressMap = { FlowManager };

const [oldOffset] = await getTimestampOffset({ addressMap });

expect(oldOffset).toBe(0);

const offset = 42;

const [txResult] = await setTimestampOffset(offset);
expect(txResult.errorMessage).toBe("");

const [newOffset] = await getTimestampOffset({ addressMap });

expect(newOffset).toBe(offset);
});
});

describe("timestamp offset utilities", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const base = path.resolve(__dirname, "../cadence");
const port = 8080;
await init({ base }, { port });
return emulator.start(port);
});

// Stop emulator, so it could be restarted
afterEach(async () => {
return emulator.stop();
});

it("should return 0 for initial block offset", async () => {
const [initialOffset] = await shallResolve(manager.getTimestampOffset());
expect(initialOffset).toBe(0);
});

it("should update block offset", async () => {
const [offset] = await shallResolve(manager.getTimestampOffset());
expect(offset).toBe(0);

const blockOffset = 42;
await shallPass(manager.setTimestampOffset(blockOffset));

const [newOffset] = await shallResolve(manager.getTimestampOffset());
expect(newOffset).toBe(blockOffset);
});
});

describe("dev tests", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
Expand Down
97 changes: 97 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ import {
emulator,
executeScript,
getBlockOffset,
setBlockOffset,
builtInMethods,
sendTransaction,
} from "flow-js-testing";
Expand Down Expand Up @@ -579,6 +580,102 @@ const main = async () => {
main();
```

### `getTimestampOffset()`

Returns current timestamp offset - amount of seconds added on top of real current timestamp.

#### Returns

| Type | Description |
| ------ | ---------------------------------------------------------------------------- |
| number | number representing amount of seconds added on top of real current timestamp |

#### Usage

```javascript
import path from "path";
import { init, emulator, getTimestampOffset } from "flow-js-testing";

const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
const port = 8080;

init(basePath, port);
await emulator.start(port);

const [timestampOffset, err] = await getTimestampOffset();
console.log({ timestampOffset }, { err });

await emulator.stop();
};

main();
```

> ⚠️ **Required:** In order for this method to work, you will need to pass code transformer to your interaction.
> Framework exposes `builtInMethods` transformer to mock built in methods
### `setTimestampOffset(offset)`

Returns current timestamp offset - amount of seconds added on top of real current timestamp.

#### Arguments

| Name | Type | Description |
| ---- | ---- | ----------- |

#### Returns

| Type | Description |
| ------ | ---------------------------------------------------------------------------- |
| number | number representing amount of seconds added on top of real current timestamp |

#### Usage

```javascript
import path from "path";
import {
init,
emulator,
executeScript,
getTimestampOffset,
setTimestampOffset,
builtInMethods,
sendTransaction,
} from "flow-js-testing";

const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
const port = 8080;

init(basePath, port);
await emulator.start(port);

// Offset current timestamp by 10s
await setTimestampOffset(10);

const [timestampOffset, err] = await getTimestampOffset();
console.log({ timestampOffset }, { err });

// "getCurrentBlock().timestamp" in your Cadence code will be replaced by Manager to a mocked value
const code = `
pub fun main(): UInt64 {
return getCurrentBlock().timestamp
}
`;

// "transformers" field expects array of functions to operate update the code.
// We will pass single operator "builtInMethods" provided by the framework
const transformers = [builtInMethods];
const [result, error] = await executeScript({ code, transformers });
console.log({ result }, { error });

await emulator.stop();
};

main();
```

## Jest Helpers

In order to simplify the process even further we've created several Jest-based methods, which will help you to catch
Expand Down
Loading

0 comments on commit 3fc34f3

Please sign in to comment.