Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
29d2cb0
feat: init cli tests
itaven Nov 12, 2025
42fe360
fix: install order for test.yaml
itaven Nov 12, 2025
93ab03c
fix: wf's run's
itaven Nov 12, 2025
2a5988f
fix: add tsx devDependency for tests
itaven Nov 12, 2025
e1df114
fix: set jest test run directory
itaven Nov 12, 2025
cc30a97
fix: fix pw-report path
itaven Nov 12, 2025
640f88e
feat: update report config
itaven Nov 12, 2025
691ffed
feat: add type Address && install viem
itaven Nov 20, 2025
6eb2ab8
fix: misc review adjustments
itaven Nov 20, 2025
cd879d9
fix: global env usage for CLI commands && reuse runCLI command
itaven Nov 20, 2025
33fdfab
fix: remove debug tip for globalSetup.ts && update README.md
itaven Nov 20, 2025
739f37b
fix: review comments
itaven Dec 1, 2025
aeafdbe
Merge branch 'refs/heads/develop' into feat/init-cli-tests
itaven Dec 6, 2025
6f16177
Merge branch 'develop' into feat/init-cli-tests
itaven Dec 11, 2025
2241eeb
feat: baseFlow - oneStepProcess.spec.ts
itaven Dec 13, 2025
51727be
feat: add temp vote enact feature
itaven Dec 15, 2025
bc1971b
feat: enact vote flow && adapt for mainnet
itaven Dec 16, 2025
d5d9538
feat: withdraw test
itaven Dec 16, 2025
927c9a1
Merge branch 'develop' into feat/init-cli-tests
itaven Dec 16, 2025
0cea950
fix: parsing error && node config usage
itaven Dec 16, 2025
759630b
fix: folder names
itaven Dec 16, 2025
6ade16f
Merge branch 'develop' into feat/init-cli-tests
itaven Dec 17, 2025
eb21d93
feat: add 2step process && improve 1step process
itaven Dec 17, 2025
9693ccc
Merge branch 'develop' into feat/init-cli-tests
itaven Dec 24, 2025
ef172f4
fix: try state only for anvil
itaven Dec 25, 2025
35785b7
chore: up wtm.wallets
itaven Dec 25, 2025
7f8f7b0
Merge branch 'fix/ci-logs' into feat/init-cli-tests
itaven Dec 25, 2025
5b7d814
test: set mainnet CI
itaven Dec 25, 2025
536f25a
feat: fixes after oracle report
itaven Dec 25, 2025
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
6 changes: 5 additions & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ jobs:
node-version: 20
cache: "yarn"

- name: Install dependencies
- name: Install root dependencies
run: yarn --immutable

- name: Install test dependencies
working-directory: tests/base
run: yarn install --immutable

- name: Check Lint
run: yarn lint

Expand Down
60 changes: 60 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Test CLI
run-name: Test CLI

on:
workflow_dispatch:
inputs:
CHAIN_ID:
description: 'Chain id for run tests'
required: true
type: choice
default: '560048'
options:
- '560048'
pull_request:

jobs:
test:
runs-on: ubuntu-latest
env:
# Required envs
CHAIN_ID: ${{ github.event.inputs.CHAIN_ID || '560048'}}
# Node.js configuration
NODE_OPTIONS: --max-old-space-size=4096

steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}

- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'yarn'

- name: Install dependencies (root)
run: yarn install --immutable

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Install dependencies in tests/base
working-directory: tests/base
run: yarn install --immutable

- name: Run tests
working-directory: tests/base
run: |
echo -e "\033[34m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m"
echo -e "🚀 Running on CHAIN_ID: \033[1;34m$CHAIN_ID\033[0m"
echo -e "🌱 Branch: \033[1;34m${GITHUB_HEAD_REF:-$GITHUB_REF_NAME}\033[0m"
echo -e "\033[34m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m"
xvfb-run --auto-servernum -- yarn test

- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: tests/base/playwright-report/
retention-days: 30

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"build": "npx tsc && tsc-alias",
"types": "echo 'No types yet'",
"lint": "eslint . --ext .ts --max-warnings 0",
"test": "jest",
"test": "jest ./tests/unit",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"prepare": "git config core.hooksPath .git-hooks || echo 'Not in a git repo'",
Expand Down
6 changes: 6 additions & 0 deletions tests/base/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

# Hoodi - `560048`
CHAIN_ID=

# Optional. Tests are run using the default public RPC endpoint, but you may provide a custom one if the free RPC is slow or unstable
EL_URL=
7 changes: 7 additions & 0 deletions tests/base/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

