JS Testing API Reference
⚠️ Required: Your project must follow the required structure and it must be initialized to use the following functions.
Accounts
getAccountAddress
Resolves name alias to a Flow address (0x prefixed) under the following conditions:
- If an account with a specific name has not been previously accessed, the framework will create a new one and then store it under the provided alias.
- Next time when you call this method, it will grab exactly the same account. This allows you to create several accounts up-front and then use them throughout your code, without worrying that accounts match or trying to store and manage specific addresses.
Arguments
| Name | Type | Description | 
|---|---|---|
| alias | string | The alias to reference or create. | 
Returns
| Type | Description | 
|---|---|
| Address | 0xprefixed address of aliased account | 
Usage
_10import {getAccountAddress} from "@onflow/flow-js-testing"_10_10const main = async () => {_10  const Alice = await getAccountAddress("Alice")_10  console.log({Alice})_10}_10_10main()
createAccount({name, keys})
In some cases, you may wish to manually create an account with a particular set of private keys
Options
Pass in the following as a single object with the following keys.
| Key | Type | Required | Description | 
|---|---|---|---|
| name | string | No | human-readable name to be associated with created account (will be used for address lookup within getAccountAddress) | 
| keys | [KeyObject or PublicKey] | No | An array of KeyObjects or PublicKeys to be added to the account upon creation (defaults to the universal private key) | 
📣 if
namefield not provided, the account address will not be cached and you will be unable to look it up usinggetAccountAddress.
Returns
| Type | Description | 
|---|---|
| Address | 0xprefixed address of created account | 
Contracts
deployContractByName(props)
Deploys contract code located inside a Cadence file. Returns the transaction result.
Arguments
Props object accepts the following fields:
| Name | Type | Optional | Description | 
|---|---|---|---|
| name | string | name of the file in contractsfolder (with.cdcextension) and name of the contract (please note those should be the same) | |
| to | Address | ✅ | (optional) account address, where contract will be deployed. If this is not specified, framework will create new account with randomized alias. | 
| addressMap | AddressMap | ✅ | (optional) object to use for address mapping of existing deployed contracts | 
| args | [Any] | ✅ | (optional) arguments, which will be passed to contract initializer. (optional) if template does not expect any arguments. | 
| update | boolean | ✅ | (optional) whether to update deployed contract. Default: false | 
| transformers | [CadenceTransformer] | ✅ | (optional) an array of operators to modify the code, before submitting it to network | 
Returns
| Type | Description | 
|---|---|
| ResponseObject | Result of the deploying transaction. | 
Usage
_27import path from "path";_27import { init, emulator, deployContractByName } from "@onflow/flow-js-testing";_27_27const main = async () => {_27  const basePath = path.resolve(__dirname, "../cadence");_27_27  await init(basePath);_27  await emulator.start();_27_27  // We will deploy our contract to the address that corresponds to "Alice" alias_27  const to = await getAccountAddress("Alice");_27_27  // We assume there is a file on "../cadence/contracts/Wallet.cdc" path_27  const name = "Wallet";_27_27  // Arguments will be processed and type matched in the same order as they are specified_27  // inside of a contract template_27  const args = [1337, "Hello", { name: "Alice" }];_27_27  const [deploymentResult, err] = await deployContractByName({ to, name });_27  console.log({ deploymentResult }, { err });_27  }_27_27  await emulator.stop();_27};_27_27main();
In a bit more rare case you would want to deploy contract code not from existing template file, but rather
from string representation of it. deployContract method will help you achieve this.
deployContract(props)
Deploys contract code specified as string. Returns the transaction result.
Arguments
Props object accepts the following fields:
| Name | Type | Optional | Description | 
|---|---|---|---|
| contractCode | string | string representation of contract | |
| name | string | name of the contract to be deployed. Should be the same as the name of the contract provided in contractCode | |
| to | Address | ✅ | account address, where contract will be deployed. If this is not specified, framework will create new account with randomized alias. | 
| addressMap | AddressMap | ✅ | object to use for import resolver. Default: {} | 
| args | [Any] | ✅ | arguments, which will be passed to contract initializer. Default: [] | 
| update | boolean | ✅ | whether to update deployed contract. Default: false | 
| transformers | [CadenceTransformer] | ✅ | an array of operators to modify the code, before submitting it to network | 
Returns
| Type | Description | 
|---|---|
| ResponseObject | Result of the deploying transaction. | 
Usage
_42import path from "path"_42import {_42  init,_42  emulator,_42  getAccountAddress,_42  deployContract,_42  executeScript,_42} from "@onflow/flow-js-testing"_42;(async () => {_42  const basePath = path.resolve(__dirname, "../cadence")_42_42  await init(basePath)_42  await emulator.start()_42_42  // We can specify, which account will hold the contract_42  const to = await getAccountAddress("Alice")_42_42  const name = "Wallet"_42  const code = `_42        access(all) contract Wallet{_42            access(all) let balance: UInt_42            init(balance: UInt){_42              self.balance = balance_42            }_42        }_42    `_42  const args = [1337]_42_42  await deployContract({to, name, code, args})_42_42  const [balance, err] = await executeScript({_42    code: `_42      import Wallet from 0x01_42      access(all) fun main(): UInt{_42        return Wallet.balance_42      }_42    `,_42  })_42  console.log({balance}, {err})_42_42  await emulator.stop()_42})()
While framework have automatic import resolver for Contracts you might want to know where it's currently deployed.
We provide a method getContractAddress for this.
getContractAddress(name)
Returns address of the account where the contract is currently deployed.
Arguments
| Name | Type | Description | 
|---|---|---|
| name | string | name of the contract | 
Returns
| Type | Description | 
|---|---|
| Address | 0xprefixed address | 
Usage
_17import path from "path"_17import {init, emulator, deployContractByName, getContractAddress} from "../src"_17;(async () => {_17  const basePath = path.resolve(__dirname, "./cadence")_17_17  await init(basePath)_17  await emulator.start()_17_17  // if we omit "to" it will be deployed to Service Account_17  // but let's pretend we don't know where it will be deployed :)_17  await deployContractByName({name: "Hello"})_17_17  const contractAddress = await getContractAddress("Hello")_17  console.log({contractAddress})_17_17  await emulator.stop()_17})()
📣 Framework does not support contracts with identical names deployed to different accounts. While you can deploy contract to a new address, the internal system, which tracks where contracts are deployed, will only store last address.
Cryptography
pubFlowKey(keyObject)
The pubFlowKey method exported by Flow JS Testing Library will generate an RLP-encoded public key given a private key, hashing algorithm, signing algorithm, and key weight.
| Name | Type | Optional | Description | 
|---|---|---|---|
| keyObject | KeyObject | ✅ | an object containing a private key & the key's hashing/signing information | 
If keyObject is not provided, Flow JS Testing will default to the universal private key.
Returns
| Type | Description | 
|---|---|
| Buffer | RLP-encoded public key | 
Usage
_11import {pubFlowKey} from "@onflow/flow-js-testing"_11_11const key = {_11  privateKey: "a1b2c3", // private key as hex string_11  hashAlgorithm: HashAlgorithm.SHA3_256,_11  signatureAlgorithm: SignatureAlgorithm.ECDSA_P256,_11  weight: 1000,_11}_11_11const pubKey = await pubFlowKey(key) // public key generated from keyObject provided_11const genericPubKey = await pubFlowKey() // public key generated from universal private key/service key
signUserMessage(msgHex, signer, domainTag)
The signUserMessage method will produce a user signature of some arbitrary data using a particular signer.
Arguments
| Name | Type | Optional | Description | 
|---|---|---|---|
| msgHex | string or Buffer | a hex-encoded string or Buffer which will be used to generate the signature | |
| signer | Address or SignerInfo | ✅ | Address or SignerInfo object representing user to generate this signature for (default: universal private key) | 
| domainTag | string | ✅ | Domain separation tag provided as a utf-8 encoded string (default: no domain separation tag). See more about domain tags here. | 
Returns
| Type | Description | 
|---|---|
| SignatureObject | An object representing the signature for the message & account/keyId which signed for this message | 
Usage
_10import {signUserMessage, getAccountAddress} from "@onflow/flow-js-testing"_10_10const Alice = await getAccountAddress("Alice")_10const msgHex = "a1b2c3"_10_10const signature = await generateUserSignature(msgHex, Alice)
verifyUserSigntatures(msgHex, signatures, domainTag)
Used to verify signatures generated by signUserMessage. This function takes an array of signatures and verifies that the total key weight sums to >= 1000 and that these signatures are valid.
Arguments
| Name | Type | Optional | Description | 
|---|---|---|---|
| msgHex | string | the message which the provided signatures correspond to provided as a hex-encoded string or Buffer | |
| signatures | [SignatureObject] | An array of SignatureObjects which will be verified against this message | |
| domainTag | string | ✅ | Domain separation tag provided as a utf-8 encoded string (default: no domain separation tag). See more about domain tags here. | 
Returns
This method returns an object with the following keys:
| Type | Description | 
|---|---|
| boolean | Returns true if signatures are valid and total weight >= 1000 | 
Usage
_15import {_15  signUserMessage,_15  verifyUserSignatures,_15  getAccountAddress,_15} from "@onflow/flow-js-testing"_15_15const Alice = await getAccountAddress("Alice")_15const msgHex = "a1b2c3"_15_15const signature = await generateUserSignature(msgHex, Alice)_15_15console.log(await verifyUserSignatures(msgHex, Alice)) // true_15_15const Bob = await getAccountAddress("Bob")_15console.log(await verifyUserSignatures(msgHex, Bob)) // false
Emulator
Flow Javascript Testing Framework exposes emulator singleton allowing you to run and stop emulator instance
programmatically. There are two methods available on it.
emulator.start(options)
Starts emulator on a specified port. Returns Promise.
Arguments
| Name | Type | Optional | Description | 
|---|---|---|---|
| options | EmulatorOptions | ✅ | an object containing options for starting the emulator | 
EmulatorOptions
| Key | Type | Optional | Description | 
|---|---|---|---|
| logging | boolean | ✅ | whether log messages from emulator shall be added to the output (default: false) | 
| flags | string | ✅ | custom command-line flags to supply to the emulator (default: no flags) | 
| adminPort | number | ✅ | override the port which the emulator will run the admin server on (default: auto) | 
| restPort | number | ✅ | override the port which the emulator will run the REST server on (default: auto) | 
| grpcPort | number | ✅ | override the port which the emulator will run the GRPC server on (default: auto) | 
| debuggerPort | number | ✅ | override the port which the emulator will run the debug server on (default: auto) | 
Returns
| Type | Description | 
|---|---|
| Promise | Promise, which resolves to true if emulator started successfully | 
Usage
_15import path from "path"_15import {emulator, init} from "../src"_15;(async () => {_15  const basePath = path.resolve(__dirname, "../cadence")_15_15  await init(basePath)_15_15  // Start emulator instance on port 8080_15  await emulator.start()_15  console.log("emulator is working")_15_15  // Stop running emulator_15  await emulator.stop()_15  console.log("emulator has been stopped")_15})()
emulator.stop()
Stops emulator instance. Returns Promise.
Arguments
This method does not expect any arguments.
Returns
| Type | Description | 
|---|---|
| Promise | Promise, which resolves to true if emulator stopped without issues | 
Usage
_16import {emulator, init} from "@onflow/flow-js-testing"_16_16describe("test setup", () => {_16  // Instantiate emulator and path to Cadence files_16  beforeEach(async () => {_16    const basePath = path.resolve(__dirname, "../cadence")_16_16    await init(basePath)_16    await emulator.start()_16  })_16_16  // Stop emulator, so it could be restarted_16  afterEach(async () => {_16    await emulator.stop()_16  })_16})
emulator.setLogging(newState)
Set logging flag on emulator, allowing to temporally enable/disable logging.
Arguments
| Name | Type | Description | 
|---|---|---|
| newState | boolean | Enable/disable logging | 
Returns
Method does not return anything.
Usage
_27import path from "path"_27import {emulator, init} from "@onflow/flow-js-testing"_27_27describe("test setup", () => {_27  // Instantiate emulator and path to Cadence files_27  beforeEach(async () => {_27    const basePath = path.resolve(__dirname, "../cadence")_27_27    await init(basePath)_27    await emulator.start()_27  })_27_27  // Stop emulator, so it could be restarted_27  afterEach(async () => {_27    await emulator.stop()_27  })_27_27  test("basic test", async () => {_27    // Turn on logging from begining_27    emulator.setLogging(true)_27    // some asserts and interactions_27_27    // Turn off logging for later calls_27    emulator.setLogging(false)_27    // more asserts and interactions here_27  })_27})
FLOW Management
Some actions on the network will require account to have certain amount of FLOW token - transaction and storage fees, account creation, etc.
Framework provides a method to query balance with getFlowBalance and mint new tokens via mintFlow. You can find
information how to use them below.
getFlowBalance(address)
Fetch current FlowToken balance of account specified by address
Arguments
| Name | Type | Description | 
|---|---|---|
| address | Address | address of the account to check | 
Returns
| Type | Description | 
|---|---|
| string | UFix64 amount of FLOW tokens stored in account storage represented as string | 
Usage
_22import {_22  init,_22  emulator,_22  getAccountAddress,_22  getFlowBalance,_22} from "@onflow/flow-js-testing"_22_22const main = async () => {_22  const basePath = path.resolve(__dirname, "../cadence")_22_22  await init(basePath)_22  await emulator.start()_22_22  const Alice = await getAccountAddress("Alice")_22_22  const [result, error] = await getFlowBalance(Alice)_22  console.log({result}, {error})_22_22  await emulator.stop()_22}_22_22main()
mintFlow(recipient, amount)
Sends transaction to mint specified amount of FLOW token and send it to recipient.
⚠️ Required: Framework shall be initialized with
initmethod for this method to work.
Arguments
| Name | Type | Description | 
|---|---|---|
| recipient | Address | address of the account to check | 
| amount | string | UFix64 amount of FLOW tokens to mint and send to recipient | 
Returns
| Type | Description | 
|---|---|
| ResponseObject | Transaction result | 
Usage
_30import path from "path"_30import {_30  init,_30  emulator,_30  getAccountAddress,_30  getFlowBalance,_30  mintFlow,_30} from "../src"_30;(async () => {_30  const basePath = path.resolve(__dirname, "./cadence")_30_30  await init(basePath)_30  await emulator.start()_30_30  // Get address for account with alias "Alice"_30  const Alice = await getAccountAddress("Alice")_30_30  // Get initial balance_30  const [initialBalance] = await getFlowBalance(Alice)_30  console.log(initialBalance)_30_30  // Add 1.0 FLOW tokens to Alice account_30  await mintFlow(Alice, "1.0")_30_30  // Check updated balance_30  const updatedBalance = await getFlowBalance(Alice)_30  console.log({updatedBalance})_30_30  await emulator.stop()_30})()
Init
For Framework to operate properly you need to initialize it first.
You can do it with provided init method.
init( basePath, options)
Initializes framework variables.
Arguments
| Name | Type | Optional | Description | 
|---|---|---|---|
| bastPath | string | path to the folder holding all Cadence template files | |
| options | object | ✅ | options object to use during initialization | 
Options
| Name | Type | Optional | Description | 
|---|---|---|---|
| pkey | ✅ | private key for service account | 
Returns
| Type | Description | 
|---|---|
| Promise | Promise, which resolves to true if framework was initialized properly | 
Usage
_12import path from "path"_12import {init} from "@onflow/flow-js-testing"_12_12describe("test setup", () => {_12  beforeEach(async () => {_12    const basePath = path.resolve(__dirname, "../cadence")_12    await init(basePath)_12_12    // alternatively you can pass specific port_12    // await init(basePath, {port: 8085})_12  })_12})
Environment
getBlockOffset()
Returns current block offset - amount of blocks added on top of real current block height.
Returns
| Type | Description | 
|---|---|
| string | number representing amount of blocks added on top of real current block (encoded as string) | 
Usage
_16import path from "path"_16import {init, emulator, getBlockOffset} from "@onflow/flow-js-testing"_16_16const main = async () => {_16  const basePath = path.resolve(__dirname, "../cadence")_16_16  init(basePath)_16  await emulator.start()_16_16  const [blockOffset, err] = await getBlockOffset()_16  console.log({blockOffset}, {err})_16_16  await emulator.stop()_16}_16_16main()
setBlockOffset(offset)
Returns current block offset - amount of blocks added on top of real current block height.
Arguments
| Name | Type | Description | 
|---|
Returns
| Type | Description | 
|---|---|
| number | number representing amount of blocks added on top of real current block height | 
Usage
_36import path from "path"_36import {_36  init,_36  emulator,_36  executeScript,_36  getBlockOffset,_36  setBlockOffset,_36  sendTransaction,_36} from "@onflow/flow-js-testing"_36_36const main = async () => {_36  const basePath = path.resolve(__dirname, "../cadence")_36_36  init(basePath)_36  await emulator.start()_36_36  // Offset current block height by 42_36  await setBlockOffset(42)_36_36  const [blockOffset, err] = await getBlockOffset()_36  console.log({blockOffset}, {err})_36_36  // "getCurrentBlock().height" in your Cadence code will be replaced by Manager to a mocked value_36  const code = `_36    access(all) fun main(): UInt64 {_36      return getCurrentBlock().height_36    }_36  `_36_36  const [result, error] = await executeScript({code})_36  console.log({result}, {error})_36_36  await emulator.stop()_36}_36_36main()
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
_16import path from "path"_16import {init, emulator, getTimestampOffset} from "@onflow/flow-js-testing"_16_16const main = async () => {_16  const basePath = path.resolve(__dirname, "../cadence")_16_16  init(basePath)_16  await emulator.start()_16_16  const [timestampOffset, err] = await getTimestampOffset()_16  console.log({timestampOffset}, {err})_16_16  await emulator.stop()_16}_16_16main()
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
_36import path from "path"_36import {_36  init,_36  emulator,_36  executeScript,_36  getTimestampOffset,_36  setTimestampOffset,_36  sendTransaction,_36} from "@onflow/flow-js-testing"_36_36const main = async () => {_36  const basePath = path.resolve(__dirname, "../cadence")_36_36  init(basePath)_36  await emulator.start()_36_36  // Offset current timestamp by 10s_36  await setTimestampOffset(10)_36_36  const [timestampOffset, err] = await getTimestampOffset()_36  console.log({timestampOffset}, {err})_36_36  // "getCurrentBlock().timestamp" in your Cadence code will be replaced by Manager to a mocked value_36  const code = `_36    access(all) fun main(): UInt64 {_36      return getCurrentBlock().timestamp_36    }_36  `_36_36  const [result, error] = await executeScript({code})_36  console.log({result}, {error})_36_36  await emulator.stop()_36}_36_36main()
Jest Helpers
In order to simplify the process even further we've created several Jest-based methods, which will help you to catch thrown errors and ensure your code works as intended.
shallPass(ix)
Ensure transaction does not throw and sealed.
Arguments
| Name | Type | Description | 
|---|---|---|
| ix | Interaction | interaction, either in form of a Promise or function | 
Returns
| Type | Description | 
|---|---|
| ResponseObject | Transaction result | 
Usage
_49import path from "path"_49import {_49  init,_49  emulator,_49  shallPass,_49  sendTransaction,_49  getAccountAddress,_49} from "js-testing-framework"_49_49// We need to set timeout for a higher number, cause some interactions might need more time_49jest.setTimeout(10000)_49_49describe("interactions - sendTransaction", () => {_49  // Instantiate emulator and path to Cadence files_49  beforeEach(async () => {_49    const basePath = path.resolve(__dirname, "./cadence")_49    await init(basePath)_49    return emulator.start()_49  })_49_49  // Stop emulator, so it could be restarted_49  afterEach(async () => {_49    return emulator.stop()_49  })_49_49  test("basic transaction", async () => {_49    const code = `_49      transaction(message: String){_49        prepare(singer: AuthAccount){_49          log(message)_49        }_49      }_49    `_49    const Alice = await getAccountAddress("Alice")_49    const signers = [Alice]_49    const args = ["Hello, Cadence"]_49_49    const [txResult, error] = await shallPass(_49      sendTransaction({_49        code,_49        signers,_49        args,_49      })_49    )_49_49    // Transaction result will hold status, events and error message_49    console.log({txResult}, {error})_49  })_49})
shallRevert(ix, message)
Ensure interaction throws an error. Can test for specific error messages or catch any error message if message is not provided.
Returns Promise, which contains result, when resolved.
Arguments
| Name | Type | Description | 
|---|---|---|
| ix | Interaction | transaction, either in form of a Promise or function | 
| message(optional) | stringorRegExp | expected error message provided as either a string equality or regular expression to match, matches any error by default | 
Returns
| Type | Description | 
|---|---|
| ResponseObject | Transaction result | 
Usage
_60import path from "path"_60import {_60  init,_60  emulator,_60  shallPass,_60  sendTransaction,_60  getAccountAddress,_60} from "js-testing-framework"_60_60// We need to set timeout for a higher number, cause some interactions might need more time_60jest.setTimeout(10000)_60_60describe("interactions - sendTransaction", () => {_60  // Instantiate emulator and path to Cadence files_60  beforeEach(async () => {_60    const basePath = path.resolve(__dirname, "./cadence")_60    await init(basePath)_60    return emulator.start()_60  })_60_60  // Stop emulator, so it could be restarted_60  afterEach(async () => {_60    return emulator.stop()_60  })_60_60  test("basic transaction", async () => {_60    const code = `_60      transaction(message: String){_60        prepare(singer: AuthAccount){_60          panic("You shall not pass!")_60        }_60      }_60    `_60    const Alice = await getAccountAddress("Alice")_60    const signers = [Alice]_60    const args = ["Hello, Cadence"]_60_60    // Catch any cadence error_60    let [txResult, error] = await shallRevert(_60      sendTransaction({_60        code,_60        signers,_60        args,_60      })_60    )_60_60    // Catch only specific panic message_60    let [txResult2, error2] = await shallRevert(_60      sendTransaction({_60        code,_60        signers,_60        args,_60      }),_60      "You shall not pass!"_60    )_60_60    // Transaction result will hold status, events and error message_60    console.log({txResult}, {error})_60  })_60})
shallResolve(ix)
Ensure interaction resolves without throwing errors.
Arguments
| Name | Type | Description | 
|---|---|---|
| ix | Interaction | interaction, either in form of a Promise or function | 
Returns
| Type | Description | 
|---|---|
| InteractionResult | Interaction result | 
Usage
_36import path from "path"_36import {init, emulator, shallPass, executeScript} from "js-testing-framework"_36_36// We need to set timeout for a higher number, cause some interactions might need more time_36jest.setTimeout(10000)_36_36describe("interactions - sendTransaction", () => {_36  // Instantiate emulator and path to Cadence files_36  beforeEach(async () => {_36    const basePath = path.resolve(__dirname, "./cadence")_36    await init(basePath)_36    return emulator.start()_36  })_36_36  // Stop emulator, so it could be restarted_36  afterEach(async () => {_36    return emulator.stop()_36  })_36_36  test("basic script", async () => {_36    const code = `_36      access(all) fun main():Int{_36        return 42_36      }_36    `_36_36    const [result, error] = await shallResolve(_36      executeScript({_36        code,_36      })_36    )_36_36    expect(result).toBe(42)_36    expect(error).toBe(null)_36  })_36})
Scripts
It is often the case that you need to query current state of the network. For example, to check balance of the account, read public value of the contract or ensure that user has specific resource in their storage.
We abstract this interaction into single method called executeScript. Method have 2 different signatures.
⚠️ Required: Your project must follow the required structure it must be initialized to use the following functions.
executeScript(props)
Provides explicit control over how you pass values.
Arguments
props object accepts following fields:
| Name | Type | Optional | Description | 
|---|---|---|---|
| code | string | ✅ | string representation of Cadence script | 
| name | string | ✅ | name of the file in scriptsfolder to use (sans.cdcextension) | 
| args | [any] | ✅ | an array of arguments to pass to script. Optional if script does not expect any arguments. | 
| transformers | [CadenceTransformer] | ✅ | an array of operators to modify the code, before submitting it to network | 
⚠️ Required: Either
codeornamefield shall be specified. Method will throw an error if both of them are empty. Ifnamefield provided, framework will source code from file and override value passed viacodefield.
Returns
| Type | Description | 
|---|---|
| ResponseObject | Script result | 
Usage
_29import path from "path"_29import {init, emulator, executeScript} from "@onflow/flow-js-testing"_29_29const main = async () => {_29  const basePath = path.resolve(__dirname, "../cadence")_29_29  // Init framework_29  init(basePath)_29  // Start emulator_29  await emulator.start()_29_29  // Define code and arguments we want to pass_29  const code = `_29    access(all) fun main(message: String): Int{_29      log(message)_29_29      return 42_29    }_29  `_29  const args = ["Hello, from Cadence"]_29_29  const [result, error, logs] = await executeScript({code, args})_29  console.log({result}, {error}, {logs})_29_29  // Stop emulator instance_29  await emulator.stop()_29}_29_29main()
executeScript(name: string, args: [any])
This signature provides simplified way of executing a script, since most of the time you will utilize existing Cadence files.
Arguments
| Name | Type | Optional | Description | 
|---|---|---|---|
| name | string | name of the file in scriptsfolder to use (sans.cdcextension) | |
| args | [any] | ✅ | an array of arguments to pass to script. Optional if scripts don't expect any arguments. Default: [] | 
Returns
| Type | Description | 
|---|---|
| ResponseObject | Script result | 
Usage
_22import path from "path"_22import {init, emulator, executeScript} from "@onflow/flow-js-testing"_22_22const main = async () => {_22  const basePath = path.resolve(__dirname, "../cadence")_22_22  // Init framework_22  init(basePath)_22  // Start emulator_22  await emulator.start()_22_22  // Define arguments we want to pass_22  const args = ["Hello, from Cadence"]_22_22  // We assume there is a file `scripts/log-message.cdc` under base path_22  const [result, error, logs] = await executeScript("log-message", args)_22  console.log({result}, {error}, {logs})_22_22  await emulator.stop()_22}_22_22main()
Transactions
Another common case is interactions that mutate network state - sending tokens from one account to another, minting new NFT, etc. Framework provides sendTransaction method to achieve this. This method have 2 different signatures.
⚠️ Required: Your project must follow the required structure it must be initialized to use the following functions.
sendTransaction(props)
Send transaction to network. Provides explicit control over how you pass values.
Arguments
props object accepts following fields:
| Name | Type | Optional | Description | 
|---|---|---|---|
| code | string | ✅ | string representation of Cadence transaction | 
| name | string | ✅ | name of the file in transactionfolder to use (sans.cdcextension) | 
| args | [any] | ✅ | an array of arguments to pass to transaction. Optional if transaction does not expect any arguments. | 
| signers | [Address or SignerInfo] | ✅ | an array of Address or SignerInfo objects representing transaction autorizers | 
| addressMap | AddressMap | ✅ | name/address map to use as lookup table for addresses in import statements | 
| transformers | [CadenceTransformer] | ✅ | an array of operators to modify the code, before submitting it to network | 
⚠️ Required: Either
codeornamefield shall be specified. Method will throw an error if both of them are empty. Ifnamefield provided, framework will source code from file and override value passed viacodefield.
📣 if
signersfield not provided, service account will be used to authorize the transaction.
📣 Pass
addressMaponly in cases, when you would want to override deployed contract. Otherwide imports can be resolved automatically without explicitly passing them viaaddressMapfield
Usage
_36import path from "path"_36import {_36  init,_36  emulator,_36  sendTransaction,_36  getAccountAddress,_36} from "@onflow/flow-js-testing"_36_36const main = async () => {_36  const basePath = path.resolve(__dirname, "../cadence")_36_36  // Init framework_36  await init(basePath)_36  // Start emulator_36  await emulator.start()_36_36  // Define code and arguments we want to pass_36  const code = `_36    transaction(message: String){_36      prepare(signer: AuthAccount){_36        log(message)_36      }_36    }_36  `_36  const args = ["Hello, from Cadence"]_36  const Alice = await getAccountAddress("Alice")_36  const signers = [Alice]_36_36  const [result, error, logs] = await sendTransaction({code, args, signers})_36  console.log({result}, {error}, {logs})_36_36  // Stop emulator instance_36  await emulator.stop()_36}_36_36main()
sendTransaction(name, signers, args)
This signature provides simplified way to send a transaction, since most of the time you will utilize existing Cadence files.
| Name | Type | Optional | Description | 
|---|---|---|---|
| name | string | ✅ | name of the file in transactionfolder to use (sans.cdcextension) | 
| args | [any] | ✅ | an array of arguments to pass to transaction. Optional if transaction does not expect any arguments. | 
| signers | [Address or SignerInfoObject] | ✅ | an array of Address or array of SignerInfoObject representing transaction autorizers | 
Usage
_29import path from "path"_29import {_29  init,_29  emulator,_29  sendTransaction,_29  shallPass,_29} from "@onflow/flow-js-testing"_29_29const main = async () => {_29  const basePath = path.resolve(__dirname, "../cadence")_29_29  // Init framework_29  await init(basePath)_29  // Start emulator_29  await emulator.start()_29_29  // Define arguments we want to pass_29  const args = ["Hello, Cadence"]_29_29  const [result, error, logs] = await shallPass(_29    sendTransaction("log-message", [], args)_29  )_29  console.log({result}, {error}, {logs})_29_29  // Stop the emulator instance_29  await emulator.stop()_29}_29_29main()
Templates
The philosophy behind Flow JS Testing Framework is to be a set of helper methods. They can be used in opinionated way, envisioned by Flow Team. Or they can work as building blocks, allowing developers to build their own testing solution as they see fit.
Following methods used inside other framework methods, but we feel encouraged to list them here as well.
getTemplate(file, addressMap, byAddress)
Returns Cadence template as string with addresses replaced using addressMap
| Name | Type | Optional | Description | 
|---|---|---|---|
| file | string | relative (to the place from where the script was called) or absolute path to the file containing the code | |
| addressMap | AddressMap | ✅ | object to use for address mapping of existing deployed contracts. Default: {} | 
| byAddress | boolean | ✅ | whether addressMap is {name:address}or{address:address}type. Default:false | 
Returns
| Type | Description | 
|---|---|
| string | content of a specified file | 
Usage
_12import path from "path"_12import {init, getTemplate} from "@onflow/flow-js-testing"_12_12const main = async () => {_12  const basePath = path.resolve(__dirname, "../cadence")_12  await init(basePath)_12_12  const template = await getTemplate("../cadence/scripts/get-name.cdc")_12  console.log({template})_12}_12_12main()
getContractCode(name, addressMap)
Returns Cadence template from file with name in _basepath_/contracts folder
Arguments
| Name | Type | Optional | Description | 
|---|---|---|---|
| name | string | name of the contract template | |
| addressMap | AddressMap | ✅ | object to use for address mapping of existing deployed contracts | 
Returns
| Type | Description | 
|---|---|
| string | Cadence template code for specified contract | 
Usage
_23import path from "path"_23import {init, emulator, getContractCode} from "@onflow/flow-js-testing"_23_23const main = async () => {_23  const basePath = path.resolve(__dirname, "../cadence")_23_23  await init(basePath)_23  await emulator.start()_23_23  // Let's assume we need to import MessageContract_23  await deployContractByName({name: "MessageContract"})_23  const [MessageContract] = await getContractAddress("MessageContract")_23  const addressMap = {MessageContract}_23_23  const contractTemplate = await getContractCode("HelloWorld", {_23    MessageContract,_23  })_23  console.log({contractTemplate})_23_23  await emulator.stop()_23}_23_23main()
getTransactionCode(name, addressMap)
Returns Cadence template from file with name in _basepath_/transactions folder
Arguments
| Name | Type | Optional | Description | 
|---|---|---|---|
| name | string | name of the transaction template | |
| addressMap | AddressMap | ✅ | object to use for address mapping of existing deployed contracts | 
Returns
| Type | Description | 
|---|---|
| string | Cadence template code for specified transaction | 
Usage
_24import path from "path"_24import {init, emulator, getTransactionCode} from "@onflow/flow-js-testing"_24_24const main = async () => {_24  const basePath = path.resolve(__dirname, "../cadence")_24_24  await init(basePath)_24  await emulator.start()_24_24  // Let's assume we need to import MessageContract_24  await deployContractByName({name: "MessageContract"})_24  const [MessageContract] = await getContractAddress("MessageContract")_24  const addressMap = {MessageContract}_24_24  const txTemplate = await getTransactionCode({_24    name: "set-message",_24    addressMap,_24  })_24  console.log({txTemplate})_24_24  await emulator.stop()_24}_24_24main()
getScriptCode(name, addressMap)
Returns Cadence template from file with name in _basepath_/scripts folder
Arguments
| Name | Type | Optional | Description | 
|---|---|---|---|
| name | string | name of the script template | |
| addressMap | AddressMap | ✅ | object to use for address mapping of existing deployed contracts | 
Returns
| Type | Description | 
|---|---|
| string | Cadence template code for specified script | 
Usage
_24import path from "path"_24import {init, emulator, getScriptCode} from "@onflow/flow-js-testing"_24_24const main = async () => {_24  const basePath = path.resolve(__dirname, "../cadence")_24_24  await init(basePath)_24  await emulator.start()_24_24  // Let's assume we need to import MessageContract_24  await deployContractByName({name: "MessageContract"})_24  const [MessageContract] = await getContractAddress("MessageContract")_24  const addressMap = {MessageContract}_24_24  const scriptTemplate = await getScriptCode({_24    name: "get-message",_24    addressMap,_24  })_24_24  console.log({scriptTemplate})_24  await emulator.stop()_24}_24_24main()
Storage Inspection
getPaths
Retrieves information about the public, private, and storage paths for a given account.
Arguments
| Name | Type | Description | 
|---|---|---|
| address | string | The address or name of the account to retrieve the paths from. | 
| useSet(optional) | boolean | Whether to return the paths as a Set or an array. Defaults to true. | 
Returns
An object containing the following properties:
| Name | Type | Description | 
|---|---|---|
| publicPaths | Array<string>orSet<string> | An array or Set of the public paths for the account, as strings. | 
| privatePaths | Array<string>orSet<string> | An array or Set of the private paths for the account, as strings. | 
| storagePaths | Array<string>orSet<string> | An array or Set of the storage paths for the account, as strings. | 
The
useSetparameter determines whether the paths are returned as an array or Set. IfuseSetistrue, the paths will be returned as a Set; otherwise, they will be returned as an array.
Usage
_22import path from "path"_22import {init, emulator} from "@onflow/flow-js-testing"_22import {getAccountAddress, getPaths} from "@onflow/flow-js-testing"_22_22const main = async () => {_22  const basePath = path.resolve(__dirname, "../cadence")_22_22  await init(basePath)_22  await emulator.start()_22_22  // Get storage stats_22  const Alice = await getAccountAddress("Alice")_22  const paths = await getPaths(Alice)_22  const {publicPaths, privatePaths, storagePaths} = paths_22_22  // Output result to console_22  console.log({Alice, paths})_22_22  await emulator.stop()_22}_22_22main()
getPathsWithType
Retrieves public, private, and storage paths for a given account with extra information available on them
Arguments
| Name | Type | Description | 
|---|---|---|
| address | string | The address or name of the account to retrieve the paths from. | 
Returns
An object containing the following properties:
| Name | Type | Description | 
|---|---|---|
| publicPaths | Object | An object containing the public paths for the account, as keys and their types as values. | 
| privatePaths | Object | An object containing the private paths for the account, as keys and their types as values. | 
| storagePaths | Object | An object containing the storage paths for the account, as keys and their types as values. | 
The types of the paths are not strictly defined and may vary depending on the actual types used in the account.
Usage
_29import path from "path"_29import {init, emulator} from "@onflow/flow-js-testing"_29import {getPathsWithType} from "@onflow/flow-js-testing"_29_29const main = async () => {_29  const basePath = path.resolve(__dirname, "../cadence")_29_29  await init(basePath)_29  await emulator.start()_29_29  const {publicPaths} = await getPathsWithType("Alice")_29  const refTokenBalance = publicPaths.flowTokenBalance_29_29  if (_29    refTokenBalance.restrictionsList.has(_29      "A.ee82856bf20e2aa6.FungibleToken.Balance"_29    )_29  ) {_29    console.log("Found specific restriction")_29  }_29_29  if (refTokenBalance.haveRestrictions("FungibleToken.Balance")) {_29    console.log("Found matching restriction")_29  }_29_29  await emulator.stop()_29}_29_29main()
getStorageValue
Arguments
| Name | Type | Description | 
|---|---|---|
| account | string | The address or name of the account to retrieve the storage value from. | 
| path | string | The path of the storage value to retrieve. | 
Returns
| Type | Description | 
|---|---|
| Promise<any> | The value of the storage at the given path, or nullif no value is found. | 
Usage
_28import path from "path"_28import {init, emulator} from "@onflow/flow-js-testing"_28import {sendTransaction, getStorageValue} from "@onflow/flow-js-testing"_28_28const main = async () => {_28  const basePath = path.resolve(__dirname, "../cadence")_28_28  await init(basePath)_28  await emulator.start()_28_28  // Inplant some value into account_28  await sendTransaction({_28    code: `_28        transaction{_28          prepare(signer: AuthAccount){_28            signer.save(42, to: /storage/answer)_28          }_28        }_28      `,_28    signers: [Alice],_28  })_28  const answer = await getStorageValue("Alice", "answer")_28  console.log({answer})_28_28  await emulator.stop()_28}_28_28main()
getStorageStats
Retrieves the storage statistics (used and capacity) for a given account.
Arguments
| Name | Type | Description | 
|---|---|---|
| address | string | The address or name of the account to check for storage statistics. | 
| convert(optional) | boolean | Whether to convert the usedandcapacityvalues from strings to numbers. Defaults totrue. | 
Returns
A Promise that resolves to an object containing the following properties:
| Name | Type | Description | 
|---|---|---|
| used | numberorstring | The amount of storage used by the account, in bytes. | 
| capacity | numberorstring | The total storage capacity of the account, in bytes. | 
If
convertistrue, theusedandcapacityvalues will be converted from strings to numbers before being returned.
Usage
_21import path from "path"_21import {init, emulator} from "@onflow/flow-js-testing"_21import {getAccountAddress, getStorageStats} from "@onflow/flow-js-testing"_21_21const main = async () => {_21  const basePath = path.resolve(__dirname, "../cadence")_21_21  await init(basePath)_21  await emulator.start()_21_21  // Get storage stats_21  const Alice = await getAccountAddress("Alice")_21  const {capacity, used} = await getStorageStats(Alice)_21_21  // Output result to console_21  console.log({Alice, capacity, used})_21_21  await emulator.stop()_21}_21_21main()
Types
AddressMap
Object to use for address mapping of existing deployed contracts. Key shall be string and value shall be Address
Example
_10const addressMap = {_10  Messanger: "0x01cf0e2f2f715450",_10  Logger: "0x179b6b1cb6755e31",_10}
Interaction
Interaction is a Promise or function returning a promise.
Example
_10const ix = async () => {_10  return new Promise((resolve, reject) => {_10    setTimeout(() => {_10      resolve(1337)_10    })_10  }, 500)_10}
CadenceTransformer
Function, which will get valid Cadence code, modify it and return valid Cadence code
Example
This transformer will look for occupancies of specific import statement and replace it with proper address, where it's deployed on Emulator
_10const replaceAddress = async code => {_10  const modified = code.replace(_10    /import\s+FungibleToken\s+from\s+0xFUNGIBLETOKEN/,_10    "import FungibleToken from 0xee82856bf20e2aa6"_10  )_10_10  return modified_10}
KeyObject
Key objects are used to specify signer keys when creating accounts.
| Key | Required | Value Type | Description | 
|---|---|---|---|
| hashAlgorithm | No | HashAlgorithm | Hashing algorithm to use for generating signatures to be signed by this key (default: HashAlgorithm.SHA3_256) | 
| privateKey | Yes | string | Private key to use to generate the signature | 
| signatureAlgorithm | No | SignatureAlgorithm | Signing algorithm used to sign transactions with this key (default: SignatureAlgorithm.ECDSA_P256) | 
| weight | No | number | Weight of the key - see Flow Core Concepts for more information | 
PublicKey
Public keys are stored as Buffer objects which have been RLP encoded according to the Flow spec.
In order to generate this object using the Flow JS Testing library, use the pubFlowKey method exported by the library.
_10import {pubFlowKey} from "@onflow/flow-js-testing"_10_10const pubKey = await pubFlowKey({_10  privateKey: ...,_10  hashAlgorithm: ...,_10  signatureAlgorithm: ...,_10  weight: ..._10})
SignatureObject
Signature objects are used to represent a signature for a particular message as well as the account and keyId which signed for this message.
| Key | Value Type | Description | 
|---|---|---|
| addr | Address | the address of the account which this signature has been generated for | 
| keyId | number | Address or SignerInfo object representing user to generate this signature for | 
| signature | string | a hexidecimal-encoded string representation of the generated signature | 
SignerInfoObject
Signer Info objects are used to specify information about which signer and which key from this signer shall be used to sign a transaction.
| Key | Required | Value Type | Description | 
|---|---|---|---|
| addr | Yes | Address | The address of the signer's account | 
| hashAlgorithm | No | HashAlgorithm | Hashing algorithm to use for generating the signature (default: HashAlgorithm.SHA3_256) | 
| keyId | No | number | The index of the desired key to use from the signer's account (default: 0) | 
| privateKey | No | string | Private key to use to generate the signature (default: service account private key - this is the default PK for all accounts generated by Flow JS Testing Library, see: accounts) | 
| signatureAlgorithm | No | SignatureAlgorithm | Signing algorithm used to generate the signature (default: SignatureAlgorithm.ECDSA_P256) | 
HashAlgorithm
| Identifier | Value | 
|---|---|
| SHA2_256 | 1 | 
| SHA3_256 | 3 | 
Hash algorithms may be provided as either an enum (accessible via the HashAlgorithm object exported by Flow JS Testing, i.e. HashAlgorithm.SHA3_256) or as a string representation of their enum identifier (i.e. "SHA3_256")
SignatureAlgorithm
| Identifier | Value | 
|---|---|
| ECDSA_P256 | 2 | 
| ECDSA_secp256k1 | 3 | 
Signing algorithms may be provided as either an enum (accessible via the SignatureAlgorithm object exported by Flow JS Testing, i.e. SignatureAlgorithm.ECDSA_P256) or as a string representation of their enum identifier (i.e. "ECDSA_P256")
Utilities
isAddress(address)
Returns true if the given string is a validly formatted account address (both "0x" prefixed and non-prefixed are valid)
Arguments
| Name | Type | Optional | Description | 
|---|---|---|---|
| address | string | string to test against the regex | 
Returns
| Type | Description | 
|---|---|
| boolean | Returns true if given string is a validly formatted account address. | 
Usage
_10import {isAddress} from "@onflow/flow-js-testing"_10_10const badAddr = "0xqrtyff"_10console.log(isAddress(badAddr)) // false_10_10const goodAddrWithPrefix = "0xf8d6e0586b0a20c1"_10console.log(isAddress(goodAddrWithPrefix)) // true_10_10const goodAddrSansPrefix = "f8d6e0586b0a20c1"_10console.log(isAddress(goodAddrSansPrefix)) // true