Skip to content

Commit d0ebfcb

Browse files
Add Cypress E2E tests for core functionality across multiple networks (#140)
1 parent ccbb715 commit d0ebfcb

File tree

15 files changed

+1866
-12
lines changed

15 files changed

+1866
-12
lines changed

.github/workflows/test-app.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: E2E on Chrome
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
cypress-run:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Cypress run
19+
uses: cypress-io/github-action@v6
20+
with:
21+
working-directory: packages/nextjs
22+
browser: chrome
23+
start: yarn dev
24+
wait-on: "http://localhost:3000"
25+
env:
26+
NEXT_PUBLIC_HEIMDALL_URL: "${{ secrets.HEIMDALL_URL }}"
27+
CYPRESS_HEIMDALL_URL: "${{ secrets.HEIMDALL_URL }}"
28+

README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,63 @@ yarn start
4242

4343
Visit your local instance of ABI Ninja at: `http://localhost:3000`.
4444

45+
# 🧪 Testing
46+
47+
ABI Ninja uses Cypress for end-to-end testing. Our test suite covers user flows and ensures the application works correctly across different networks and contract types. The test suite will automatically run on pull requests.
48+
49+
## Setting Up Cypress Environment
50+
51+
Before running the tests, you need to set up your Cypress environment:
52+
53+
1. Copy the example environment file:
54+
55+
```
56+
cp cypress.env.example.json cypress.env.json
57+
```
58+
59+
2. Edit `cypress.env.json` and fill in heimdall_url
60+
61+
62+
## Running Tests
63+
64+
To run the Cypress tests:
65+
66+
1. Ensure your development server is running:
67+
68+
```
69+
yarn start
70+
```
71+
72+
2. In a new terminal window, run the Cypress tests:
73+
74+
```
75+
yarn cypress:open
76+
```
77+
78+
This will open the Cypress Test Runner, where you can run individual tests or the entire suite.
79+
80+
3. For headless testing, use:
81+
82+
```
83+
yarn cypress:run
84+
```
85+
86+
## Test Coverage
87+
88+
Our tests cover the following key areas:
89+
90+
- Loading and interacting with verified contracts on various networks
91+
- Handling unverified contracts and manual ABI input
92+
- Detecting and interacting with proxy contracts
93+
- Network switching and custom network addition
94+
95+
## Writing New Tests
96+
97+
When adding new features or modifying existing ones, please update or add corresponding tests. Test files are located in the `cypress/e2e` directory.
98+
99+
For more information on writing Cypress tests, refer to the Cypress Documentation.
100+
101+
45102
## Contributing to ABI Ninja
46103

47104
We welcome contributions to ABI Ninja!

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
"postinstall": "husky install",
1616
"precommit": "lint-staged",
1717
"vercel": "yarn workspace @se-2/nextjs vercel",
18-
"vercel:yolo": "yarn workspace @se-2/nextjs vercel:yolo"
18+
"vercel:yolo": "yarn workspace @se-2/nextjs vercel:yolo",
19+
"cypress:open": "yarn workspace @se-2/nextjs cypress:open",
20+
"cypress:run": "yarn workspace @se-2/nextjs cypress:run"
1921
},
2022
"packageManager": "yarn@3.2.3",
2123
"devDependencies": {

packages/nextjs/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,9 @@ yarn-error.log*
3434
# vercel
3535
.vercel
3636

37+
# Cypress
38+
cypress/downloads/
39+
cypress.env.json
40+
3741
# typescript
3842
*.tsbuildinfo

packages/nextjs/cypress.config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { defineConfig } from "cypress";
2+
3+
export default defineConfig({
4+
e2e: {
5+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
6+
setupNodeEvents(on, config) {
7+
// implement node event listeners here
8+
},
9+
},
10+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"HEIMDALL_URL": ""
3+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
describe("Contract Interaction", () => {
2+
it("should load DAI contract and interact with its balanceOf method", () => {
3+
cy.visit("http://localhost:3000");
4+
cy.loadContract("0x6B175474E89094C44Da98b954EedeAC495271d0F");
5+
cy.url().should("include", "/0x6B175474E89094C44Da98b954EedeAC495271d0F/1");
6+
cy.interactWithMethod("balanceOf", "0x6B175474E89094C44Da98b954EedeAC495271d0F");
7+
});
8+
9+
it("should load proxy contract on Base and interact with its balanceOf method", () => {
10+
cy.visit("http://localhost:3000");
11+
cy.selectNetwork("Base");
12+
cy.loadContract("0xca808b3eada02d53073e129b25f74b31d8647ae0");
13+
cy.url().should("include", "/0xca808b3eada02d53073e129b25f74b31d8647ae0/8453");
14+
cy.contains("Implementation Address").should("be.visible");
15+
cy.wait(1000); // wait for: the method card to re-render
16+
cy.interactWithMethod("balanceOf", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
17+
});
18+
19+
it("should load unverified contract on Sepolia and ADD changeOwner write method to the UI", () => {
20+
cy.wakeUpHeimdall();
21+
cy.visit("http://localhost:3000");
22+
cy.selectNetwork("Sepolia");
23+
cy.get('input[placeholder="Contract address"]').type("0x759c0e9d7858566df8ab751026bedce462ff42df");
24+
cy.get("button:visible").contains("Decompile (beta)", { timeout: 10000 }).click({ force: true });
25+
cy.wait(2000);
26+
cy.url().should("include", "/0x759c0e9d7858566df8ab751026bedce462ff42df/11155111");
27+
cy.contains("changeOwner").click();
28+
});
29+
30+
it("should load a contract on BNB Smart Chain and interact with its balanceOf method", () => {
31+
cy.visit("http://localhost:3000");
32+
cy.selectNetwork("Other chains");
33+
cy.get("#see-other-chains-modal").should("be.visible");
34+
cy.contains("BNB Smart Chain").click();
35+
cy.get(".modal-content").should("not.exist");
36+
cy.get("#react-select-container").should("contain", "BNB Smart Chain");
37+
cy.loadContract("0x2170ed0880ac9a755fd29b2688956bd959f933f8");
38+
cy.url().should("include", "/0x2170ed0880ac9a755fd29b2688956bd959f933f8/56");
39+
cy.get(".loading-spinner", { timeout: 10000 }).should("not.exist");
40+
cy.interactWithMethod("balanceOf", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
41+
});
42+
43+
it("should add Parex as a custom chain and interact with a contract by submitting an ABI manually", () => {
44+
cy.visit("http://localhost:3000");
45+
cy.addCustomChain({
46+
id: "322202",
47+
name: "Parex",
48+
nativeCurrencyName: "PAREX",
49+
nativeCurrencySymbol: "PAREX",
50+
nativeCurrencyDecimals: "18",
51+
rpcUrl: "https://mainnet-rpc.parex.network",
52+
blockExplorer: "https://scan.parex.network/",
53+
});
54+
cy.get("#react-select-container").should("contain", "Parex");
55+
cy.get('input[placeholder="Contract address"]').type("0x6058518142C6AD506530F5A62dCc58050bf6fC28");
56+
cy.fixture("parex_abi").then(parexContractABI => {
57+
cy.importABI(JSON.stringify(parexContractABI));
58+
});
59+
cy.url().should("include", "/0x6058518142C6AD506530F5A62dCc58050bf6fC28/322202");
60+
cy.get(".loading-spinner", { timeout: 10000 }).should("not.exist");
61+
cy.interactWithMethod("getUserBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
62+
});
63+
});

0 commit comments

Comments
 (0)