Skip to content

Commit

Permalink
Adds tests for Near.call (#25)
Browse files Browse the repository at this point in the history
* init tests

* adds tests for vm custom elements

* fix structure for video, update pause method

* wip

* wip

* passing unhappy paths

* renames

* happy path tests

* validates more transaction details
  • Loading branch information
elliotBraem authored Jul 9, 2024
1 parent b10c132 commit e8070a2
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 0 deletions.
7 changes: 7 additions & 0 deletions playwright-tests/code/near-call/object-params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const { tx } = props;

function handleClick() {
Near.call(tx);
}

return <button onClick={handleClick}>click</button>;
13 changes: 13 additions & 0 deletions playwright-tests/code/near-call/positional-params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const { contractName, methodName, args, gas, deposit, extra } = props;

function handleClick() {
if (extra) {
Near.call(contractName, methodName, args, gas, deposit, extra);
} else if (contractName && !methodName && !args && !gas && !deposit) {
Near.call(contractName);
} else {
Near.call(contractName, methodName, args, gas, deposit);
}
}

return <button onClick={handleClick}>click</button>;
31 changes: 31 additions & 0 deletions playwright-tests/storage-states/wallet-connected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"cookies": [],
"origins": [
{
"origin": "http://localhost:3000",
"localStorage": [
{
"name": "near-wallet-selector:selectedWalletId",
"value": "\"my-near-wallet\""
},
{
"name": "near_app_wallet_auth_key",
"value": "{\"accountId\":\"anybody.near\",\"allKeys\":[\"ed25519:CziSGowWUKiP5N5pqGUgXCJXtqpySAk29YAU6zEs5RAi\"]}}"
},
{
"name": "near-social-vm:v01::accountId:",
"value": "anybody.near"
},
{
"name": "near-api-js:keystore:anybody.near:mainnet",
"value": "ed25519:67p9ygtfVNZz5AzMkeN4bqstCck8RWxWDthcTa7JaBvxkrBRTc6A43SsuPy9LdtiR6XtSRD1HiS4KQTWCZw83FKS"
},
{
"name": "near-wallet-selector:contract",
"value": "{\"contractId\":\"social.near\",\"methodNames\":[]}"
}
]
}
],
"sessionStorage": []
}
10 changes: 10 additions & 0 deletions playwright-tests/storage-states/wallet-not-connected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"cookies": [],
"origins": [
{
"origin": "http://localhost:3000",
"localStorage": []
}
],
"sessionStorage": []
}
27 changes: 27 additions & 0 deletions playwright-tests/testUtils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { expect } from "@playwright/test";
import path from "path";
import fs from "fs";

export const pauseIfVideoRecording = async (page) => {
let isVideoRecorded = (await page.video()) ? true : false;
Expand Down Expand Up @@ -40,3 +42,28 @@ export const escapeHtml = (html) => {
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
};

export const useCode = async (page, filePath, props) => {
const fullPath = path.join(__dirname, "code", filePath);
try {
const code = fs.readFileSync(fullPath, "utf8");
const initialProps = props ? JSON.stringify(props) : "";

// Set code and initialProps attribute
await page.evaluate(
({ code, initialProps }) => {
const viewer = document.querySelector("near-social-viewer");
viewer.setAttribute("code", code);
viewer.setAttribute("initialprops", initialProps);
},
{ code, initialProps }
);

// Verify the viewer is visible
await waitForSelectorToBeVisible(page, "near-social-viewer");

await pauseIfVideoRecording(page);
} catch (err) {
throw new Error(`Error loading file: ${err.message}`);
}
};
216 changes: 216 additions & 0 deletions playwright-tests/tests/vm/near-call.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import { describe, expect, test } from "@playwright/test";
import { pauseIfVideoRecording, useCode } from "../../testUtils";

describe("Near.call", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/");
});

describe("User is not logged in", () => {
test.use({
storageState: "playwright-tests/storage-states/wallet-not-connected.json",
});

test("should throw 'No wallet selected' error", async ({ page }) => {
const expectedErrorMessage = "No wallet selected";

await useCode(page, "near-call/positional-params.js", {
contractName: "hello.near-examples.near",
methodName: "set_greeting",
});

// Expect error message to be displayed
const [error] = await Promise.all([
page.waitForEvent("pageerror"),
await page.getByRole("button", { name: "click" }).click(),
]);

await pauseIfVideoRecording(page);

// Verify that the expected error message was logged
expect(error).toBeTruthy();
expect(error.message).toContain(expectedErrorMessage);
});
});

