diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index f3c58ea0a..2ba05a6ec 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -157,8 +157,66 @@ jobs:
chmod uog+x target/release/zeitgeist
cd integration-tests
+ export NODE_OPTIONS="--require ./scripts/ws-shim.cjs"
pnpm exec moonwall test zombienet_zeitgeist_upgrade --runInBand
+ zombienet_battery_station_upgrade:
+ name: Battery Station Zombienet Post-Upgrade Tests
+ runs-on: ubuntu-22.04
+ needs: ["build_parachain"]
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ - name: Install build tools
+ run: ./scripts/init.sh
+
+ - uses: pnpm/action-setup@v2
+ with:
+ version: 8
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 20.x
+ cache: "pnpm"
+ cache-dependency-path: "./integration-tests/pnpm-lock.yaml"
+
+ - name: Install pnpm packages
+ run: |
+ cd integration-tests
+ pnpm install
+
+ - name: Cache Dependencies
+ uses: Swatinem/rust-cache@v2
+
+ - name: Create local folders
+ run: |
+ mkdir -p target/release/wbuild/battery-station-runtime/
+ mkdir -p integration-tests/tmp
+
+ - name: Download runtime
+ uses: actions/download-artifact@v4.1.8
+ with:
+ name: runtimes
+ path: target/release/wbuild/battery-station-runtime/
+
+ - name: Download binary
+ uses: actions/download-artifact@v4.1.8
+ with:
+ name: binaries
+ path: target/release
+
+ - name: Display structure of downloaded files
+ run: ls -R
+ working-directory: target/
+
+ - name: Test battery-station runtime upgrade using Zombienet
+ run: |
+ chmod uog+x target/release/zeitgeist
+
+ cd integration-tests
+ export NODE_OPTIONS="--require ./scripts/ws-shim.cjs"
+ pnpm exec moonwall test zombienet_battery_station_upgrade --runInBand
+
chopsticks_battery_station_upgrade:
name: Battery Station Chopsticks Post-Upgrade Tests
runs-on: ubuntu-22.04
@@ -205,6 +263,7 @@ jobs:
- name: Battery Station post-upgrade tests using Chopsticks
run: |
cd integration-tests
+ export NODE_OPTIONS="--require ./scripts/ws-shim.cjs"
pnpm exec moonwall test chopsticks_battery_station_upgrade --runInBand
- name: Show chopsticks logs
@@ -260,6 +319,7 @@ jobs:
- name: Zeitgeist post-upgrade tests using Chopsticks
run: |
cd integration-tests
+ export NODE_OPTIONS="--require ./scripts/ws-shim.cjs"
pnpm exec moonwall test chopsticks_zeitgeist_upgrade --runInBand
- name: Show chopsticks logs
diff --git a/integration-tests/scripts/ws-shim.cjs b/integration-tests/scripts/ws-shim.cjs
new file mode 100644
index 000000000..5ec53eaa3
--- /dev/null
+++ b/integration-tests/scripts/ws-shim.cjs
@@ -0,0 +1,4 @@
+// Ensure a global WebSocket exists when running under Node.
+if (typeof global.WebSocket === "undefined") {
+ global.WebSocket = require("ws");
+}
diff --git a/integration-tests/tests/common-tests.ts b/integration-tests/tests/common-tests.ts
index 29983ffc0..def155d3f 100644
--- a/integration-tests/tests/common-tests.ts
+++ b/integration-tests/tests/common-tests.ts
@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Zeitgeist. If not, see .
+import "./setup-websocket";
import { expect, ChopsticksContext } from "@moonwall/cli";
import { generateKeyringPair } from "@moonwall/util";
import { ApiPromise, Keyring } from "@polkadot/api";
diff --git a/integration-tests/tests/rt-upgrade-battery-station-chopsticks/test-battery-station-chopsticks-runtime-upgrade.ts b/integration-tests/tests/rt-upgrade-battery-station-chopsticks/test-battery-station-chopsticks-runtime-upgrade.ts
index f33973c74..9443caefe 100644
--- a/integration-tests/tests/rt-upgrade-battery-station-chopsticks/test-battery-station-chopsticks-runtime-upgrade.ts
+++ b/integration-tests/tests/rt-upgrade-battery-station-chopsticks/test-battery-station-chopsticks-runtime-upgrade.ts
@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Zeitgeist. If not, see .
+import "../setup-websocket";
import {
MoonwallContext,
beforeAll,
diff --git a/integration-tests/tests/rt-upgrade-zeitgeist-chopsticks/test-zeitgeist-chopsticks-runtime-upgrade.ts b/integration-tests/tests/rt-upgrade-zeitgeist-chopsticks/test-zeitgeist-chopsticks-runtime-upgrade.ts
index c73a0862b..1e97492d7 100644
--- a/integration-tests/tests/rt-upgrade-zeitgeist-chopsticks/test-zeitgeist-chopsticks-runtime-upgrade.ts
+++ b/integration-tests/tests/rt-upgrade-zeitgeist-chopsticks/test-zeitgeist-chopsticks-runtime-upgrade.ts
@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Zeitgeist. If not, see .
+import "../setup-websocket";
import {
MoonwallContext,
beforeAll,
diff --git a/integration-tests/tests/rt-upgrade-zombienet/test-zombienet-runtime-upgrade.ts b/integration-tests/tests/rt-upgrade-zombienet/test-zombienet-runtime-upgrade.ts
index b93ac0e7e..51fd76763 100644
--- a/integration-tests/tests/rt-upgrade-zombienet/test-zombienet-runtime-upgrade.ts
+++ b/integration-tests/tests/rt-upgrade-zombienet/test-zombienet-runtime-upgrade.ts
@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Zeitgeist. If not, see .
+import "../setup-websocket";
import {
MoonwallContext,
beforeAll,
@@ -117,32 +118,67 @@ describeSuite({
);
}
- const txStatus = async (tx: any, label: string) =>
+ const txStatus = async (tx: any, label: string, timeoutMs = 120_000) =>
new Promise((resolve, reject) => {
let unsubscribe: (() => void) | undefined;
+ const timeout = setTimeout(() => {
+ const err = new Error(`${label} timed out waiting for inclusion`);
+ log(err.message);
+ unsubscribe?.();
+ reject(err);
+ }, timeoutMs);
+
+ const finish = (fn: (value?: any) => void, msg?: string, err?: any) => {
+ clearTimeout(timeout);
+ if (msg) {
+ log(msg);
+ }
+ unsubscribe?.();
+ fn(err);
+ };
+
tx.signAndSend(alice, (result: any) => {
+ const status = result.status;
+
if (result.dispatchError) {
// Dispatch errors won't throw, so surface them explicitly.
const errText = result.dispatchError.toString();
- log(`${label} dispatchError=${errText}`);
- reject(new Error(`${label} failed: ${errText}`));
- unsubscribe?.();
+ finish(reject, `${label} dispatchError=${errText}`, new Error(errText));
return;
}
+
log(
- `${label} status=${result.status?.type ?? "unknown"}, events=${result.events
+ `${label} status=${status?.type ?? "unknown"}, events=${result.events
?.map((ev: any) => `${ev.event.section}.${ev.event.method}`)
.join(",")}`
);
- if (result.status?.isInBlock || result.status?.isFinalized) {
- unsubscribe?.();
- resolve();
+
+ if (
+ status?.isDropped ||
+ status?.isInvalid ||
+ status?.isUsurped ||
+ status?.isRetracted ||
+ status?.isFinalityTimeout
+ ) {
+ finish(
+ reject,
+ `${label} failed with status=${status?.type ?? "unknown"}`,
+ new Error(`${label} failed with status=${status?.type ?? "unknown"}`)
+ );
+ return;
+ }
+
+ if (status?.isInBlock || status?.isFinalized) {
+ finish(resolve);
}
})
.then((unsub: () => void) => {
unsubscribe = unsub;
})
- .catch(reject);
+ .catch((err: any) => {
+ clearTimeout(timeout);
+ reject(err);
+ });
});
const findCall = (callName: string) => {
diff --git a/integration-tests/tests/setup-websocket.ts b/integration-tests/tests/setup-websocket.ts
new file mode 100644
index 000000000..1edab3a5b
--- /dev/null
+++ b/integration-tests/tests/setup-websocket.ts
@@ -0,0 +1,7 @@
+// Provide a global WebSocket for Node environments.
+import WebSocket from "ws";
+
+const g = globalThis as Record;
+if (!g.WebSocket) {
+ g.WebSocket = WebSocket;
+}