diff --git a/.github/actions/setup-all/action.yml b/.github/actions/setup-all/action.yml index 3bc240092..ae802225c 100644 --- a/.github/actions/setup-all/action.yml +++ b/.github/actions/setup-all/action.yml @@ -6,7 +6,7 @@ inputs: node_version: description: Node.js version required: false - default: '20.10.0' + default: '22.12.0' go_version: description: Go version required: false diff --git a/.github/actions/setup-js/action.yml b/.github/actions/setup-js/action.yml index a27794037..847f302b0 100644 --- a/.github/actions/setup-js/action.yml +++ b/.github/actions/setup-js/action.yml @@ -6,7 +6,7 @@ inputs: node_version: description: Node.js version required: false - default: '20.10.0' + default: '22.12.0' base_ref: description: Determines which base SHA to use ('base' for a specific SHA/branch, 'last_successful' for the last successful workflow) required: false diff --git a/.gitignore b/.gitignore index dd2b813d4..20ddcda6d 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ deploy.log # Next.js .next +.next-* # builds dist diff --git a/apps/explorer-e2e/playwright.config.ts b/apps/explorer-e2e/playwright.config.ts index fa62e24c7..106e7d83d 100644 --- a/apps/explorer-e2e/playwright.config.ts +++ b/apps/explorer-e2e/playwright.config.ts @@ -1,10 +1,9 @@ import { defineConfig, devices } from '@playwright/test' import { nxE2EPreset } from '@nx/playwright/preset' - import { workspaceRoot } from '@nx/devkit' -// For CI, you may want to set BASE_URL to the deployed application. -const baseURL = process.env['BASE_URL'] || 'http://localhost:3005' +// // For CI, you may want to set BASE_URL to the deployed application. +// const baseURL = process.env['BASE_URL'] || 'http://localhost:3005' /** * Read environment variables from file. @@ -20,13 +19,13 @@ export default defineConfig({ reporter: process.env.CI ? 'blob' : 'html', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { - baseURL, + // baseURL, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', video: 'on-first-retry', }, // Timeout per test. - timeout: 60_000, + timeout: 180_000, expect: { // Raise the timeout because it is running against next dev mode // which requires compilation the first to a page is visited. @@ -36,7 +35,7 @@ export default defineConfig({ /* Run your local dev server before starting the tests */ webServer: { command: 'npx nx run explorer:serve:development-testnet-zen', - url: baseURL, + // url: baseURL, reuseExistingServer: !process.env.CI, cwd: workspaceRoot, }, diff --git a/apps/explorer-e2e/src/fixtures/ExplorerApp.ts b/apps/explorer-e2e/src/fixtures/ExplorerApp.ts index c4cada5bf..7d700d10e 100644 --- a/apps/explorer-e2e/src/fixtures/ExplorerApp.ts +++ b/apps/explorer-e2e/src/fixtures/ExplorerApp.ts @@ -1,11 +1,18 @@ import { Locator, Page } from 'playwright' import { SEARCHBAR } from './constants' +import path from 'path' export class ExplorerApp { + // If no baseUrl is provided, use the default address and port for: + // explorer:serve:development-testnet-zen. + public readonly baseUrl: string = 'http://localhost:3005' private readonly searchBar: Locator - constructor(public readonly page: Page) { + constructor(public readonly page: Page, customBaseUrl?: string) { this.searchBar = this.page.locator(SEARCHBAR) + if (customBaseUrl) { + this.baseUrl = customBaseUrl + } } async navigateBySearchBar(searchTerm: string) { @@ -15,6 +22,6 @@ export class ExplorerApp { } async goTo(url: string) { - await this.page.goto(url) + await this.page.goto(path.join(this.baseUrl, url)) } } diff --git a/apps/explorer-e2e/src/fixtures/cluster.ts b/apps/explorer-e2e/src/fixtures/cluster.ts new file mode 100644 index 000000000..43994c021 --- /dev/null +++ b/apps/explorer-e2e/src/fixtures/cluster.ts @@ -0,0 +1,82 @@ +import { Explored } from '@siafoundation/explored-js' +import { Hostd } from '@siafoundation/hostd-js' +import { Bus } from '@siafoundation/renterd-js' +import { Walletd } from '@siafoundation/walletd-js' +import { startWebServerCluster, stopWebServer } from './webServerCluster' +import { + clusterd, + setupCluster, + teardownCluster, +} from '@siafoundation/clusterd' + +export type Cluster = Awaited> + +export async function startCluster() { + const exploredCount = 1 + const renterdCount = 1 + const walletdCount = 1 + const hostdCount = 3 + await setupCluster({ + exploredCount, + renterdCount, + walletdCount, + hostdCount, + }) + const renterd = clusterd.nodes.find((n) => n.type === 'renterd') + const explored = clusterd.nodes.find((n) => n.type === 'explored') + const hostds = clusterd.nodes.filter((n) => n.type === 'hostd') + const walletds = clusterd.nodes.filter((n) => n.type === 'walletd') + if (!renterd || !explored || !hostds || !walletds) { + throw new Error('Failed to start cluster') + } + const daemons = { + renterd, + explored, + hostds, + walletds, + } + const apis = { + renterd: Bus({ + api: `${renterd.apiAddress}/api`, + password: renterd.password, + }), + explored: Explored({ + api: `${explored.apiAddress}/api`, + password: explored.password, + }), + hostds: hostds.map((h) => + Hostd({ + api: `${h.apiAddress}/api`, + password: h.password, + }) + ), + walletds: walletds.map((w) => + Walletd({ + api: `${w.apiAddress}/api`, + password: w.password, + }) + ), + } + const { baseUrl } = await startWebServerCluster({ + exploredAddress: daemons.explored.apiAddress, + }) + console.log(` + webServerUrl: ${baseUrl} + clusterd: http://localhost:${clusterd.managementPort} + explored: ${daemons.explored.apiAddress} + renterd: ${daemons.renterd.apiAddress} + hostds: ${daemons.hostds.map((h) => h.apiAddress)} + walletds: ${daemons.walletds.map((w) => w.apiAddress)} + `) + return { + webServerUrl: baseUrl, + clusterd, + apis, + daemons, + } +} + +export async function stopCluster() { + stopWebServer() + teardownCluster() +} diff --git a/apps/explorer-e2e/src/fixtures/constants.ts b/apps/explorer-e2e/src/fixtures/constants.ts index eeb055cdf..fe553d382 100644 --- a/apps/explorer-e2e/src/fixtures/constants.ts +++ b/apps/explorer-e2e/src/fixtures/constants.ts @@ -56,15 +56,6 @@ export const TEST_TX_1 = { }, } -export const TEST_ADDRESS_1 = { - id: '68bf48e81536f2221f3809aa9d1c89c1c869a17c6f186a088e49fd2605e4bfaaa24f26e4c42c', - display: { - title: 'Address 68bf48e81536f22...', - transactionNumber: '500 events', - transactionID: 'c0b92135ca06...', - }, -} - export const TEST_CONTRACT_1 = { id: '25c94822bf7bd86a92d28a148d9d30151949f3599bf93af0df7b4f1e1b3c990d', renewedFromTitle: 'Contract 494d147a8028217...', diff --git a/apps/explorer-e2e/src/fixtures/utils.ts b/apps/explorer-e2e/src/fixtures/utils.ts new file mode 100644 index 000000000..1e1299b39 --- /dev/null +++ b/apps/explorer-e2e/src/fixtures/utils.ts @@ -0,0 +1,3 @@ +export function keys(obj: T) { + return Object.keys(obj) as Array +} diff --git a/apps/explorer-e2e/src/fixtures/walletd.ts b/apps/explorer-e2e/src/fixtures/walletd.ts new file mode 100644 index 000000000..e98e63e6f --- /dev/null +++ b/apps/explorer-e2e/src/fixtures/walletd.ts @@ -0,0 +1,96 @@ +import { Walletd } from '@siafoundation/walletd-js' +import { blake2bHex } from 'blakejs' +import { WalletAddressMetadata } from '@siafoundation/walletd-types' +import { to } from '@siafoundation/request' +import { clusterd, mine } from '@siafoundation/clusterd' +import { Bus } from '@siafoundation/renterd-js' +import { humanSiacoin } from '@siafoundation/units' + +export async function addWalletToWalletd(walletd: ReturnType) { + // For some reason when this code runs on GitHub Actions it throws an ESM + // import error for the SDK. Running locally it works fine. + // Error: require() of ES Module sdk/index.esm.js from /fixtures/walletd.ts not supported. + // This dynamic import is a workaround. + const { initSDK, getSDK } = await import('@siafoundation/sdk') + await initSDK() + const sdk = getSDK() + const { phrase: mnemonic } = sdk.wallet.generateSeedPhrase() + const mnemonicHash = blake2bHex(mnemonic) + const [wallet, walletError] = await to( + walletd.walletAdd({ + data: { + name: 'test', + description: 'test', + metadata: { + type: 'seed', + mnemonicHash, + }, + }, + }) + ) + if (!wallet || walletError) { + throw new Error(`Failed to add wallet: ${walletError}`) + } + const kp = sdk.wallet.keyPairFromSeedPhrase(mnemonic, 0) + const suh = sdk.wallet.standardUnlockHash(kp.publicKey) + const uc = sdk.wallet.standardUnlockConditions(kp.publicKey) + const metadata: WalletAddressMetadata = { + index: 0, + } + const [, addressError] = await to( + walletd.walletAddressAdd({ + params: { + id: wallet.id, + }, + data: { + address: suh.address, + description: '', + spendPolicy: { + type: 'uc', + policy: uc.unlockConditions, + }, + metadata, + }, + }) + ) + if (addressError) { + throw new Error(`Failed to add address: ${addressError}`) + } + return { wallet, address: suh.address } +} + +// The renterd node receives all the initial funds so we can use it to fund +// other wallets. +export async function sendSiacoinFromRenterd(address: string, amount: string) { + console.log(`Sending ${humanSiacoin(amount)} from renterd to:`, address) + const renterdNode = clusterd.nodes.find((n) => n.type === 'renterd') + if (!renterdNode) { + throw new Error('Renterd node not found') + } + const bus = Bus({ + api: renterdNode.apiAddress + '/api', + password: renterdNode.password, + }) + + try { + // Send some funds to the wallet. + await bus.walletSend({ + data: { + address, + amount, + subtractMinerFee: false, + }, + }) + await mine(1) + } catch (e) { + console.log('error sending siacoin', e) + } +} + +export async function getRenterdAddress() { + const renterdNode = clusterd.nodes.find((n) => n.type === 'renterd') + if (!renterdNode) { + throw new Error('Renterd node not found') + } + return renterdNode.walletAddress +} diff --git a/apps/explorer-e2e/src/fixtures/webServerCluster.ts b/apps/explorer-e2e/src/fixtures/webServerCluster.ts new file mode 100644 index 000000000..116541e87 --- /dev/null +++ b/apps/explorer-e2e/src/fixtures/webServerCluster.ts @@ -0,0 +1,80 @@ +import { ChildProcess, spawn } from 'child_process' +import { workspaceRoot } from '@nx/devkit' +import net from 'net' + +let server: ChildProcess +let baseUrl: string + +// Starts the explorer app webserver configured to run against the testnet +// cluster provided via the NEXT_PUBLIC_EXPLORED_ADDRESS environment variable. +export async function startWebServerCluster({ + exploredAddress, +}: { + exploredAddress: string +}) { + const port = await findFreePort() + server = spawn( + 'npx', + [ + 'nx', + 'run', + 'explorer:serve:development-testnet-cluster', + '--port', + port.toString(), + ], + { + cwd: workspaceRoot, + shell: true, + env: { + ...process.env, + NEXT_PUBLIC_EXPLORED_ADDRESS: exploredAddress, + }, + } + ) + + server.stdout?.on('data', (data) => { + console.log(data.toString()) + }) + + server.stderr?.on('data', (data) => { + console.error(data.toString()) + }) + + // Wait until stdout prints "Ready", eg: + // ✓ Starting... + // ✓ Ready in 1606ms + await new Promise((resolve) => { + server.stdout?.on('data', (data) => { + if (data.toString().includes('Ready')) { + console.log('Server ready') + resolve(true) + } + }) + }) + baseUrl = `http://localhost:${port}` + return { + baseUrl, + } +} + +export function stopWebServer() { + console.log('Stopping webserver: ', baseUrl) + server.kill() // Kill the server after each test +} + +async function findFreePort(): Promise { + return new Promise((res) => { + const srv = net.createServer() + srv.listen(0, () => { + const addr = srv.address() + if (typeof addr === 'string') { + throw new Error('Address is a string') + } + const port = addr?.port + if (!port) { + throw new Error('Port is undefined') + } + srv.close(() => res(port)) + }) + }) +} diff --git a/apps/explorer-e2e/src/specs/address.spec.ts b/apps/explorer-e2e/src/specs/address.spec.ts index 7032ec783..0cf646f90 100644 --- a/apps/explorer-e2e/src/specs/address.spec.ts +++ b/apps/explorer-e2e/src/specs/address.spec.ts @@ -1,52 +1,88 @@ import { test, expect } from '@playwright/test' import { ExplorerApp } from '../fixtures/ExplorerApp' -import { TEST_ADDRESS_1 } from '../fixtures/constants' +import { startCluster, stopCluster } from '../fixtures/cluster' +import { mine, renterdWaitForContracts } from '@siafoundation/clusterd' +import { addWalletToWalletd, sendSiacoinFromRenterd } from '../fixtures/walletd' +import { Cluster } from '../fixtures/cluster' +import { toHastings } from '@siafoundation/units' let explorerApp: ExplorerApp +let cluster: Cluster test.beforeEach(async ({ page }) => { - explorerApp = new ExplorerApp(page) + cluster = await startCluster() + await renterdWaitForContracts({ + renterdNode: cluster.daemons.renterd, + hostdCount: cluster.daemons.hostds.length, + }) + explorerApp = new ExplorerApp(page, cluster.webServerUrl) +}) + +test.afterEach(async () => { + await stopCluster() }) test('address can be searched by id', async ({ page }) => { + const wallet = await cluster.apis.renterd.wallet() await explorerApp.goTo('/') - await explorerApp.navigateBySearchBar(TEST_ADDRESS_1.id) - - await expect(page.getByText(TEST_ADDRESS_1.display.title)).toBeVisible() + await explorerApp.navigateBySearchBar(wallet.data.address) + await expect( + page + .getByTestId('entity-heading') + .getByText(`Address ${wallet.data.address.slice(0, 5)}`) + ).toBeVisible() }) test('address can be directly navigated to by id', async ({ page }) => { - await explorerApp.goTo('/address/' + TEST_ADDRESS_1.id) - - await expect(page.getByText(TEST_ADDRESS_1.display.title)).toBeVisible() + const wallet = await cluster.apis.renterd.wallet() + await explorerApp.goTo('/address/' + wallet.data.address) + await expect( + page + .getByTestId('entity-heading') + .getByText(`Address ${wallet.data.address.slice(0, 5)}`) + ).toBeVisible() }) test('address displays the intended data', async ({ page }) => { - const displayKeys = Object.keys(TEST_ADDRESS_1.display) - - await explorerApp.goTo('/address/' + TEST_ADDRESS_1.id) - - for (const key of displayKeys) { - const currentProperty = TEST_ADDRESS_1.display[key] - await expect(page.getByText(currentProperty)).toBeVisible() - } -}) - -test('address can navigate to the unspent outputs list', async ({ page }) => { - await explorerApp.goTo('/address/' + TEST_ADDRESS_1.id) + const { wallet, address } = await addWalletToWalletd(cluster.apis.walletds[0]) + await sendSiacoinFromRenterd(address, toHastings(1_000_000).toString()) + await mine(10) + const events = await cluster.apis.walletds[0].walletEvents({ + params: { + id: wallet.id, + limit: 1_000, + offset: 0, + }, + }) + const outputs = await cluster.apis.walletds[0].walletOutputsSiacoin({ + params: { + id: wallet.id, + }, + }) + await explorerApp.goTo('/address/' + address) + await expect(page.getByText(`Address ${address.slice(0, 5)}`)).toBeVisible() + await expect(page.getByText(events.data[0].id.slice(0, 5))).toBeVisible() + await expect(page.getByText(`${events.data.length} events`)).toBeVisible() await page.getByRole('tab').getByText('Unspent outputs').click() - await expect(page.getByText('Siacoin output').first()).toBeVisible() + await expect( + page.getByText(outputs.data.outputs[0].id.slice(0, 5)) + ).toBeVisible() }) test('address can navigate through to a transaction', async ({ page }) => { - await explorerApp.goTo('/address/' + TEST_ADDRESS_1.id) + const wallet = await cluster.apis.renterd.wallet() + const events = await cluster.apis.renterd.walletEvents({ + params: { + limit: 1, + offset: 0, + }, + }) + await explorerApp.goTo('/address/' + wallet.data.address) await page - .locator( - 'a[data-testid="entity-link"][href*="b24a7d623b82206cd3363db0c0d41446f106a59227d86ef081d601315dbd8cca"]' - ) + .locator(`a[data-testid="entity-link"][href*="${events.data[0].id}"]`) .click() - await expect(page.getByText('Transaction b24a7d623b82206...')).toBeVisible() + await expect(page.getByText(events.data[0].id.slice(0, 5))).toBeVisible() }) diff --git a/apps/explorer-e2e/src/specs/block.spec.ts b/apps/explorer-e2e/src/specs/block.spec.ts index ca5ad1622..ca282b69e 100644 --- a/apps/explorer-e2e/src/specs/block.spec.ts +++ b/apps/explorer-e2e/src/specs/block.spec.ts @@ -63,7 +63,8 @@ test('block displays the intended data', async ({ page }) => { await explorerApp.goTo('/block/' + TEST_BLOCK_1.height) for (const key of displayKeys) { - const currentProperty = TEST_BLOCK_1.display[key] + const currentProperty = + TEST_BLOCK_1.display[key as keyof typeof TEST_BLOCK_1.display] await expect(page.getByText(currentProperty)).toBeVisible() } }) diff --git a/apps/explorer-e2e/src/specs/contract.spec.ts b/apps/explorer-e2e/src/specs/contract.spec.ts index 6b0f64282..7e9b03a5f 100644 --- a/apps/explorer-e2e/src/specs/contract.spec.ts +++ b/apps/explorer-e2e/src/specs/contract.spec.ts @@ -5,6 +5,7 @@ import { RENEWED_TO_BUTTON, TEST_CONTRACT_1, } from '../fixtures/constants' +import { keys } from '../fixtures/utils' let explorerApp: ExplorerApp @@ -26,7 +27,7 @@ test('contract can be directly navigated to', async ({ page }) => { }) test('contract displays the intended data', async ({ page }) => { - const displayKeys = Object.keys(TEST_CONTRACT_1.display) + const displayKeys = keys(TEST_CONTRACT_1.display) await explorerApp.goTo('/contract/' + TEST_CONTRACT_1.id) diff --git a/apps/explorer-e2e/src/specs/tx.spec.ts b/apps/explorer-e2e/src/specs/tx.spec.ts index 638ad313a..5e750c0b5 100644 --- a/apps/explorer-e2e/src/specs/tx.spec.ts +++ b/apps/explorer-e2e/src/specs/tx.spec.ts @@ -1,6 +1,7 @@ import { test, expect } from '@playwright/test' import { ExplorerApp } from '../fixtures/ExplorerApp' import { TEST_TX_1 } from '../fixtures/constants' +import { keys } from '../fixtures/utils' let explorerApp: ExplorerApp @@ -45,7 +46,7 @@ test('transaction can click through to an address', async ({ page }) => { }) test('transaction displays the intended data', async ({ page }) => { - const displayKeys = Object.keys(TEST_TX_1.display) + const displayKeys = keys(TEST_TX_1.display) await explorerApp.goTo('/tx/' + TEST_TX_1.id) diff --git a/apps/explorer-e2e/tsconfig.json b/apps/explorer-e2e/tsconfig.json index fd1b9df91..7367984d8 100644 --- a/apps/explorer-e2e/tsconfig.json +++ b/apps/explorer-e2e/tsconfig.json @@ -5,7 +5,7 @@ "allowJs": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, - "strict": false, + "strict": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "resolveJsonModule": true, diff --git a/apps/explorer/components/EntityHeading.tsx b/apps/explorer/components/EntityHeading.tsx index 262c521ad..159a0025c 100644 --- a/apps/explorer/components/EntityHeading.tsx +++ b/apps/explorer/components/EntityHeading.tsx @@ -21,7 +21,7 @@ type Props = { export function EntityHeading({ label, type, value, href }: Props) { return (
- + {upperFirst(label)}{' '} {type === 'block' && Number(value).toLocaleString()} diff --git a/apps/explorer/config/testnet-cluster.ts b/apps/explorer/config/testnet-cluster.ts new file mode 100644 index 000000000..4cc207531 --- /dev/null +++ b/apps/explorer/config/testnet-cluster.ts @@ -0,0 +1,13 @@ +import { webLinks } from '@siafoundation/design-system' + +export const network = 'zen' +export const networkName = 'Zen Testnet' +export const siteName = 'zen.siascan.com' +export const appName = 'siascan' +export const appLink = webLinks.explore.testnetZen +export const isMainnet = false + +// APIs +export const faucetApi = 'https://api.siascan.com/zen/faucet' +export const siaCentralApi = 'https://api.siacentral.com/v2/zen' +export const exploredApi = `${process.env.NEXT_PUBLIC_EXPLORED_ADDRESS}/api` diff --git a/apps/explorer/next.config.js b/apps/explorer/next.config.js index e9ea754eb..f207a1241 100644 --- a/apps/explorer/next.config.js +++ b/apps/explorer/next.config.js @@ -1,4 +1,6 @@ -const { composePlugins, withNx } = require('@nx/next'); +const { composePlugins, withNx } = require('@nx/next') + +const runningTargetConfiguration = process.env.NX_TASK_TARGET_CONFIGURATION /** * @type {import('@nx/next/plugins/with-nx').WithNxOptions} @@ -12,10 +14,12 @@ const nextConfig = { svgr: false, }, output: 'standalone', + // Use the Nx target name for the dist directory + distDir: runningTargetConfiguration?.includes('development') + ? `.next-${runningTargetConfiguration}` + : '.next', } -const plugins = [ - withNx, -]; +const plugins = [withNx] -module.exports = composePlugins(...plugins)(nextConfig); +module.exports = composePlugins(...plugins)(nextConfig) diff --git a/apps/explorer/project.json b/apps/explorer/project.json index 372afd7ec..2ffbb6a67 100644 --- a/apps/explorer/project.json +++ b/apps/explorer/project.json @@ -23,6 +23,15 @@ } ] }, + "development-testnet-cluster": { + "outputPath": "dist/apps/explorer-testnet-cluster", + "fileReplacements": [ + { + "replace": "apps/explorer/config/index.ts", + "with": "apps/explorer/config/testnet-cluster.ts" + } + ] + }, "local": {}, "local-testnet-zen": { "outputPath": "dist/apps/explorer-testnet-zen", @@ -62,6 +71,11 @@ "dev": true, "port": 3005 }, + "development-testnet-cluster": { + "buildTarget": "explorer:build:development-testnet-cluster", + "dev": true, + "port": 3005 + }, "production": { "buildTarget": "explorer:build:production", "dev": false diff --git a/apps/explorer/tsconfig.json b/apps/explorer/tsconfig.json index 5d9709a02..8bf2851f6 100644 --- a/apps/explorer/tsconfig.json +++ b/apps/explorer/tsconfig.json @@ -11,10 +11,7 @@ "resolveJsonModule": true, "isolatedModules": true, "incremental": true, - "types": [ - "jest", - "node" - ], + "types": ["jest", "node"], "plugins": [ { "name": "next" @@ -29,10 +26,8 @@ "**/*.jsx", "next-env.d.ts", ".next/types/**/*.ts", - "../../dist/apps/explorer/.next/types/**/*.ts" + ".next-development-testnet-zen/types/**/*.ts", + ".next-development-testnet-cluster/types/**/*.ts" ], - "exclude": [ - "node_modules", - "jest.config.ts" - ] + "exclude": ["node_modules", "jest.config.ts"] } diff --git a/libs/clusterd/src/index.ts b/libs/clusterd/src/index.ts index 85c81d8e1..1e50ae8ee 100644 --- a/libs/clusterd/src/index.ts +++ b/libs/clusterd/src/index.ts @@ -100,8 +100,9 @@ export async function setupCluster({ Maybe<{ type: string; apiAddress: string; password: string }[]> >(`http://localhost:${clusterd.managementPort}/nodes`) const runningCount = nodes.data?.length - const totalCount = renterdCount + hostdCount + walletdCount - if (nodes.data?.length === renterdCount + hostdCount + walletdCount) { + const totalCount = + renterdCount + hostdCount + walletdCount + exploredCount + if (nodes.data?.length === totalCount) { clusterd.nodes = nodes.data?.map((n) => { if ('apiAddress' in n) { return { diff --git a/libs/e2e/package.json b/libs/e2e/package.json index 826d2c47e..5b82ef87f 100644 --- a/libs/e2e/package.json +++ b/libs/e2e/package.json @@ -4,8 +4,8 @@ "version": "0.5.2", "license": "MIT", "dependencies": { - "@playwright/test": "^1.36.0", - "playwright": "^1.42.1", + "@playwright/test": "^1.49.1", + "playwright": "^1.49.1", "@siafoundation/react-core": "2.0.0" }, "types": "./src/index.d.ts" diff --git a/package-lock.json b/package-lock.json index 23d8c9749..a54baea6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -356,9 +356,9 @@ "version": "0.5.2", "license": "MIT", "dependencies": { - "@playwright/test": "^1.36.0", + "@playwright/test": "^1.49.1", "@siafoundation/react-core": "2.0.0", - "playwright": "^1.42.1" + "playwright": "^1.49.1" } }, "libs/env": { @@ -38209,9 +38209,9 @@ "@siafoundation/e2e": { "version": "file:libs/e2e", "requires": { - "@playwright/test": "^1.36.0", + "@playwright/test": "^1.49.1", "@siafoundation/react-core": "2.0.0", - "playwright": "^1.42.1" + "playwright": "^1.49.1" } }, "@siafoundation/explored-js": {