Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add browser test to canary flow #1808

Merged
merged 1 commit into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1133,10 +1133,10 @@ jobs:
- *checkout
- *setup_env
- run:
name: "Build and test"
name: "Build"
command: build canary true

run-deployment-canary:
run-deployment-canary-uniswap:
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small
Expand All @@ -1147,6 +1147,17 @@ jobs:
name: "Test"
command: spot_run_test_script ./scripts/run_tests canary uniswap_trade_on_l1_from_l2.test.ts canary docker-compose.yml

run-deployment-canary-browser:
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small
steps:
- *checkout
- *setup_env
- run:
name: "Test"
command: spot_run_test_script ./scripts/run_tests canary aztec_js_browser.test.test.ts canary docker-compose.yml

# Repeatable config for defining the workflow below.
tag_regex: &tag_regex /^v.*/
defaults: &defaults
Expand Down Expand Up @@ -1396,7 +1407,13 @@ workflows:
- deploy-end
<<: *deploy_defaults

- run-deployment-canary:
- run-deployment-canary-uniswap:
requires:
- build-deployment-canary
<<: *deploy_defaults

- run-deployment-canary-browser:
requires:
- build-deployment-canary
<<: *deploy_defaults

1 change: 1 addition & 0 deletions yarn-project/aztec.js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export {
PackedArguments,
PublicKey,
PrivateKey,
SyncStatus,
Tx,
TxExecutionRequest,
TxHash,
Expand Down
4 changes: 4 additions & 0 deletions yarn-project/canary/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@
"@aztec/noir-contracts": "workspace:^",
"@jest/globals": "^29.5.0",
"@types/jest": "^29.5.0",
"@types/koa-static": "^4.0.2",
"@types/node": "^18.7.23",
"jest": "^29.5.0",
"koa": "^2.14.2",
"koa-static": "^5.0.0",
"puppeteer": "^21.1.0",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.1",
"tslib": "^2.4.0",
Expand Down
216 changes: 216 additions & 0 deletions yarn-project/canary/src/aztec_js_browser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/* eslint-disable no-console */
import * as AztecJs from '@aztec/aztec.js';
import { AztecAddress, PrivateKey } from '@aztec/circuits.js';
import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
import { PrivateTokenContractAbi } from '@aztec/noir-contracts/artifacts';

import { Server } from 'http';
import Koa from 'koa';
import serve from 'koa-static';
import path, { dirname } from 'path';
import { Browser, Page, launch } from 'puppeteer';
import { fileURLToPath } from 'url';

declare global {
interface Window {
AztecJs: typeof AztecJs;
}
}

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const PORT = 3000;

const { SANDBOX_URL } = process.env;

const conditionalDescribe = () => (SANDBOX_URL ? describe : describe.skip);
const privKey = PrivateKey.random();

/**
* This test is a bit of a special case as it's relying on sandbox and web browser and not only on anvil and node.js.
* To run the test, do the following:
* 1) Build the whole repository,
* 2) go to `yarn-project/aztec.js` and build the web packed package with `yarn build:web`,
* 3) start anvil: `anvil`,
* 4) open new terminal and optionally set the more verbose debug level: `DEBUG=aztec:*`,
* 5) go to the sandbox dir `yarn-project/aztec-sandbox` and run `yarn start`,
* 6) open new terminal and export the sandbox URL: `export SANDBOX_URL='http://localhost:8080'`,
* 7) go to `yarn-project/end-to-end` and run the test: `yarn test aztec_js_browser`
*
* NOTE: If you see aztec-sandbox logs spammed with unexpected logs there is probably a chrome process with a webpage
* unexpectedly running in the background. Kill it with `killall chrome`
*/
conditionalDescribe()('e2e_aztec.js_browser', () => {
const initialBalance = 33n;
const transferAmount = 3n;

let contractAddress: AztecAddress;

let logger: DebugLogger;
let pageLogger: DebugLogger;
let app: Koa;
let testClient: AztecJs.AztecRPC;
let server: Server;

let browser: Browser;
let page: Page;

beforeAll(async () => {
testClient = AztecJs.createAztecRpcClient(SANDBOX_URL!, AztecJs.makeFetch([1, 2, 3], true));
await AztecJs.waitForSandbox(testClient);

app = new Koa();
app.use(serve(path.resolve(__dirname, './web')));
server = app.listen(PORT, () => {
logger(`Server started at http://localhost:${PORT}`);
});

logger = createDebugLogger('aztec:aztec.js:web');
pageLogger = createDebugLogger('aztec:aztec.js:web:page');

browser = await launch({
executablePath: process.env.CHROME_BIN,
headless: 'new',
args: [
'--allow-file-access-from-files',
'--no-sandbox',
'--headless',
'--disable-web-security',
'--disable-features=IsolateOrigins',
'--disable-site-isolation-trials',
'--disable-gpu',
'--disable-dev-shm-usage',
'--disk-cache-dir=/dev/null',
],
});
page = await browser.newPage();
page.on('console', msg => {
pageLogger(msg.text());
});
page.on('pageerror', err => {
pageLogger.error(err.toString());
});
await page.goto(`http://localhost:${PORT}/index.html`);
}, 120_000);

afterAll(async () => {
await browser.close();
server.close();
});

it('Loads Aztec.js in the browser', async () => {
const createAccountsExists = await page.evaluate(() => {
const { createAccounts } = window.AztecJs;
return typeof createAccounts === 'function';
});
expect(createAccountsExists).toBe(true);
});

it('Creates an account', async () => {
const result = await page.evaluate(
async (rpcUrl, privateKeyString) => {
const { PrivateKey, createAztecRpcClient, makeFetch, getUnsafeSchnorrAccount } = window.AztecJs;
const client = createAztecRpcClient(rpcUrl!, makeFetch([1, 2, 3], true));
const privateKey = PrivateKey.fromString(privateKeyString);
const account = getUnsafeSchnorrAccount(client, privateKey);
await account.waitDeploy();
const completeAddress = await account.getCompleteAddress();
const addressString = completeAddress.address.toString();
console.log(`Created Account: ${addressString}`);
return addressString;
},
SANDBOX_URL,
privKey.toString(),
);
const accounts = await testClient.getAccounts();
const stringAccounts = accounts.map(acc => acc.address.toString());
expect(stringAccounts.includes(result)).toBeTruthy();
}, 15_000);

it('Deploys Private Token contract', async () => {
await deployPrivateTokenContract();
}, 30_000);

it("Gets the owner's balance", async () => {
const result = await page.evaluate(
async (rpcUrl, contractAddress, PrivateTokenContractAbi) => {
const { Contract, AztecAddress, createAztecRpcClient, makeFetch } = window.AztecJs;
const client = createAztecRpcClient(rpcUrl!, makeFetch([1, 2, 3], true));
const owner = (await client.getAccounts())[0].address;
const wallet = await AztecJs.getSandboxAccountsWallet(client);
const contract = await Contract.at(AztecAddress.fromString(contractAddress), PrivateTokenContractAbi, wallet);
const balance = await contract.methods.getBalance(owner).view({ from: owner });
return balance;
},
SANDBOX_URL,
(await getPrivateTokenAddress()).toString(),
PrivateTokenContractAbi,
);
logger('Owner balance:', result);
expect(result).toEqual(initialBalance);
});

it('Sends a transfer TX', async () => {
const result = await page.evaluate(
async (rpcUrl, contractAddress, transferAmount, PrivateTokenContractAbi) => {
console.log(`Starting transfer tx`);
const { AztecAddress, Contract, createAztecRpcClient, makeFetch } = window.AztecJs;
const client = createAztecRpcClient(rpcUrl!, makeFetch([1, 2, 3], true));
const accounts = await client.getAccounts();
const owner = accounts[0].address;
const receiver = accounts[1].address;
const wallet = await AztecJs.getSandboxAccountsWallet(client);
const contract = await Contract.at(AztecAddress.fromString(contractAddress), PrivateTokenContractAbi, wallet);
await contract.methods.transfer(transferAmount, owner, receiver).send({ origin: owner }).wait();
console.log(`Transferred ${transferAmount} tokens to new Account`);
return await contract.methods.getBalance(receiver).view({ from: receiver });
},
SANDBOX_URL,
(await getPrivateTokenAddress()).toString(),
transferAmount,
PrivateTokenContractAbi,
);
expect(result).toEqual(transferAmount);
}, 60_000);

const deployPrivateTokenContract = async () => {
const txHash = await page.evaluate(
async (rpcUrl, privateKeyString, initialBalance, PrivateTokenContractAbi) => {
const { PrivateKey, DeployMethod, createAztecRpcClient, makeFetch, getUnsafeSchnorrAccount } = window.AztecJs;
const client = createAztecRpcClient(rpcUrl!, makeFetch([1, 2, 3], true));
let accounts = await client.getAccounts();
if (accounts.length === 0) {
// This test needs an account for deployment. We create one in case there is none available in the RPC server.
const privateKey = PrivateKey.fromString(privateKeyString);
await getUnsafeSchnorrAccount(client, privateKey).waitDeploy();
accounts = await client.getAccounts();
}
const owner = accounts[0];
const tx = new DeployMethod(owner.publicKey, client, PrivateTokenContractAbi, [
initialBalance,
owner.address,
]).send();
await tx.wait();
const receipt = await tx.getReceipt();
console.log(`Contract Deployed: ${receipt.contractAddress}`);
return receipt.txHash.toString();
},
SANDBOX_URL,
privKey.toString(),
initialBalance,
PrivateTokenContractAbi,
);

const txResult = await testClient.getTxReceipt(AztecJs.TxHash.fromString(txHash));
expect(txResult.status).toEqual(AztecJs.TxStatus.MINED);
contractAddress = txResult.contractAddress!;
};

const getPrivateTokenAddress = async () => {
if (!contractAddress) {
await deployPrivateTokenContract();
}
return contractAddress;
};
});
Loading