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 | 0x prefixed 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
name
field not provided, the account address will not be cached and you will be unable to look it up usinggetAccountAddress
.
Returns
Type | Description |
---|---|
Address | 0x prefixed 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 contracts folder (with .cdc extension) 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 pub contract Wallet{_42 pub 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 pub 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 | 0x prefixed 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.