describe("User is logged in", () => {
test.use({
storageState: "playwright-tests/storage-states/wallet-connected.json",
});

describe("arguments: (contractName, methodName, args?, gas?, deposit?)", () => {
test("should throw error if appropriate arguments are not provide (over 5 args)", async ({
page,
}) => {
const expectedErrorMessage =
"Method: Near.call. Required argument: 'contractName'. If the first argument is a string: 'methodName'. Optional: 'args', 'gas' (defaults to 300Tg), 'deposit' (defaults to 0)";

await useCode(page, "near-call/positional-params.js", {
contractName: "hello.near-examples.near",
methodName: "set_greeting",
args: { message: "Hello, World!" },
gas: "300000000000000",
deposit: "1000000000000000000000000",
extra: "extra argument",
});

// Expect error message to be displayed
const [error] = await Promise.all([
page.waitForEvent("pageerror"),
await page.getByRole("button", { name: "click" }).click(),
]);

await pauseIfVideoRecording(page);

// Verify that the expected error message was logged
expect(error).toBeTruthy();
expect(error.message).toContain(expectedErrorMessage);
});
test("should open confirmation modal with appropriate details", async ({
page,
}) => {
const expectedTransactionData = { message: "Hello, World!" };

await useCode(page, "near-call/positional-params.js", {
contractName: "hello.near-examples.near",
methodName: "set_greeting",
args: { message: "Hello, World!" },
gas: "300000000000000",
deposit: "1000000000000000000000000",
});

await page.getByRole("button", { name: "click" }).click();

const transactionObj = JSON.parse(
await page.locator("div.modal-body code").innerText()
);

await pauseIfVideoRecording(page);

// do something with transactionObj
expect(transactionObj).toMatchObject(expectedTransactionData);
});
});

describe("arguments: ({ tx })", () => {
test("should throw error if transaction object argument is invalid (single string provided)", async ({
page,
}) => {
const expectedErrorMessage =
"Method: Near.call. Required argument: 'tx/txs'. A single argument call requires an TX object or an array of TX objects.";

await useCode(page, "near-call/positional-params.js", {
contractName: "hello.near-examples.near",
});

// Expect error message to be displayed
const [error] = await Promise.all([
page.waitForEvent("pageerror"),
await page.getByRole("button", { name: "click" }).click(),
]);

await pauseIfVideoRecording(page);

// Verify that the expected error message was logged
expect(error).toBeTruthy();
expect(error.message).toContain(expectedErrorMessage);
});
test("should open confirmation modal with appropriate details", async ({
page,
}) => {
const expectedTransactionData = { message: "Hello, World!" };

await useCode(page, "near-call/object-params.js", {
tx: {
contractName: "hello.near-examples.near",
methodName: "set_greeting",
args: { message: "Hello, World!" },
gas: "300000000000000",
deposit: "1000000000000000000000000",
},
});

await page.getByRole("button", { name: "click" }).click();

const transactionObj = JSON.parse(
await page.locator("div.modal-body code").innerText()
);
const modalBody = await page.locator(".modal-body");
const transactionNumber = await modalBody.locator("h4").textContent();
const values = await modalBody
.locator(".font-monospace")
.allInnerTexts();
const [contractId, methodName, deposit, gas] = values;

await pauseIfVideoRecording(page);

// do something with transactionObj
expect(transactionObj).toMatchObject(expectedTransactionData);
expect(transactionNumber).toBe("Transaction #1");
expect(contractId).toBe("hello.near-examples.near");
expect(methodName).toBe("set_greeting");
expect(deposit).toBe("1 NEAR");
expect(gas).toBe("300 TGas");
});
});

describe("arguments: [{ tx }, ...]", () => {
test("should open confirmation modal with appropriate details, multiple transactions", async ({
page,
}) => {
await useCode(page, "near-call/object-params.js", {
tx: [
{
contractName: "hello.near-examples.near",
methodName: "set_greeting",
args: { message: "Hello, World!" },
gas: "300000000000000",
deposit: "1000000000000000000000000",
},
{
contractName: "goodbye.near-examples.near",
methodName: "set_goobye",
args: { message: "Goodbye, World!" },
gas: "600000000000000",
deposit: "2000000000000000000000000",
},
],
});

await page.getByRole("button", { name: "click" }).click();

const blocks = await page
.locator("div.modal-body code")
.allInnerTexts();
const modalBody = await page.locator(".modal-body");
const transactionNumbers = await modalBody.locator("h4").allInnerTexts();
const values = await modalBody
.locator(".font-monospace")
.allInnerTexts();

const [firstBlock, secondBlock] = blocks;

await pauseIfVideoRecording(page);

expect(transactionNumbers).toEqual(["Transaction #1", "Transaction #2"]);
expect(values).toEqual([
"hello.near-examples.near",
"set_greeting",
"1 NEAR",
"300 TGas",
"goodbye.near-examples.near",
"set_goobye",
"2 NEAR",
"600 TGas",
]);

expect(JSON.parse(firstBlock)).toMatchObject({
message: "Hello, World!",
});
expect(JSON.parse(secondBlock)).toMatchObject({
message: "Goodbye, World!",
});
});
});
});
});

0 comments on commit e8070a2

Please sign in to comment.