Skip to content

Instantly share code, notes, and snippets.

@the-vampiire
Last active February 2, 2022 19:54
Show Gist options
  • Save the-vampiire/d997df81750537f58d91aa14984c5614 to your computer and use it in GitHub Desktop.
Save the-vampiire/d997df81750537f58d91aa14984c5614 to your computer and use it in GitHub Desktop.
algorand sandbox global jest setup consistent test accounts
# using algorand sandbox
# https://github.com/algorand/sandbox
ALGORAND_ALGOD_API_BASE_URL=http://localhost
ALGORAND_ALGOD_API_PORT=4001
ALGORAND_ALGOD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
ALGORAND_KMD_API_BASE_URL=http://localhost
ALGORAND_KMD_API_PORT=4002
ALGORAND_KMD_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
ALGORAND_INDEXER_API_BASE_URL=http://localhost
ALGORAND_INDEXER_API_PORT=8980
ALGORAND_INDEXER_TOKEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
# optional
# how many test accounts to create if not existing in projectRoot/test-env/accounts.json file
TEST_ACCOUNTS_COUNT=4,
# what the prefix should be for the test account env var
TEST_ACCOUNT_ENV_PREFIX=TEST_ACCOUNT_ADDRESS_
# other test env vars you need...

Usage

  1. create jest.config.js in project root
  2. create test-env/ dir in project root
  3. copy / clone setup.js, setup-test-accounts.js and .test.env into test-env/
  4. run jest tests

Requirements

Behavior

First time the global setup is run it will generate:

  • process.env.TEST_ACCOUNTS_COUNT accounts
  • write them to test-env/accounts.json for faster startup in the future

If you need more/less accounts just delete test-env/accounts.json and change TEST_ACCOUNTS_COUNT value then run your tests again (to repeat the above process for the new count).

Access

Test accounts will be accessible in jest tests by

assuming prefix is TEST_ACCOUNT_ADDRESS_

process.env.TEST_ACCOUNT_ADDRESS_0 // 0, 1, 2...up to TEST_ACCOUNTS_COUNT - 1

generic

// accountNumber = 0, 1, 2...up to TEST_ACCOUNTS_COUNT - 1
process.env[`${process.env.TEST_ACCOUNT_ENV_PREFIX}${accountNumber}`];

Optional

if you want to have a clean slate when running tests you can install docker-compose (NPM)

npm i -D docker-compose

and copy/clone the file test-env/reset-sandbox.js

make sure to update the path to your sandbox dir! the file currently assumes it is in projectRoot/algorand-sandbox

then update your test-env/setup.js file to utilize it

require("dotenv").config({ path: __dirname + "/.test.env" });

const resetSandbox = require("./reset-sandbox");
const setupTestAccounts = require("./setup-test-accounts");

module.exports = async () => {
  await resetSandbox();
  await setupTestAccounts();
};
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: 'ts-jest',
globalSetup: "<rootDir>/test-env/setup.js",
testPathIgnorePatterns: [".js"], // prevent duplicate tests of src/ (ts) and build/ (js)
watchPathIgnorePatterns: [".js"],
};
const path = require("path");
const dockerCompose = require("docker-compose");
const resetSandbox = async () => {
const cwd = path.join(__dirname, "../", "algorand-sandbox"); // set path relative to test-env dir!
console.log("resetting sandbox");
await dockerCompose.stop({ cwd });
await dockerCompose.rm({ cwd });
await dockerCompose.upAll({ cwd });
console.log("sandbox reset");
}
module.exports = resetSandbox;
require("dotenv").config({ path: __dirname + "/.test.env" })
const { writeFile } = require("fs/promises");
const { Kmd, generateAccount, secretKeyToMnemonic, mnemonicToSecretKey } = require("algosdk");
const assert = require("assert");
const {
ALGORAND_KMD_TOKEN,
ALGORAND_KMD_API_BASE_URL,
ALGORAND_KMD_API_PORT,
TEST_ACCOUNTS_COUNT = 4,
TEST_ACCOUNT_ENV_PREFIX = "TEST_ACCOUNT_ADDRESS_",
} = process.env;
const TEST_ACCOUNTS_TO_CREATE = Number(TEST_ACCOUNTS_COUNT);
const kmdClient = new Kmd(ALGORAND_KMD_TOKEN, ALGORAND_KMD_API_BASE_URL, ALGORAND_KMD_API_PORT);
const generateAccounts = (count) => Array.from({ length: count }).map(e => {
const { addr, sk } = generateAccount();
const mnemonic = secretKeyToMnemonic(sk);
return { address: addr, mnemonic };
});
const getTestAccounts = async () => {
try {
const testAccounts = require("./accounts.json");
return testAccounts;
} catch {
console.log(`accounts.json not found, generating ${TEST_ACCOUNTS_TO_CREATE} test accounts`);
}
const accounts = generateAccounts(TEST_ACCOUNTS_TO_CREATE);
await writeFile(__dirname + "/accounts.json", JSON.stringify(accounts, null, 2));
return accounts;
}
const getTestAddresses = async (testAccounts, walletHandleToken) => {
const { addresses } = await kmdClient.listKeys(walletHandleToken);
const testAddresses = addresses.filter(address => testAccounts.some(testAccount => testAccount.address === address));
if (testAddresses.length !== testAccounts.length) {
console.log("importing test accounts");
await Promise.all(
testAccounts.map(
account => {
const { sk } = mnemonicToSecretKey(account.mnemonic);
return kmdClient.importKey(walletHandleToken, sk);
}
)
);
return getTestAddresses(testAccounts, walletHandleToken);
}
console.log("test accounts imported");
return testAddresses;
}
const getKmdDefaultWalletHandle = async () => {
const [defaultWallet] = (await kmdClient.listWallets()).wallets;
const { wallet_handle_token: walletHandleToken } = await kmdClient.initWalletHandle(defaultWallet.id, "")
return walletHandleToken;
}
const loadTestAddressesIntoEnv = (testAddresses) => testAddresses.forEach((address, index) => {
const envVar = `${TEST_ACCOUNT_ENV_PREFIX}${index}`;
process.env[envVar] = address;
});
const assertTestAddressEnv = (testAddresses) => testAddresses.forEach((_, index) => {
const envVar = `${TEST_ACCOUNT_ENV_PREFIX}${index}`;
assert.notEqual(process.env[envVar], undefined, `Test account address env var [${envVar}] not set`);
});
const setupTestAccounts = async () => {
const testAccounts = await getTestAccounts();
const defaultWalletHandleToken = await getKmdDefaultWalletHandle();
const testAddresses = await getTestAddresses(testAccounts, defaultWalletHandleToken);
loadTestAddressesIntoEnv(testAddresses);
assertTestAddressEnv(testAddresses);
console.log("all test account addresses imported into env!");
};
module.exports = setupTestAccounts;
require("dotenv").config({ path: __dirname + "/.test.env" });
const setupTestAccounts = require("./setup-test-accounts");
module.exports = async () => {
await setupTestAccounts();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment