diff --git a/.changeset/rare-starfishes-mate.md b/.changeset/rare-starfishes-mate.md
new file mode 100644
index 00000000..afb6b3cc
--- /dev/null
+++ b/.changeset/rare-starfishes-mate.md
@@ -0,0 +1,5 @@
+---
+"flow-js-testing": minor
+---
+
+Dynamically select ports for emulator instead of supplying admin port statically through emulator.start arguments, deprecate use of this argument
diff --git a/README.md b/README.md
index 3f540b35..49e37b62 100644
--- a/README.md
+++ b/README.md
@@ -6,14 +6,14 @@
Test your Flow applications written in Cadence with ease
- Quick Intro»
+ Read the docs
Report Bug
·
Contribute
·
- Installation
+ Installation
@@ -34,15 +34,9 @@ Most of the methods will not work, unless you have Flow Emulator running in the
You can install it alongside Flow CLI. Please refer to [Install Flow CLI](https://docs.onflow.org/flow-cli/install)
for instructions.
-If you have it already installed, run the `flow init` in your terminal to create `flow.json` config file.
-Then start the emulator with `flow emulator -v`.
+If you have it already installed, run the `flow init` in your terminal to create `flow.json` config file in the root directory of your tests.
-## Documentation
-
-- [Installation](/docs/install.md)
-- [API](/docs/api.md)
-- Extra Examples
- - [Metadata](/docs/examples/metadata.md)
+In order to use the emulator within your tests, please refer to the [documentation](https://docs.onflow.org/flow-js-testing/emulator/).
## Playground Integration
diff --git a/TRANSITIONS.md b/TRANSITIONS.md
new file mode 100644
index 00000000..1f510c03
--- /dev/null
+++ b/TRANSITIONS.md
@@ -0,0 +1,12 @@
+# Transitions
+
+## 0001 Deprecate `emulator.start()` port argument
+
+- **Date:** Jun 28 2022
+- **Type:** Depreaction of `port` argument for `emulator.start()`
+
+`emulator.start` was previously called with the arguments: `emulator.start(port, options = {})`. The `port` argument has now been removed and manual specification of the ports is no longer recommended.
+
+However, the `adminPort`, `restPort`, and `grpcPort` of the emulator may be overriden as fields in `options` (i.e. `options.restPort = 1234`) if absolutely necessary - however their use is not advisable and may cause unintended consequences.
+
+Instead, it is recommended omit supplying a static a port and allow flow-js-testing to automatically determine available ports to supply the emululator. Flow-js-testing will automatically configure @onflow/fcl to use these ports for all of its functionality.
diff --git a/dev-test/deploy.test.js b/dev-test/deploy.test.js
index 4ead3ec1..3510cdc8 100644
--- a/dev-test/deploy.test.js
+++ b/dev-test/deploy.test.js
@@ -19,9 +19,8 @@ describe("interactions - sendTransaction", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
await init(basePath);
- return emulator.start(port);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
diff --git a/dev-test/imports.test.js b/dev-test/imports.test.js
index 078e93fd..e04fb688 100644
--- a/dev-test/imports.test.js
+++ b/dev-test/imports.test.js
@@ -16,7 +16,7 @@ describe("import resolver", () => {
const basePath = path.resolve(__dirname, "./cadence");
const port = 8081;
await init(basePath, { port });
- return emulator.start(port, false);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
diff --git a/dev-test/interaction.test.js b/dev-test/interaction.test.js
index fc399e00..3aeec38a 100644
--- a/dev-test/interaction.test.js
+++ b/dev-test/interaction.test.js
@@ -17,9 +17,8 @@ describe("interactions - sendTransaction", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8082;
- await init(basePath, { port });
- return emulator.start(port);
+ await init(basePath);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -132,9 +131,8 @@ describe("interactions - executeScript", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- return emulator.start(port, false);
+ await init(basePath);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -167,7 +165,7 @@ describe("interactions - executeScript", () => {
});
test("executeScript - shall pass with short notation", async () => {
- const [result,err] = await shallResolve(executeScript("log-message"));
+ const [result, err] = await shallResolve(executeScript("log-message"));
expect(err).toBe(null);
expect(result).toBe(42);
});
@@ -191,8 +189,8 @@ describe("interactions - executeScript", () => {
}
`;
const args = [[]];
- return executeScript({ code, args });
- })
+ return executeScript({ code, args });
+ });
expect(err).toBe(null);
expect(result.length).toBe(0);
});
diff --git a/dev-test/metadata.test.js b/dev-test/metadata.test.js
index 64e9eca0..baa6c5bf 100644
--- a/dev-test/metadata.test.js
+++ b/dev-test/metadata.test.js
@@ -6,9 +6,8 @@ jest.setTimeout(10000);
describe("metadata examples", () => {
beforeEach(async () => {
const basePath = path.resolve("./cadence");
- const port = 8083;
await init(basePath);
- return emulator.start(port);
+ return emulator.start();
});
afterEach(async () => {
diff --git a/dev-test/usage.test.js b/dev-test/usage.test.js
index b47266c2..c6bd3b7b 100644
--- a/dev-test/usage.test.js
+++ b/dev-test/usage.test.js
@@ -23,9 +23,8 @@ describe("Basic Usage test", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8084;
await init(basePath);
- return emulator.start(port);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -80,9 +79,8 @@ describe("Basic Usage test", () => {
describe("jest methods", () => {
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8082;
await init(basePath);
- return emulator.start(port);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -146,10 +144,9 @@ describe("jest methods", () => {
describe("Path arguments", () => {
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8082;
await init(basePath);
- return emulator.start(port, true);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
diff --git a/dev-test/utilities.test.js b/dev-test/utilities.test.js
index 698b56d6..4da94dc0 100644
--- a/dev-test/utilities.test.js
+++ b/dev-test/utilities.test.js
@@ -24,9 +24,8 @@ describe("block height 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);
+ await init({ base });
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -59,7 +58,6 @@ describe("block height offset", () => {
const [offSet] = await getBlockOffset({ addressMap });
expect(offSet).toBe(0);
-
});
it("should update offset with utility method", async () => {
@@ -87,9 +85,8 @@ describe("block height 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);
+ await init({ base });
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -118,9 +115,8 @@ describe("dev tests", () => {
// 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, false);
+ await init({ base });
+ return emulator.start();
});
// Stop emulator, so it could be restarted
diff --git a/docs/README.md b/docs/README.md
index b82f8850..a3053046 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,4 +1,4 @@
# Flow Javascript Testing Framework Documentation
This directory contains the source files for the Flow Javascript Testing Framework documentation.
-Read the full version on the [Flow documentation website](https://docs.onflow.org/flow-cli).
\ No newline at end of file
+Read the full version on the [Flow documentation website](https://docs.onflow.org/flow-js-testing/).
diff --git a/docs/api.md b/docs/api.md
index b374e123..a3d630a3 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -19,22 +19,21 @@ Resolves name alias to a Flow address (`0x` prefixed) under the following condit
#### Returns
-| Type | Description |
-| --------------------------------------------------- | ---------------------------------------- |
+| Type | Description |
+| ------------------------------------------------------------- | ---------------------------------------- |
| [Address](https://docs.onflow.org/fcl/reference/api/#address) | `0x` prefixed address of aliased account |
#### Usage
```javascript
-import path from "path"
+import path from "path";
import { init, emulator, getAccountAddress } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
const Alice = await getAccountAddress("Alice");
console.log({ Alice });
@@ -53,18 +52,18 @@ Deploys contract code located inside a Cadence file. Returns the transaction res
Props object accepts 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) |
+| 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](https://docs.onflow.org/fcl/reference/api/#address) | ✅ | (optional) account address, where contract will be deployed. If this is not specified, framework will create new account with randomized alias. |
-| `addressMap` | [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` |
+| `addressMap` | [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` |
#### Returns
-| Type | Description |
-| ----------------------------------------------------------------- | ------------------------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Result of the deploying transaction. |
#### Usage
@@ -75,10 +74,9 @@ import { init, emulator, deployContractByName } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, {port});
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// We will deploy our contract to the address that corresponds to "Alice" alias
const to = await getAccountAddress("Alice");
@@ -111,19 +109,19 @@ Deploys contract code specified as string. Returns the transaction result.
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` |
+| 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](https://docs.onflow.org/fcl/reference/api/#address) | ✅ | account address, where contract will be deployed. If this is not specified, framework will create new account with randomized alias. |
-| `addressMap` | [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` |
+| `addressMap` | [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` |
#### Returns
-| Type | Description |
-| ----------------------------------------------------------------- | ------------------------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Result of the deploying transaction. |
#### Usage
@@ -134,10 +132,9 @@ import { init, emulator, getAccountAddress, deployContract, executeScript } from
(async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// We can specify, which account will hold the contract
const to = await getAccountAddress("Alice");
@@ -155,7 +152,7 @@ import { init, emulator, getAccountAddress, deployContract, executeScript } from
await deployContract({ to, name, code, args });
- const [balance,err] = await executeScript({
+ const [balance, err] = await executeScript({
code: `
import Wallet from 0x01
pub fun main(): UInt{
@@ -184,8 +181,8 @@ Returns address of the account where the contract is currently deployed.
#### Returns
-| Type | Description |
-| --------------------------------------------------- | --------------------- |
+| Type | Description |
+| ------------------------------------------------------------- | --------------------- |
| [Address](https://docs.onflow.org/fcl/reference/api/#address) | `0x` prefixed address |
#### Usage
@@ -196,10 +193,9 @@ import { init, emulator, deployContractByName, getContractAddress } from "../src
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// if we omit "to" it will be deployed to Service Account
// but let's pretend we don't know where it will be deployed :)
@@ -210,7 +206,6 @@ import { init, emulator, deployContractByName, getContractAddress } from "../src
await emulator.stop();
})();
-
```
📣 Framework does not support contracts with identical names deployed to different accounts. While you can deploy contract
@@ -221,16 +216,25 @@ to a new address, the internal system, which tracks where contracts are deployed
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(port, logging)`
+### `emulator.start(options)`
Starts emulator on a specified port. Returns Promise.
#### Arguments
-| Name | Type | Optional | Description |
-| --------- | ------- | -------- | ----------------------------------------------------------------- |
-| `port` | number | ✅ | number representing a port to use for access API. Default: `8080` |
-| `logging` | boolean | ✅ | whether log messages from emulator shall be added to the output |
+| 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: "") |
+| `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) |
#### Returns
@@ -246,19 +250,17 @@ import { emulator, init } from "../src";
(async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
+ await init(basePath);
// Start emulator instance on port 8080
- await emulator.start(port);
+ await emulator.start();
console.log("emulator is working");
// Stop running emulator
await emulator.stop();
console.log("emulator has been stopped");
})();
-
```
### `emulator.stop()`
@@ -284,10 +286,9 @@ describe("test setup", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
});
// Stop emulator, so it could be restarted
@@ -321,10 +322,9 @@ describe("test setup", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
});
// Stop emulator, so it could be restarted
@@ -358,8 +358,8 @@ Fetch current FlowToken balance of account specified by address
#### Arguments
-| Name | Type | Description |
-| --------- | --------------------------------------------------- | ------------------------------- |
+| Name | Type | Description |
+| --------- | ------------------------------------------------------------- | ------------------------------- |
| `address` | [Address](https://docs.onflow.org/fcl/reference/api/#address) | address of the account to check |
#### Returns
@@ -375,15 +375,14 @@ import { init, emulator, getAccountAddress, getFlowBalance } from "flow-js-testi
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
const Alice = await getAccountAddress("Alice");
const [result, error] = await getFlowBalance(Alice);
- console.log( { result }, { error });
+ console.log({ result }, { error });
await emulator.stop();
};
@@ -399,15 +398,15 @@ Sends transaction to mint specified amount of FLOW token and send it to recipien
#### Arguments
-| Name | Type | Description |
-| ----------- | --------------------------------------------------- | ---------------------------------------------------------- |
+| Name | Type | Description |
+| ----------- | ------------------------------------------------------------- | ---------------------------------------------------------- |
| `recipient` | [Address](https://docs.onflow.org/fcl/reference/api/#address) | address of the account to check |
-| `amount` | string | UFix64 amount of FLOW tokens to mint and send to recipient |
+| `amount` | string | UFix64 amount of FLOW tokens to mint and send to recipient |
#### Returns
-| Type | Description |
-| ----------------------------------------------------------------- | ------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Transaction result |
#### Usage
@@ -418,17 +417,16 @@ import { init, emulator, getAccountAddress, getFlowBalance, mintFlow } from "../
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// Get address for account with alias "Alice"
const Alice = await getAccountAddress("Alice");
// Get initial balance
const [initialBalance] = await getFlowBalance(Alice);
- console.log( initialBalance );
+ console.log(initialBalance);
// Add 1.0 FLOW tokens to Alice account
await mintFlow(Alice, "1.0");
@@ -439,7 +437,6 @@ import { init, emulator, getAccountAddress, getFlowBalance, mintFlow } from "../
await emulator.stop();
})();
-
```
## Init
@@ -449,9 +446,7 @@ You can do it with provided `init` method.
### init( basePath, options)
-Initializes framework variables and specifies port to use for HTTP and grpc access.
-`port` is set to 8080 by default. grpc port is calculated to `3569 + (port - 8080)` to allow multiple instances
-of emulator to be run in parallel.
+Initializes framework variables.
#### Arguments
@@ -464,7 +459,6 @@ of emulator to be run in parallel.
| Name | Type | Optional | Description |
| ------ | ---- | -------- | ------------------------------- |
-| `port` | | ✅ | http port for access node |
| `pkey` | | ✅ | private key for service account |
#### Returns
@@ -510,10 +504,9 @@ import { init, emulator, getBlockOffset } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- init(basePath, port);
- await emulator.start(port);
+ init(basePath);
+ await emulator.start();
const [blockOffset, err] = await getBlockOffset();
console.log({ blockOffset }, { err });
@@ -557,10 +550,9 @@ import {
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- init(basePath, port);
- await emulator.start(port);
+ init(basePath);
+ await emulator.start();
// Offset current block height by 42
await setBlockOffset(42);
@@ -604,8 +596,8 @@ Ensure transaction does not throw and sealed.
#### Returns
-| Type | Description |
-| ----------------------------------------------------------------- | ------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Transaction result |
#### Usage
@@ -627,9 +619,8 @@ describe("interactions - sendTransaction", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- return emulator.start(port);
+ await init(basePath);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -675,8 +666,8 @@ Ensure interaction throws an error. You might want to use this to test incorrect
#### Returns
-| Type | Description |
-| ----------------------------------------------------------------- | ------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Transaction result |
#### Usage
@@ -698,9 +689,8 @@ describe("interactions - sendTransaction", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- return emulator.start(port);
+ await init(basePath);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -763,9 +753,8 @@ describe("interactions - sendTransaction", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- return emulator.start(port);
+ await init(basePath);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -809,11 +798,11 @@ Provides explicit control over how you pass values.
`props` object accepts following fields:
-| Name | Type | Optional | Description |
-| -------------- | ----------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------ |
-| `code` | string | ✅ | string representation of Cadence script |
-| `name` | string | ✅ | name of the file in `scripts` folder to use (sans `.cdc` extension) |
-| `args` | array | ✅ | an array of arguments to pass to script. Optional if script does not expect any arguments. |
+| Name | Type | Optional | Description |
+| -------------- | ------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------ |
+| `code` | string | ✅ | string representation of Cadence script |
+| `name` | string | ✅ | name of the file in `scripts` folder to use (sans `.cdc` extension) |
+| `args` | array | ✅ | an array of arguments to pass to script. Optional if script does not expect any arguments. |
| `transformers` | array[[CadenceTransformer](#cadencetransformer)] | ✅ | an array of operators to modify the code, before submitting it to network |
> ⚠️ **Required:** Either `code` or `name` field shall be specified. Method will throw an error if both of them are empty.
@@ -821,8 +810,8 @@ Provides explicit control over how you pass values.
#### Returns
-| Type | Description |
-| ----------------------------------------------------------------- | ------------- |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------- |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Script result |
#### Usage
@@ -833,12 +822,11 @@ import { init, emulator, executeScript } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
// Init framework
- init(basePath, { port });
+ init(basePath);
// Start emulator
- await emulator.start(port);
+ await emulator.start();
// Define code and arguments we want to pass
const code = `
@@ -874,8 +862,8 @@ Cadence files.
#### Returns
-| Type | Description |
-| ----------------------------------------------------------------- | ------------- |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------- |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Script result |
#### Usage
@@ -886,12 +874,11 @@ import { init, emulator, executeScript } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
// Init framework
- init(basePath, port);
+ init(basePath);
// Start emulator
- await emulator.start(port);
+ await emulator.start();
// Define arguments we want to pass
const args = ["Hello, from Cadence"];
@@ -922,14 +909,14 @@ Provides explicit control over how you pass values.
`props` object accepts following fields:
-| Name | Type | Optional | Description |
-| -------------- | ----------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------- |
-| `code` | string | ✅ | string representation of Cadence transaction |
-| `name` | string | ✅ | name of the file in `transaction` folder to use (sans `.cdc` extension) |
-| `args` | [Any] | ✅ | an array of arguments to pass to transaction. Optional if transaction does not expect any arguments. |
-| `signers` | [Address] | ✅ | an array of [Address](https://docs.onflow.org/fcl/reference/api/#address) representing transaction autorizers |
-| `addressMap` | [AddressMap](#addressmap) | ✅ | name/address map to use as lookup table for addresses in import statements |
-| `transformers` | array[[CadenceTransformer](#cadencetransformer)] | ✅ | an array of operators to modify the code, before submitting it to network |
+| Name | Type | Optional | Description |
+| -------------- | ------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------- |
+| `code` | string | ✅ | string representation of Cadence transaction |
+| `name` | string | ✅ | name of the file in `transaction` folder to use (sans `.cdc` extension) |
+| `args` | [Any] | ✅ | an array of arguments to pass to transaction. Optional if transaction does not expect any arguments. |
+| `signers` | [Address] | ✅ | an array of [Address](https://docs.onflow.org/fcl/reference/api/#address) representing transaction autorizers |
+| `addressMap` | [AddressMap](#addressmap) | ✅ | name/address map to use as lookup table for addresses in import statements |
+| `transformers` | array[[CadenceTransformer](#cadencetransformer)] | ✅ | an array of operators to modify the code, before submitting it to network |
> ⚠️ **Required:** Either `code` or `name` field shall be specified. Method will throw an error if both of them are empty.
> If `name` field provided, framework will source code from file and override value passed via `code` field.
@@ -941,8 +928,8 @@ Provides explicit control over how you pass values.
#### Returns
-| Type | Description |
-| ----------------------------------------------------------------- | ------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Interaction result |
#### Usage
@@ -953,12 +940,11 @@ import { init, emulator, sendTransaction, getAccountAddress } from "flow-js-test
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
// Init framework
- await init(basePath, { port });
+ await init(basePath);
// Start emulator
- await emulator.start(port);
+ await emulator.start();
// Define code and arguments we want to pass
const code = `
@@ -987,16 +973,16 @@ main();
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 `transaction` folder to use (sans `.cdc` extension) |
-| `signers` | array | ✅ | an array of [Address](https://docs.onflow.org/fcl/reference/api/#address) representing transaction autorizers |
-| `args` | [Any] | ✅ | an array of arguments to pass to transaction. Optional if transaction does not expect any arguments. |
+| Name | Type | Optional | Description |
+| --------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------- |
+| `name` | string | ✅ | name of the file in `transaction` folder to use (sans `.cdc` extension) |
+| `signers` | array | ✅ | an array of [Address](https://docs.onflow.org/fcl/reference/api/#address) representing transaction autorizers |
+| `args` | [Any] | ✅ | an array of arguments to pass to transaction. Optional if transaction does not expect any arguments. |
#### Returns
-| Type | Description |
-| ----------------------------------------------------------------- | ------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Interaction result |
#### Usage
@@ -1007,12 +993,11 @@ import { init, emulator, sendTransaction } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
// Init framework
- await init(basePath, { port });
+ await init(basePath);
// Start emulator
- await emulator.start(port);
+ await emulator.start();
// Define arguments we want to pass
const args = ["Hello, Cadence"];
@@ -1092,10 +1077,9 @@ import { init, emulator, getContractCode } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// Let's assume we need to import MessageContract
await deployContractByName({ name: "MessageContract" });
@@ -1138,10 +1122,9 @@ import { init, emulator, getTransactionCode } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// Let's assume we need to import MessageContract
await deployContractByName({ name: "MessageContract" });
@@ -1185,10 +1168,9 @@ import { init, emulator, getScriptCode } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// Let's assume we need to import MessageContract
await deployContractByName({ name: "MessageContract" });
diff --git a/docs/contracts.md b/docs/contracts.md
index f840f4ed..e3b9bc5c 100644
--- a/docs/contracts.md
+++ b/docs/contracts.md
@@ -14,18 +14,18 @@ Deploys contract code located inside a Cadence file. Returns the transaction res
Props object accepts the following fields:
-| Name | Type | Optional | Description |
-| ------------ | --------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
-| `name` | string | | name of the file in `contracts` folder (sans `.cdc` extension) and name of the contract (please note those should be the same) |
+| Name | Type | Optional | Description |
+| ------------ | ------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
+| `name` | string | | name of the file in `contracts` folder (sans `.cdc` extension) and name of the contract (please note those should be the same) |
| `to` | [Address](https://docs.onflow.org/fcl/reference/api/#address) | ✅ | (optional) account address, where contract will be deployed. If this is not specified, framework will create new account with randomized alias. |
-| `addressMap` | [AddressMap](api.md#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` |
+| `addressMap` | [AddressMap](api.md#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` |
#### Returns
-| Type | Description |
-| ----------------------------------------------------------------- | ------------------------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Result of the deploying transaction. |
Usage:
@@ -36,10 +36,9 @@ import { init, emulator, deployContractByName } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- init(basePath, port);
- await emulator.start(port);
+ init(basePath);
+ await emulator.start();
// We will deploy our contract to the address that corresponds to "Alice" alias
const to = await getAccountAddress("Alice");
@@ -71,14 +70,14 @@ Deploys contract code specified as string. Returns transaction result.
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` |
+| 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](https://docs.onflow.org/fcl/reference/api/#address) | ✅ | account address, where contract will be deployed. If this is not specified, framework will create new account with randomized alias. |
-| `addressMap` | [AddressMap](api.md#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` |
+| `addressMap` | [AddressMap](api.md#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` |
Usage:
@@ -88,10 +87,9 @@ import { init, emulator, deployContract } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port, false);
+ await init(basePath);
+ await emulator.start();
const to = await getAccountAddress("Alice");
const name = "Wallet";
@@ -112,7 +110,7 @@ const main = async () => {
args,
});
- console.log( deploymentResult, error );
+ console.log(deploymentResult, error);
await emulator.stop();
};
@@ -137,10 +135,9 @@ import { getContractAddress } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port, false);
+ await init(basePath);
+ await emulator.start();
// if we ommit "to" it will be deployed to a newly generated address with "unknown" alias
await deployContractByName({ name: "HelloWorld" });
diff --git a/docs/emulator.md b/docs/emulator.md
index f443b690..5924904c 100644
--- a/docs/emulator.md
+++ b/docs/emulator.md
@@ -4,18 +4,34 @@ sidebar_title: Emulator
description: How to start a new instance of emulator
---
-Flow Javascript Testing Framework exposes `emulator` singleton allowing you to start and stop an emulator instance programmatically. There are two methods available on it.
+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(port, logging)`
+## `emulator.start(options)`
-Starts emulator on a specified port. Returns Promise.
+Starts emulator on random available port, unless overriden in options. Returns Promise.
#### Arguments
-| Name | Type | Optional | Description |
-| --------- | ------- | -------- | ----------------------------------------------------------------- |
-| `port` | number | ✅ | number representing a port to use for access API. Default: `8080` |
-| `logging` | boolean | ✅ | whether log messages from emulator shall be added to the output |
+| 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: "") |
+| `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) |
+
+#### Returns
+
+| Type | Description |
+| ------------------- | ---------------------------------------------------------------- |
+| [Promise](#Promise) | Promise, which resolves to true if emulator started successfully |
#### Usage
@@ -26,12 +42,11 @@ describe("test setup", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
+ await init(basePath);
// Start emulator instance on port 8080
- await emulator.start(port);
+ await emulator.start();
});
});
```
@@ -53,10 +68,9 @@ describe("test setup", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
});
// Stop emulator, so it could be restarted
@@ -85,10 +99,9 @@ describe("test setup", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
});
// Stop emulator, so it could be restarted
@@ -100,7 +113,7 @@ describe("test setup", () => {
// Turn on logging from begining
emulator.setLogging(true);
// some asserts and interactions
-
+
// Turn off logging for later calls
emulator.setLogging(false);
// more asserts and interactions here
diff --git a/docs/examples/metadata.md b/docs/examples/metadata.md
index e0126214..88dd8bf0 100644
--- a/docs/examples/metadata.md
+++ b/docs/examples/metadata.md
@@ -14,12 +14,11 @@ import { executeScript } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
// Init framework
- await init(basePath, { port });
+ await init(basePath);
// Start emulator
- await emulator.start(port);
+ await emulator.start();
const code = `
pub fun main(metadata: {String: String}): String{
@@ -33,7 +32,7 @@ const main = async () => {
// If something goes wrong with script execution, the method will throw an error
// so we need to catch it and proce
const [name, err] = await shallResolve(executeScript({ code, args }));
- console.log( name, err );
+ console.log(name, err);
await emulator.stop();
};
@@ -65,4 +64,4 @@ const args = [
```
Framework will try to resolve the types to the best of its abilities. If you encounter an error for your use case,
-please create an issue here: [https://github.com/onflow/flow-js-testing/issues](https://github.com/onflow/flow-js-testing/issues)
\ No newline at end of file
+please create an issue here: [https://github.com/onflow/flow-js-testing/issues](https://github.com/onflow/flow-js-testing/issues)
diff --git a/docs/execute-scripts.md b/docs/execute-scripts.md
index 2392a1df..83b666a9 100644
--- a/docs/execute-scripts.md
+++ b/docs/execute-scripts.md
@@ -38,9 +38,9 @@ const main = async () => {
const port = 8080;
// Init framework
- init(basePath, { port });
+ init(basePath);
// Start emulator
- await emulator.start(port);
+ await emulator.start();
// Define code and arguments we want to pass
const code = `
@@ -52,7 +52,7 @@ const main = async () => {
`;
const args = ["Hello, from Cadence"];
- const [result,e] = await executeScript({ code, args });
+ const [result, e] = await executeScript({ code, args });
console.log(result, e);
// Stop emulator instance
@@ -82,19 +82,18 @@ import { init, emulator, executeScript } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
// Init framework
- init(basePath, port);
+ init(basePath);
// Start emulator
- await emulator.start(port, false);
+ await emulator.start();
// Define arguments we want to pass
const args = ["Hello, from Cadence"];
- const [result,error] = await executeScript("log-message", args);
+ const [result, error] = await executeScript("log-message", args);
console.log(result, error);
-
+
await emulator.stop();
};
diff --git a/docs/flow-token.md b/docs/flow-token.md
index 443da0a6..6d00fe75 100644
--- a/docs/flow-token.md
+++ b/docs/flow-token.md
@@ -13,8 +13,8 @@ Returns current FLOW token balance of the specified account.
#### Arguments
-| Name | Type | Description |
-| --------- | --------------------------------------------------- | ------------------------------- |
+| Name | Type | Description |
+| --------- | ------------------------------------------------------------- | ------------------------------- |
| `address` | [Address](https://docs.onflow.org/fcl/reference/api/#address) | address of the account to check |
#### Returns
@@ -30,10 +30,9 @@ import { init, emulator, getAccountAddress, getFlowBalance } from "flow-js-testi
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
const Alice = await getAccountAddress("Alice");
@@ -54,10 +53,10 @@ Sends transaction to mint the specified amount of FLOW and send it to recipient.
#### Arguments
-| Name | Type | Description |
-| ----------- | --------------------------------------------------- | ---------------------------------------------------------- |
+| Name | Type | Description |
+| ----------- | ------------------------------------------------------------- | ---------------------------------------------------------- |
| `recipient` | [Address](https://docs.onflow.org/fcl/reference/api/#address) | address of the account to check |
-| `amount` | string | UFix64 amount of FLOW tokens to mint and send to recipient |
+| `amount` | string | UFix64 amount of FLOW tokens to mint and send to recipient |
#### Usage
@@ -66,15 +65,14 @@ import { init, emulator, mintFlow } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
const Alice = await getAccountAddress("Alice");
const amount = "42.0";
const [mintResult, error] = await mintFlow(Alice);
- console.log( mintResult, error );
+ console.log(mintResult, error);
await emulator.stop();
};
diff --git a/docs/init.md b/docs/init.md
index 7e1c0330..faaaefc3 100644
--- a/docs/init.md
+++ b/docs/init.md
@@ -9,9 +9,7 @@ You can do it with provided `init` method.
### init( basePath, options)
-Initializes framework variables and specifies port to use for HTTP and grpc access.
-`port` is set to 8080 by default. gRPC port is calculated to `3569 + (port - 8080)` to allow multiple instances
-of emulator to be run in parallel.
+Initializes framework variables.
#### Arguments
@@ -24,7 +22,6 @@ of emulator to be run in parallel.
| Name | Type | Optional | Description |
| ------ | ---- | -------- | ------------------------------- |
-| `port` | | ✅ | http port for access node |
| `pkey` | | ✅ | private key for service account |
#### Usage
diff --git a/docs/jest-helpers.md b/docs/jest-helpers.md
index 41fff00c..4668712d 100644
--- a/docs/jest-helpers.md
+++ b/docs/jest-helpers.md
@@ -13,27 +13,21 @@ Ensure transaction did not throw and was sealed.
#### Arguments
-| Name | Type | Description |
-| ---- | --------------------------- | ---------------------------------------------------- |
-| `ix` | [Interaction](api.md#interaction) | interaction, either in form of a Promise or function |
+| Name | Type | Description |
+| ---- | --------------------------------- | ---------------------------------------------------- |
+| `ix` | [Interaction](api.md#interaction) | interaction, either in form of a Promise or function |
#### Returns
-| Type | Description |
-| --------------------------------------- | ------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Transaction result |
#### Usage
```javascript
import path from "path";
-import {
- init,
- emulator,
- shallPass,
- sendTransaction,
- getAccountAddress,
-} from "flow-js-testing";
+import { init, emulator, shallPass, sendTransaction, getAccountAddress } from "flow-js-testing";
// We need to set timeout for a higher number, because some transactions might take up some time
jest.setTimeout(10000);
@@ -42,9 +36,8 @@ describe("interactions - sendTransaction", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- return emulator.start(port);
+ await init(basePath);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -85,14 +78,14 @@ Returns Promise, which contains result, when resolved.
#### Arguments
-| Name | Type | Description |
-| ---- | --------------------------- | ---------------------------------------------------- |
+| Name | Type | Description |
+| ---- | --------------------------------- | ---------------------------------------------------- |
| `ix` | [Interaction](api.md#interaction) | transaction, either in form of a Promise or function |
#### Returns
-| Type | Description |
-| --------------------------------------- | ------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Transaction result |
#### Usage
@@ -114,9 +107,8 @@ describe("interactions - sendTransaction", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- return emulator.start(port);
+ await init(basePath);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
@@ -156,14 +148,14 @@ Ensure interaction resolves without throwing errors.
#### Arguments
-| Name | Type | Description |
-| ---- | --------------------------- | ---------------------------------------------------- |
+| Name | Type | Description |
+| ---- | --------------------------------- | ---------------------------------------------------- |
| `ix` | [Interaction](api.md#interaction) | interaction, either in form of a Promise or function |
#### Returns
-| Type | Description |
-| --------------------------------------- | ------------------ |
+| Type | Description |
+| --------------------------------------------------------------------------- | ------------------ |
| [ResponseObject](https://docs.onflow.org/fcl/reference/api/#responseobject) | Transaction result |
#### Usage
@@ -179,9 +171,8 @@ describe("interactions - sendTransaction", () => {
// Instantiate emulator and path to Cadence files
beforeEach(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- return emulator.start(port);
+ await init(basePath);
+ return emulator.start();
});
// Stop emulator, so it could be restarted
diff --git a/docs/send-transactions.md b/docs/send-transactions.md
index fda4ee4f..ef93398f 100644
--- a/docs/send-transactions.md
+++ b/docs/send-transactions.md
@@ -17,12 +17,12 @@ Provides explicit control over how you pass values.
`props` object accepts following fields:
-| Name | Type | Optional | Description |
-| ------------ | ------------------------------ | -------- | ---------------------------------------------------------------------------------------------------- |
-| `code` | string | ✅ | string representation of Cadence transaction |
-| `name` | string | ✅ | name of the file in `transaction` folder to use (sans `.cdc` extension) |
-| `args` | [Any] | ✅ | an array of arguments to pass to transaction. Optional if transaction does not expect any arguments. |
-| `signers` | [Address] | ✅ | an array of [Address](#Address) representing transaction autorizers |
+| Name | Type | Optional | Description |
+| ------------ | ------------------------------- | -------- | ---------------------------------------------------------------------------------------------------- |
+| `code` | string | ✅ | string representation of Cadence transaction |
+| `name` | string | ✅ | name of the file in `transaction` folder to use (sans `.cdc` extension) |
+| `args` | [Any] | ✅ | an array of arguments to pass to transaction. Optional if transaction does not expect any arguments. |
+| `signers` | [Address] | ✅ | an array of [Address](#Address) representing transaction autorizers |
| `addressMap` | [AddressMap](api.md#addressmap) | ✅ | name/address map to use as lookup table for addresses in import statements |
> ⚠️ **Required:** Either `code` or `name` field shall be specified. Method will throw an error if both of them are empty.
@@ -41,12 +41,11 @@ import { init, emulator, sendTransaction, getAccountAddress } from "flow-js-test
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
// Init framework
- await init(basePath, { port });
+ await init(basePath);
// Start emulator
- await emulator.start(port);
+ await emulator.start();
// Define code and arguments we want to pass
const code = `
@@ -62,7 +61,7 @@ const main = async () => {
const [tx, error] = await sendTransaction({ code, args, signers });
console.log(tx, error);
-
+
// Stop emulator instance
await emulator.stop();
};
@@ -89,12 +88,11 @@ import { init, emulator, sendTransaction } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
// Init framework
- await init(basePath, { port });
+ await init(basePath);
// Start emulator
- await emulator.start(port);
+ await emulator.start();
// Define arguments we want to pass
const args = ["Hello, Cadence"];
diff --git a/docs/templates.md b/docs/templates.md
index 79dc2eca..449649c9 100644
--- a/docs/templates.md
+++ b/docs/templates.md
@@ -13,11 +13,11 @@ them here as well.
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 |
+| 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](./api.md#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` |
+| `byAddress` | boolean | ✅ | whether addressMap is `{name:address}` or `{address:address}` type. Default: `false` |
#### Returns
@@ -48,9 +48,9 @@ Returns Cadence template from file with `name` in `_basepath_/contracts` folder
#### Arguments
-| Name | Type | Optional | Description |
-| ------------ | ------------------------------ | -------- | ---------------------------------------------------------------- |
-| `name` | string | | name of the contract template |
+| Name | Type | Optional | Description |
+| ------------ | --------------------------------- | -------- | ---------------------------------------------------------------- |
+| `name` | string | | name of the contract template |
| `addressMap` | [AddressMap](./api.md#addressmap) | ✅ | object to use for address mapping of existing deployed contracts |
#### Returns
@@ -67,10 +67,9 @@ import { init, emulator, getContractCode } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// Let's assume we need to import MessageContract
await deployContractByName({ name: "MessageContract" });
@@ -94,9 +93,9 @@ Returns Cadence template from file with `name` in `_basepath_/transactions` fold
#### Arguments
-| Name | Type | Optional | Description |
-| ------------ | ------------------------------ | -------- | ---------------------------------------------------------------- |
-| `name` | string | | name of the transaction template |
+| Name | Type | Optional | Description |
+| ------------ | --------------------------------- | -------- | ---------------------------------------------------------------- |
+| `name` | string | | name of the transaction template |
| `addressMap` | [AddressMap](./api.md#addressmap) | ✅ | object to use for address mapping of existing deployed contracts |
#### Returns
@@ -113,10 +112,9 @@ import { init, emulator, getTransactionCode } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// Let's assume we need to import MessageContract
await deployContractByName({ name: "MessageContract" });
@@ -141,9 +139,9 @@ Returns Cadence template from file with `name` in `_basepath_/scripts` folder
#### Arguments
-| Name | Type | Optional | Description |
-| ------------ | ------------------------------ | -------- | ---------------------------------------------------------------- |
-| `name` | string | | name of the script template |
+| Name | Type | Optional | Description |
+| ------------ | --------------------------------- | -------- | ---------------------------------------------------------------- |
+| `name` | string | | name of the script template |
| `addressMap` | [AddressMap](./api.md#addressmap) | ✅ | object to use for address mapping of existing deployed contracts |
#### Returns
@@ -160,10 +158,9 @@ import { init, emulator, getScriptCode } from "flow-js-testing";
const main = async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// Let's assume we need to import MessageContract
await deployContractByName({ name: "MessageContract" });
diff --git a/examples/01-get-account-address.js b/examples/01-get-account-address.js
index 31b7777c..88d8cfe1 100644
--- a/examples/01-get-account-address.js
+++ b/examples/01-get-account-address.js
@@ -1,15 +1,14 @@
-import path from "path"
+import path from "path";
import { init, emulator, getAccountAddress } from "../src";
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
const Alice = await getAccountAddress("Alice");
console.log({ Alice });
await emulator.stop();
-})();
\ No newline at end of file
+})();
diff --git a/examples/02-deploy-contract-by-name.js b/examples/02-deploy-contract-by-name.js
index f8fb4273..16fa95ba 100644
--- a/examples/02-deploy-contract-by-name.js
+++ b/examples/02-deploy-contract-by-name.js
@@ -4,11 +4,10 @@ import { init, emulator, deployContractByName, executeScript } from "../src";
(async () => {
// Init framework
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
+ await init(basePath);
// Start Emulator
- await emulator.start(port);
+ await emulator.start();
// Deploy contract Greeting with single argument
await deployContractByName({
diff --git a/examples/03-deploy-contract.js b/examples/03-deploy-contract.js
index 143bccc7..79e36252 100644
--- a/examples/03-deploy-contract.js
+++ b/examples/03-deploy-contract.js
@@ -3,10 +3,9 @@ import { init, emulator, getAccountAddress, deployContract, executeScript } from
(async () => {
const basePath = path.resolve(__dirname, "../cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// We can specify, which account will hold the contract
const to = await getAccountAddress("Alice");
diff --git a/examples/04-get-contract-address.js b/examples/04-get-contract-address.js
index 10c820fe..fab9e476 100644
--- a/examples/04-get-contract-address.js
+++ b/examples/04-get-contract-address.js
@@ -3,10 +3,9 @@ import { init, emulator, deployContractByName, getContractAddress } from "../src
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// if we omit "to" it will be deployed to Service Account
// but let's pretend we don't know where it will be deployed :)
diff --git a/examples/05-emulator-management.js b/examples/05-emulator-management.js
index 8ff35688..81c525af 100644
--- a/examples/05-emulator-management.js
+++ b/examples/05-emulator-management.js
@@ -3,7 +3,6 @@ import { emulator, init, executeScript } from "../src";
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
await init(basePath);
// Let's define simple method to log message to emulator console
@@ -25,8 +24,8 @@ import { emulator, init, executeScript } from "../src";
// emulator.addFilter("service");
emulator.addFilter("info");
- // Start emulator instance on port 8080
- await emulator.start(port, { logging });
+ // Start emulator instance on available ports
+ await emulator.start({ logging });
// This line will be visible in emulator output
emulator.setLogging(true);
diff --git a/examples/06-flow-management.js b/examples/06-flow-management.js
index bde7940f..0b51602f 100644
--- a/examples/06-flow-management.js
+++ b/examples/06-flow-management.js
@@ -3,10 +3,9 @@ import { init, emulator, getAccountAddress, getFlowBalance, mintFlow } from "../
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// Get address for account with alias "Alice"
const Alice = await getAccountAddress("Alice");
diff --git a/examples/07-block-offset.js b/examples/07-block-offset.js
index 9a8765cb..bdff5a2d 100644
--- a/examples/07-block-offset.js
+++ b/examples/07-block-offset.js
@@ -10,10 +10,9 @@ import {
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
const [initialBlockOffset] = await getBlockOffset();
console.log({ initialBlockOffset });
diff --git a/examples/08-execute-script.js b/examples/08-execute-script.js
index b27c4b8b..39078bba 100644
--- a/examples/08-execute-script.js
+++ b/examples/08-execute-script.js
@@ -3,10 +3,9 @@ import { init, emulator, executeScript } from "../src";
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
// We have created a file called "log-args.cdc" under "./cadence/scripts" folder.
// It's available for use since we configured framework to use "./cadence" folder as root
@@ -45,7 +44,7 @@ import { init, emulator, executeScript } from "../src";
// "executeScript" also supports short form, accepting name of the file in "scripts folder
// and array of arguments
- const [shortForm] = await executeScript("hello")
+ const [shortForm] = await executeScript("hello");
console.log({ shortForm });
await emulator.stop();
diff --git a/examples/09-send-transaction.js b/examples/09-send-transaction.js
index fdd82d4d..1145bea3 100644
--- a/examples/09-send-transaction.js
+++ b/examples/09-send-transaction.js
@@ -3,10 +3,9 @@ import { init, emulator, getAccountAddress, sendTransaction } from "../src";
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port, true);
+ await init(basePath);
+ await emulator.start();
emulator.addFilter(`debug`);
diff --git a/examples/10-templates.js b/examples/10-templates.js
index dd603031..491d0680 100644
--- a/examples/10-templates.js
+++ b/examples/10-templates.js
@@ -10,10 +10,9 @@ import {
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
const addressMap = {
Profile: "0xf8d6e0586b0a20c7",
diff --git a/examples/100-pass-array-of-dictionaries.js b/examples/100-pass-array-of-dictionaries.js
index dace09e2..39ac5372 100644
--- a/examples/100-pass-array-of-dictionaries.js
+++ b/examples/100-pass-array-of-dictionaries.js
@@ -1,16 +1,11 @@
import path from "path";
-import {
- init,
- emulator,
- executeScript,
-} from "../src";
+import { init, emulator, executeScript } from "../src";
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
const code = `
pub fun main(meta: [{String:String}], key: String): String?{
@@ -24,7 +19,7 @@ import {
nickname: "Giorgio",
},
],
- "name"
+ "name",
];
const result = await executeScript({ code, args });
diff --git a/examples/101-pass-int-dictionary.js b/examples/101-pass-int-dictionary.js
index c5f9bea7..4fda5210 100644
--- a/examples/101-pass-int-dictionary.js
+++ b/examples/101-pass-int-dictionary.js
@@ -3,10 +3,9 @@ import { init, emulator, executeScript } from "../src";
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
const code = `
pub fun main(data: {UInt32: UInt32}, key: UInt32): UInt32?{
diff --git a/examples/102-pass-string-to-int-dictionary.js b/examples/102-pass-string-to-int-dictionary.js
index 680e29b3..92edaf7d 100644
--- a/examples/102-pass-string-to-int-dictionary.js
+++ b/examples/102-pass-string-to-int-dictionary.js
@@ -3,10 +3,9 @@ import { init, emulator, executeScript } from "../src";
(async () => {
const basePath = path.resolve(__dirname, "./cadence");
- const port = 8080;
- await init(basePath, { port });
- await emulator.start(port);
+ await init(basePath);
+ await emulator.start();
const code = `
pub fun main(data: {String: UInt32}, key: String): UInt32?{
@@ -14,7 +13,7 @@ import { init, emulator, executeScript } from "../src";
}
`;
- const args = [{ "cadence": 0, "test": 1337 }, "cadence"];
+ const args = [{ cadence: 0, test: 1337 }, "cadence"];
const [result] = await executeScript({ code, args });
console.log({ result });
diff --git a/flow.json b/flow.json
index 6cb72570..16248416 100644
--- a/flow.json
+++ b/flow.json
@@ -1,21 +1,21 @@
{
- "emulators": {
- "default": {
- "port": 3569,
- "serviceAccount": "emulator-account"
- }
- },
- "contracts": {},
- "networks": {
- "emulator": "127.0.0.1:3569",
- "mainnet": "access.mainnet.nodes.onflow.org:9000",
- "testnet": "access.devnet.nodes.onflow.org:9000"
- },
- "accounts": {
- "emulator-account": {
- "address": "f8d6e0586b0a20c7",
- "key": "f9cd76bf71c3371c76743ff22a0a1ee6657c63c46c62bd86a20266471fe0ea70"
- }
- },
- "deployments": {}
-}
\ No newline at end of file
+ "emulators": {
+ "default": {
+ "port": 3569,
+ "serviceAccount": "emulator-account"
+ }
+ },
+ "contracts": {},
+ "networks": {
+ "emulator": "127.0.0.1:3569",
+ "mainnet": "access.mainnet.nodes.onflow.org:9000",
+ "testnet": "access.devnet.nodes.onflow.org:9000"
+ },
+ "accounts": {
+ "emulator-account": {
+ "address": "f8d6e0586b0a20c7",
+ "key": "f9cd76bf71c3371c76743ff22a0a1ee6657c63c46c62bd86a20266471fe0ea70"
+ }
+ },
+ "deployments": {}
+}
diff --git a/src/cli/templates/test.js b/src/cli/templates/test.js
index 2c5219a7..32107bb7 100644
--- a/src/cli/templates/test.js
+++ b/src/cli/templates/test.js
@@ -28,13 +28,10 @@ describe("${name}", ()=>{
? "\n\t\t// You can specify different port to parallelize execution of describe blocks"
: ""
}
- const port = 8080; ${
- comments ? "\n\t\t// Setting logging flag to true will pipe emulator output to console" : ""
- }
const logging = false;
- await init(basePath, { port });
- return emulator.start(port, logging);
+ await init(basePath);
+ return emulator.start({ logging });
});
${comments ? "\n // Stop emulator, so it could be restarted" : ""}
afterEach(async () => {
diff --git a/src/emulator.js b/src/emulator.js
index 70e6ed4d..677f8476 100644
--- a/src/emulator.js
+++ b/src/emulator.js
@@ -17,6 +17,7 @@
*/
import { send, build, getBlock, decode } from "@onflow/fcl";
import { config } from "@onflow/config";
+import { getAvailablePorts } from "./utils";
const { spawn } = require("child_process");
@@ -24,12 +25,12 @@ const DEFAULT_HTTP_PORT = 8080;
const DEFAULT_GRPC_PORT = 3569;
const print = {
- "log": console.log,
- "service": console.log,
- "info": console.log,
- "error": console.error,
- "warn": console.warn
-}
+ log: console.log,
+ service: console.log,
+ info: console.log,
+ error: console.error,
+ warn: console.warn,
+};
/** Class representing emulator */
export class Emulator {
@@ -62,12 +63,12 @@ export class Emulator {
}
}
- checkLevel(message, level){
- if(level === "debug"){
+ checkLevel(message, level) {
+ if (level === "debug") {
// We might need to find a better way for this, but this will do for now...
- return message.includes("LOG") ? "log" : level
+ return message.includes("LOG") ? "log" : level;
}
- return level
+ return level;
}
extractKeyValue(str) {
@@ -104,21 +105,40 @@ export class Emulator {
* @param {boolean} logging - whether logs shall be printed
* @returns Promise<*>
*/
- async start(port = DEFAULT_HTTP_PORT, options = {}) {
- // config access node
- config().put("accessNode.api", `http://localhost:${port}`);
+ async start(options = {}) {
+ // populate emulator ports with available ports
+ [this.grpcPort, this.restPort, this.adminPort] = await getAvailablePorts(3);
+
+ // override ports if specified in options
+ this.grpcPort = options.grpcPort || this.grpcPort;
+ this.restPort = options.restPort || this.restPort;
+ this.adminPort = options.adminPort || this.adminPort;
+
+ // Support deprecated start call using static port
+ if (arguments.length > 1 || typeof arguments[0] === "number") {
+ console.warn(`Calling emulator.start with the port argument is now deprecated in favour of dynamically selected ports and will be removed in future versions of flow-js-testing.
+Please refrain from supplying this argument, as using it may cause unintended consequences.
+More info: https://github.com/onflow/flow-js-testing/blob/master/TRANSITIONS.md#001-deprecate-emulatorstart-port-argument`);
+
+ [this.adminPort, options = {}] = arguments;
+
+ const offset = this.adminPort - DEFAULT_HTTP_PORT;
+ this.grpcPort = DEFAULT_GRPC_PORT + offset;
+ }
const { flags = "", logging = false } = options;
- const offset = port - DEFAULT_HTTP_PORT;
- let grpc = DEFAULT_GRPC_PORT + offset;
+
+ // config access node
+ config().put("accessNode.api", `http://localhost:${this.adminPort}`);
this.logging = logging;
this.process = spawn("flow", [
"emulator",
"--verbose",
`--log-format=JSON`,
- `--admin-port=${port}`,
- `--port=${grpc}`,
+ `--rest-port=${this.restPort}`,
+ `--admin-port=${this.adminPort}`,
+ `--port=${this.grpcPort}`,
flags,
]);
this.logProcessor = (item) => item;
@@ -146,7 +166,7 @@ export class Emulator {
});
}
for (let i = 0; i < filtered.length; i++) {
- const item = data[i]
+ const item = data[i];
const { msg } = item;
const level = this.checkLevel(msg, item.level);
this.log(`${level.toUpperCase()}: ${msg}`);
@@ -159,7 +179,7 @@ export class Emulator {
this.log(`${level.toUpperCase()}: ${msg}`);
// TODO: Fix this
// This is really hacky solution, which depends on specific phrasing
- if (msg.includes("Starting") && msg.includes(port)) {
+ if (msg.includes("Starting") && msg.includes(this.adminPort)) {
this.log("EMULATOR IS UP! Listening for events!");
}
}
diff --git a/src/init.js b/src/init.js
index 2201e06b..eafe17ad 100644
--- a/src/init.js
+++ b/src/init.js
@@ -17,7 +17,6 @@
*/
import { set } from "./config";
-import { config } from "@onflow/config";
/**
* Inits framework variables, storing private key of service account and base path
@@ -27,7 +26,6 @@ import { config } from "@onflow/config";
* @param {number} [props.pkey] - private key to use for service account in case of collisions
*/
export const init = async (basePath, props = {}) => {
- const { port } = props;
const { pkey = "48a1f554aeebf6bf9fe0d7b5b79d080700b073ee77909973ea0b2f6fbc902" } = props;
set("PRIVATE_KEY", process.env.PK, "accounts/emulator-account/key", pkey);
@@ -38,9 +36,4 @@ export const init = async (basePath, props = {}) => {
"f8d6e0586b0a20c7",
);
set("BASE_PATH", process.env.BASE_PATH, "testing/paths", basePath);
-
- // Only set port if it was passed as argument
- if (port) {
- config().put("accessNode.api", `http://localhost:${port}`);
- }
};
diff --git a/src/utils.js b/src/utils.js
index f3d7bec7..75922bbc 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -16,4 +16,20 @@
* limitations under the License.
*/
+import { createServer } from "net";
+
export const isObject = (arg) => typeof arg === "object" && arg !== null;
+
+export function getAvailablePorts(count = 1) {
+ if (count === 0) return Promise.resolve([]);
+ return new Promise((resolve, reject) => {
+ const server = createServer();
+ server.listen(0, () => {
+ const port = server.address().port;
+ server.close(async (err) => {
+ if (err) reject(err);
+ resolve([...(await getAvailablePorts(count - 1)), port]);
+ });
+ });
+ });
+}