# playwright
test-results/
playwright-report/
logs/
.yalc
.yarn/*
130 changes: 130 additions & 0 deletions tests/base/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# 🧪 Lido Staking Vault CLI – Playwright Test Suite

This project provides **Playwright-based tests** for the `lido-staking-vault-cli`.
It spins up a **forked Ethereum test network**, bootstraps **smart contracts via CLI**, and runs tests.

---

## ⚙️ Prerequisites

- **Node.js ≥ 18**
- **Yarn** (recommended)

---

## 📦 Installation

From the **root project directory**:

```bash
yarn && yarn build
```

Then navigate to the test suite directory:

```bash
cd tests/base/
yarn
```

> ⚠️ Both installation steps are required — one for the root project and one for the test package.

---

## 🧩 Configuration

1. Copy the example environment file:

```bash
cp .env.example .env
```

2. Fill in the required parameters in `.env`:

```bash
CHAIN_ID=`560048` or `1` (available after stVaults to be released)
RPC_URL=<optional override>
```

> Tests are run using the default public RPC endpoint, but you may provide a custom one if the free RPC is slow or unstable.

---

## 🚀 Running Tests

Run the full Playwright test suite:

```bash
yarn test-widget
Comment thread
DiRaiks marked this conversation as resolved.
Outdated
```

This command expands to:

```bash
yarn playwright test --project=lsv_cli_tests
```

Playwright automatically runs the setup project before executing the main test suite.

---

## 🧱 Test Workflow Overview

- **`playwright.config.ts`** defines two Playwright projects:

- `setup lsv_cli before all` — runs the global setup and initializes the environment.
- `lsv_cli_tests` — contains the actual test specifications.

- **`tests/base/tests/globalSetup.ts`**:

- Creates a vault through the CLI.
- Grants required roles.
- Persists the fork state to `state.json`.

- **`tests/base/tests/test.fixture.ts`**:

- Reuses the saved fork state.
- Starts/stops the forked node.
- Exposes vault metadata and role accounts to the test cases.

---

## 🔁 Fork and Global Setup

The suite uses `EthereumNodeService` from `@lidofinance/wallets-testing-nodes` to launch an **Anvil-based fork** of the Ethereum network.

During the **`setup lsv_cli before all`** project:

1. `globalSetup.ts` starts the fork with `--dump-state` enabled.
2. The CLI creates a fresh vault and grants node-operator-related roles.
3. The resulting chain snapshot is written to `state.json`.
4. `VAULT_ADDRESS` and `DASHBOARD_ADDRESS` are written to the environment for later test use.

Since Playwright runs global setup and test workers in separate processes, those environment variables are dynamically assigned during the global setup stage.
Subsequent workers load the snapshot via `--load-state=./state.json`, ensuring **deterministic test state** and **fast startup times** for all runs.

---

## 🧑‍🔧 Debugging Tip

For long debugging sessions or active test development, you can temporarily disable global setup to speed up iteration.

1. Comment out the following lines in `globalSetup.ts`:

```ts
// console.log(`Vault address ${vaultData.vaultAddress}`);
// console.log(`Dashboard address ${vaultData.dashboardAddress}`);
```

2. Run the tests once to trigger `globalSetup.ts` — this will generate and log the required addresses.
3. Copy the printed `VAULT_ADDRESS` and `DASHBOARD_ADDRESS` values into your `.env` file.
4. Comment out the entire content of `globalSetup.ts`.
5. Run tests again — they will now reuse the existing fork state and skip the global precondition setup.

> **Note:** You may need to occasionally refresh `VAULT_ADDRESS` and `DASHBOARD_ADDRESS`. Since vault and dashboard contracts are created sequentially, their addresses change predictably. If someone creates a new vault on the testnet after your snapshot, the stored addresses may become invalid. In that case, rerun the global setup to regenerate and update your `.env` values.

---

✅ **Summary:**
This test suite automates end-to-end validation of `lido-staking-vault-cli` flows within a reproducible, isolated environment.
It provides deterministic results, faster execution, and confidence in vault creation and role management logic.
52 changes: 52 additions & 0 deletions tests/base/config/env.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {
NetworkConfig,
NETWORKS_CONFIG,
} from '@lidofinance/wallets-testing-wallets';
import { ENV_CONFIG } from './env.validation';

export const getStandConfig = (): StandConfig => {
const config = STAND_CONFIGS.get(ENV_CONFIG.CHAIN_ID);

if (!config) {
throw new Error(
`CONFIG_VALIDATION_ERROR: CHAIN_ID is not correctly defined (value is "${ENV_CONFIG.CHAIN_ID}"). Please fix it in the .env file.`,
);
}

return config;
};

export interface StandConfig {
networkConfig: NetworkConfig;
deployed: string;
contracts: {
stake: string;
Comment thread
DiRaiks marked this conversation as resolved.
Outdated
wrap: string;
withdraw: string;
};
}

export const STAND_ENV = {
hoodiTestnet: '560048',
};

export const STAND_CONFIGS = new Map<string, StandConfig>([
[
STAND_ENV.hoodiTestnet,
{
deployed: 'deployed-hoodi-vaults.json',
networkConfig: {
...NETWORKS_CONFIG.testnet.ETHEREUM_HOODI,
rpcUrl: process.env.RPC_URL
? process.env.RPC_URL
: NETWORKS_CONFIG.testnet.ETHEREUM_HOODI.rpcUrl,
},
contracts: {
stake: '0x3508A952176b3c15387C97BE809eaffB1982176a',
wrap: '0x7E99eE3C66636DE415D2d7C880938F2f40f94De4',
withdraw: '0xfe56573178f1bcdf53F01A6E9977670dcBBD9186',
},
},
],
// mainnnet
]);
35 changes: 35 additions & 0 deletions tests/base/config/env.validation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import path from 'path';

import { z } from 'zod';
import { config as envConfig } from 'dotenv';

const envSchema = z.object({
CHAIN_ID: z.string(),
});

envConfig({ path: path.resolve(__dirname, '../.env') });
class LsvCliEnvs {
CHAIN_ID!: string;

constructor() {
this.validateEnv();
}

private validateEnv() {
const result = envSchema.safeParse(process.env);

if (!result.success) {
throw new Error(
`.env validation error for test run: ${JSON.stringify(
result.error.format(),
)}`,
);
}

const validatedEnv = result.data;

this.CHAIN_ID = validatedEnv.CHAIN_ID;
}
}

export const ENV_CONFIG = new LsvCliEnvs();
19 changes: 19 additions & 0 deletions tests/base/config/report.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ReporterDescription } from '@playwright/test';

const htmlReporter: ReporterDescription = [
'html',
{ outputFolder: 'playwright-report', open: 'never' },
];
const consoleReporter: ReporterDescription = [
'list',
{ printSteps: !process.env.CI },
];
const githubReporter: ReporterDescription = ['github'];

export const getReportConfig: () => ReporterDescription[] = function () {
const reporterConfig: ReporterDescription[] = [htmlReporter, consoleReporter];
if (process.env.CI) {
reporterConfig.push(githubReporter);
}
return reporterConfig;
};
21 changes: 21 additions & 0 deletions tests/base/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "lsv_cli_tests",
"version": "0.0.1",
"private": true,
"scripts": {
"lsvCLI": "tsx ../../index.ts",
"test": "yarn playwright test --project=lsv_cli_tests"
},
"dependencies": {
"@lidofinance/wallets-testing-nodes": "^1.6.0",
"@lidofinance/wallets-testing-wallets": "^1.39.0",
"@playwright/test": "^1.56.1",
"zod": "^3.24.1"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need zod?

@itaven itaven Dec 1, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially, I used it for several required env variables, but in this case I can use it without Zod.
Removed.

},
"devDependencies": {
"add": "^2.0.6",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need "add"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad. Removed

"dotenv": "^16.4.5",
"tsx": "^4.19.3",
"yarn": "^1.22.22"
Comment thread
DiRaiks marked this conversation as resolved.
Outdated
}
}
31 changes: 31 additions & 0 deletions tests/base/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { PlaywrightTestConfig } from '@playwright/test';
import { getReportConfig } from './config/report.config';

export const pwConfig: PlaywrightTestConfig = {
timeout: 180 * 1000,
testDir: './tests',
fullyParallel: false,
forbidOnly: !!process.env.CI,
retries: 0,
// eslint-disable-next-line sonarjs/no-all-duplicated-branches
workers: process.env.CI ? 1 : 1,
Comment thread
DiRaiks marked this conversation as resolved.
Outdated
reporter: getReportConfig(),
use: {
actionTimeout: 15000,
Comment thread
DiRaiks marked this conversation as resolved.
Outdated
trace: 'retain-on-failure',
},
projects: [
{
name: 'lsv_cli_tests',
dependencies: ['setup lsv_cli before all'],
timeout: 220 * 1000,
},
{
name: 'setup lsv_cli before all',
testMatch: /globalSetup\.ts/,
timeout: 350 * 1000, // for Setup project we have to increase timeout
},
],
};

export default pwConfig;
Loading
Loading