This is an automated email from the ASF dual-hosted git repository.

piotr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/master by this push:
     new 29dd64d4 feat(js): integrate node bdd test to docker compose (#1926)
29dd64d4 is described below

commit 29dd64d4a14e36f476ae70cb4752b30ed7b86226
Author: T1B0 <[email protected]>
AuthorDate: Fri Jul 4 20:47:29 2025 +0200

    feat(js): integrate node bdd test to docker compose (#1926)
    
    integrate node bdd test to docker compose
    accept IGGY_TCP_ADDRESS env var when running bdd/e2e tests
---
 .github/workflows/ci-check-node-sdk.yml            |  2 +-
 .github/workflows/ci-test-bdd.yml                  |  4 +--
 bdd/README.md                                      |  7 +++++
 bdd/docker-compose.yml                             | 17 ++++++++---
 .../ci-test-bdd.yml => bdd/node/Dockerfile         | 33 ++++------------------
 foreign/node/README.md                             | 18 ++++++++++--
 foreign/node/cucumber.json                         |  3 +-
 foreign/node/package-lock.json                     | 20 ++++++-------
 foreign/node/package.json                          |  3 +-
 foreign/node/src/bdd/README.md                     | 24 ++++++++++++++++
 foreign/node/src/bdd/auth.ts                       |  7 +++--
 foreign/node/src/e2e/tcp.client.e2e.ts             |  8 ++----
 foreign/node/src/e2e/tcp.consumer-group.e2e.ts     |  5 +++-
 foreign/node/src/e2e/tcp.consumer-stream.e2e.ts    | 11 +++++---
 foreign/node/src/e2e/tcp.parallel.e2e.ts           | 12 +++-----
 foreign/node/src/e2e/tcp.send-message.e2e.ts       | 11 +++-----
 foreign/node/src/e2e/tcp.stream.e2e.ts             | 10 ++-----
 foreign/node/src/e2e/tcp.system.e2e.ts             |  9 ++----
 foreign/node/src/e2e/tcp.token.e2e.ts              |  8 ++----
 foreign/node/src/e2e/tcp.topic.e2e.ts              | 13 ++++-----
 foreign/node/src/e2e/tcp.user.e2e.ts               |  8 ++----
 .../src/{bdd/auth.ts => e2e/test-client.utils.ts}  | 26 +++++------------
 foreign/node/src/tcp.sm.utils.ts                   |  8 ++++++
 scripts/run-bdd-tests.sh                           |  8 ++++++
 24 files changed, 147 insertions(+), 128 deletions(-)

diff --git a/.github/workflows/ci-check-node-sdk.yml 
b/.github/workflows/ci-check-node-sdk.yml
index f6d1a615..bb4ecfbd 100644
--- a/.github/workflows/ci-check-node-sdk.yml
+++ b/.github/workflows/ci-check-node-sdk.yml
@@ -75,7 +75,7 @@ jobs:
         run: cd foreign/node/ && npm run build
         
       - name: run unit test
-        run: cd foreign/node/ && npm run test
+        run: cd foreign/node/ && npm run test:unit
 
       ### Integration tests (e2e)
       
diff --git a/.github/workflows/ci-test-bdd.yml 
b/.github/workflows/ci-test-bdd.yml
index 35964a8e..036f69c3 100644
--- a/.github/workflows/ci-test-bdd.yml
+++ b/.github/workflows/ci-test-bdd.yml
@@ -26,7 +26,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        sdk: [rust, python, go]
+        sdk: [rust, python, go, node]
     steps:
       - name: Checkout code
         uses: actions/checkout@v4
@@ -45,4 +45,4 @@ jobs:
 
       - name: Clean up Docker resources
         if: always()
-        run: ./scripts/run-bdd-tests.sh clean
\ No newline at end of file
+        run: ./scripts/run-bdd-tests.sh clean
diff --git a/bdd/README.md b/bdd/README.md
index ebda0ca3..c96156e1 100644
--- a/bdd/README.md
+++ b/bdd/README.md
@@ -16,6 +16,8 @@ bdd/
 │   ├── Dockerfile              # Python BDD test container
 │   ├── tests/
 │   └── requirements.txt
+├── node/                       # Node SDK BDD implementation
+│   └── Dockerfile              # Node BDD test container
 ├── docker-compose.yml          # Orchestrates server + SDK containers
 ├── Dockerfile                  # Debug build of Iggy server
 └── README.md
@@ -33,6 +35,7 @@ bdd/
 ../scripts/run-bdd-tests.sh rust
 ../scripts/run-bdd-tests.sh python
 ../scripts/run-bdd-tests.sh go
+../scripts/run-bdd-tests.sh node
 
 # Clean up Docker resources
 ../scripts/run-bdd-tests.sh clean
@@ -75,6 +78,10 @@ The Rust implementation is located in `core/bdd/` and linked 
via Docker volumes.
 
 The Python implementation is in `bdd/python/tests/` and needs to be updated as 
the Python SDK API evolves.
 
+### For Node SDK
+
+The node.js BDD test are run by cucumber-js, bdd test code is located at 
[foreign/node/src/bdd](../foreign/node/src/bdd/)
+
 ### Adding New Scenarios
 
 Add new `.feature` files to the `bdd/scenarios/` directory and implement the 
corresponding step definitions in each SDK's test directory.
diff --git a/bdd/docker-compose.yml b/bdd/docker-compose.yml
index 0d262f06..a52f1e19 100644
--- a/bdd/docker-compose.yml
+++ b/bdd/docker-compose.yml
@@ -21,10 +21,6 @@ services:
     build:
       context: ..
       dockerfile: bdd/Dockerfile
-    ports:
-      - "8090:8090"  # TCP
-      - "3000:3000"  # HTTP
-      - "8080:8080"  # QUIC
     environment:
       - RUST_LOG=info
       - IGGY_SYSTEM_PATH=local_data
@@ -76,5 +72,18 @@ services:
     volumes:
       - 
./scenarios/basic_messaging.feature:/app/features/basic_messaging.feature
     command: [ "ginkgo", "-v", "-r" ]
+
+  node-bdd:
+    build:
+      context: ..
+      dockerfile: bdd/node/Dockerfile
+    depends_on:
+      iggy-server:
+        condition: service_healthy
+    environment:
+      - IGGY_TCP_ADDRESS=iggy-server:8090
+    command: ["npm", "run", "test:bdd"]
+
+    
 volumes:
   iggy_data:
diff --git a/.github/workflows/ci-test-bdd.yml b/bdd/node/Dockerfile
similarity index 51%
copy from .github/workflows/ci-test-bdd.yml
copy to bdd/node/Dockerfile
index 35964a8e..019b44c9 100644
--- a/.github/workflows/ci-test-bdd.yml
+++ b/bdd/node/Dockerfile
@@ -15,34 +15,13 @@
 # specific language governing permissions and limitations
 # under the License.
 
-name: Cross-SDK BDD Tests
+FROM node:24-slim
 
-on:
-  workflow_call:
+COPY ./foreign/node .
+COPY ./bdd/scenarios ./bdd/
 
-jobs:
-  bdd-tests:
-    name: BDD tests (${{ matrix.sdk }})
-    runs-on: ubuntu-latest
-    strategy:
-      matrix:
-        sdk: [rust, python, go]
-    steps:
-      - name: Checkout code
-        uses: actions/checkout@v4
-      
-      - name: Cache Rust dependencies
-        uses: Swatinem/rust-cache@v2
-        with:
-          workspaces: |
-            . -> target
-            foreign/python -> target
-          cache-on-failure: true
-          key: bdd-${{ matrix.sdk }}
+RUN npm ci
 
-      - name: Run BDD tests for ${{ matrix.sdk }}
-        run: ./scripts/run-bdd-tests.sh ${{ matrix.sdk }}
+USER node
 
-      - name: Clean up Docker resources
-        if: always()
-        run: ./scripts/run-bdd-tests.sh clean
\ No newline at end of file
+CMD ["npm", "run", "test"]
diff --git a/foreign/node/README.md b/foreign/node/README.md
index 93d24029..f7d08535 100644
--- a/foreign/node/README.md
+++ b/foreign/node/README.md
@@ -11,7 +11,7 @@ note: previous works on node.js http client has been moved to 
[iggy-node-http-cl
 ## install
 
 ```bash
-npm i @apache-iggy/node-sdk
+npm i --save @apache-iggy/node-sdk
 ```
 
 ## basic usage
@@ -46,10 +46,12 @@ npm run build
 
 ### test
 
+note: use env var `IGGY_TCP_ADDRESS="host:port"` to set server address for bdd 
and e2e tests.
+
 #### unit tests
 
 ```bash
-npm run test
+npm run test:unit
 ```
 
 #### e2e tests
@@ -60,6 +62,18 @@ e2e test expect an iggy-server at tcp://127.0.0.1:8090
 npm run test:e2e
 ```
 
+#### bdd tests
+
+bdd test expect an iggy-server at tcp://127.0.0.1:8090
+
+```bash
+npm run test:bdd
+```
+
+#### run all test
+
+`npm run test` runs unit, bdd and e2e tests suite (expect an iggy-server at 
tcp://127.0.0.1:8090)
+
 ### lint
 
 ```bash
diff --git a/foreign/node/cucumber.json b/foreign/node/cucumber.json
index e7796ca7..04c4b8c8 100644
--- a/foreign/node/cucumber.json
+++ b/foreign/node/cucumber.json
@@ -7,7 +7,8 @@
       "src/bdd/**/*.ts"
     ],
     "paths": [
-      "../../bdd/**/*.feature"
+      "../../bdd/**/*.feature",
+      "./bdd/**/*.feature"
     ]
   }
 }
diff --git a/foreign/node/package-lock.json b/foreign/node/package-lock.json
index cd086583..328472cb 100644
--- a/foreign/node/package-lock.json
+++ b/foreign/node/package-lock.json
@@ -16,7 +16,7 @@
       "devDependencies": {
         "@commitlint/cli": "19.6.1",
         "@commitlint/config-conventional": "19.6.0",
-        "@cucumber/cucumber": "^11.3.0",
+        "@cucumber/cucumber": "11.3.0",
         "@semantic-release/changelog": "6.0.3",
         "@semantic-release/exec": "6.0.3",
         "@semantic-release/git": "10.0.1",
@@ -2673,9 +2673,9 @@
       }
     },
     
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion":
 {
-      "version": "2.0.1",
-      "resolved": 
"https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz";,
-      "integrity": 
"sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "version": "2.0.2",
+      "resolved": 
"https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz";,
+      "integrity": 
"sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
@@ -2921,9 +2921,9 @@
       "license": "MIT"
     },
     "node_modules/brace-expansion": {
-      "version": "1.1.11",
-      "resolved": 
"https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz";,
-      "integrity": 
"sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "version": "1.1.12",
+      "resolved": 
"https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz";,
+      "integrity": 
"sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
       "dev": true,
       "license": "MIT",
       "peer": true,
@@ -4421,9 +4421,9 @@
       }
     },
     "node_modules/glob/node_modules/brace-expansion": {
-      "version": "2.0.1",
-      "resolved": 
"https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz";,
-      "integrity": 
"sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "version": "2.0.2",
+      "resolved": 
"https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz";,
+      "integrity": 
"sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
diff --git a/foreign/node/package.json b/foreign/node/package.json
index ee217e81..aacf8eeb 100644
--- a/foreign/node/package.json
+++ b/foreign/node/package.json
@@ -27,9 +27,10 @@
   "types": "dist/index.d.ts",
   "main": "dist/index.js",
   "scripts": {
-    "test": "node --import @swc-node/register/esm-register --test 
--experimental-test-coverage './src/**/*.test.ts'",
+    "test:unit": "node --import @swc-node/register/esm-register --test 
--experimental-test-coverage './src/**/*.test.ts'",
     "test:e2e": "node --import @swc-node/register/esm-register --test 
--experimental-test-coverage --test-force-exit './src/e2e/*.e2e.ts'",
     "test:bdd": "cucumber-js --exit",
+    "test": "npm run test:unit && npm run test:bdd && npm run test:e2e",
     "clean": "rm -Rf dist/",
     "lint": "eslint src/**/*.ts",
     "commitlint": "commitlint --edit",
diff --git a/foreign/node/src/bdd/README.md b/foreign/node/src/bdd/README.md
new file mode 100644
index 00000000..b7ec9eac
--- /dev/null
+++ b/foreign/node/src/bdd/README.md
@@ -0,0 +1,24 @@
+
+# Node.js bdd test
+
+Node.js bdd test are run via cucumber-js.
+scenario are located at [/bdd/scenarios](../../../../bdd/scenarios)
+
+## env var
+
+use env var `IGGY_TCP_ADDRESS="host:port"` to set expected server address for 
bdd test suite.
+
+## Run via docker
+
+see [/bdd/README.md](../../../../bdd/README.md)
+
+## Run locally
+
+note: bdd test expect an iggy-server at tcp://127.0.0.1:8090
+
+from [/foreign/node](../../) run
+
+```bash
+npm ci # if not already done
+npm run test:bdd
+```
diff --git a/foreign/node/src/bdd/auth.ts b/foreign/node/src/bdd/auth.ts
index 0b02f3c8..4ad867af 100644
--- a/foreign/node/src/bdd/auth.ts
+++ b/foreign/node/src/bdd/auth.ts
@@ -22,11 +22,14 @@ import assert from 'node:assert/strict';
 import { Client } from '../client/index.js';
 import { Given } from "@cucumber/cucumber";
 import type { TestWorld } from './world.js';
+import { getIggyAddress } from '../tcp.sm.utils.js';
 
 const credentials = { username: 'iggy', password: 'iggy' };
+const [host, port] = getIggyAddress();
+
 const opt = {
   transport: 'TCP' as const,
-  options: { port: 8090, host: '127.0.0.1' },
+  options: { host, port },
   credentials
 };
 
@@ -35,7 +38,7 @@ Given('I have a running Iggy server', function () {
 });
 
 
-Given('I am authenticated as the root user', async function(this: TestWorld) {
+Given('I am authenticated as the root user', async function (this: TestWorld) {
   this.client = new Client(opt);
   assert.deepEqual({ userId: 1 }, await 
this.client.session.login(credentials));
   assert.equal(true, await this.client.system.ping());
diff --git a/foreign/node/src/e2e/tcp.client.e2e.ts 
b/foreign/node/src/e2e/tcp.client.e2e.ts
index b3084a5b..9e5e9a21 100644
--- a/foreign/node/src/e2e/tcp.client.e2e.ts
+++ b/foreign/node/src/e2e/tcp.client.e2e.ts
@@ -20,15 +20,11 @@
 
 import { after, describe, it } from 'node:test';
 import assert from 'node:assert/strict';
-import { Client } from '../client/client.js';
+import { getTestClient } from './test-client.utils.js';
 
 describe('e2e -> client', async () => {
 
-  const c = new Client({
-    transport: 'TCP',
-    options: { port: 8090, host: '127.0.0.1' },
-    credentials: { username: 'iggy', password: 'iggy' }
-  });
+  const c = getTestClient();
 
   it('e2e -> client::getMe', async () => {
     const cli = await c.client.getMe();
diff --git a/foreign/node/src/e2e/tcp.consumer-group.e2e.ts 
b/foreign/node/src/e2e/tcp.consumer-group.e2e.ts
index ca3595d0..6a1f6d4d 100644
--- a/foreign/node/src/e2e/tcp.consumer-group.e2e.ts
+++ b/foreign/node/src/e2e/tcp.consumer-group.e2e.ts
@@ -23,12 +23,15 @@ import assert from 'node:assert/strict';
 import { SingleClient } from '../client/client.js';
 import { ConsumerKind, PollingStrategy, Partitioning } from '../wire/index.js';
 import { generateMessages } from '../tcp.sm.utils.js';
+import { getIggyAddress } from '../tcp.sm.utils.js';
 
 describe('e2e -> consumer-group', async () => {
 
+  const [host, port] = getIggyAddress();
+
   const c = new SingleClient({
     transport: 'TCP',
-    options: { port: 8090, host: '127.0.0.1' },
+    options: { host, port },
     credentials: { username: 'iggy', password: 'iggy' }
   });
   
diff --git a/foreign/node/src/e2e/tcp.consumer-stream.e2e.ts 
b/foreign/node/src/e2e/tcp.consumer-stream.e2e.ts
index 7663a8a8..d6fef70e 100644
--- a/foreign/node/src/e2e/tcp.consumer-stream.e2e.ts
+++ b/foreign/node/src/e2e/tcp.consumer-stream.e2e.ts
@@ -21,20 +21,23 @@
 import { after, describe, it } from 'node:test';
 import assert from 'node:assert/strict';
 import type { Readable } from 'node:stream';
+import { Client } from '../client/client.js';
 import { groupConsumerStream } from '../stream/consumer-stream.js';
-import { Client } from '../client/index.js';
 import {
   PollingStrategy, Partitioning,
   type PollMessagesResponse
 } from '../wire/index.js';
-import { sendSomeMessages } from '../tcp.sm.utils.js';
+import { sendSomeMessages, getIggyAddress } from '../tcp.sm.utils.js';
+
 
 describe('e2e -> consumer-stream', async () => {
 
+  const [host, port] = getIggyAddress();
   const credentials = { username: 'iggy', password: 'iggy' };
+
   const opt = {
     transport: 'TCP' as const,
-    options: { port: 8090, host: '127.0.0.1' },
+    options: { host, port },
     credentials
   };
 
@@ -78,7 +81,7 @@ describe('e2e -> consumer-stream', async () => {
     const s = await pollStream(pollReq);
     const s2 = await pollStream(pollReq);
     let recv = 0;
-    const dataCb = (str: Readable) => (d: PollMessagesResponse) => {      
+    const dataCb = (str: Readable) => (d: PollMessagesResponse) => {
       recv += d.messages.length;
       assert.equal(d.messages.length, d.count);
       if (recv === ct) {
diff --git a/foreign/node/src/e2e/tcp.parallel.e2e.ts 
b/foreign/node/src/e2e/tcp.parallel.e2e.ts
index 22ced901..9b0938d1 100644
--- a/foreign/node/src/e2e/tcp.parallel.e2e.ts
+++ b/foreign/node/src/e2e/tcp.parallel.e2e.ts
@@ -20,18 +20,14 @@
 
 import { after, describe, it } from 'node:test';
 import assert from 'node:assert/strict';
-import { Client } from '../client/client.js';
+import { getTestClient } from './test-client.utils.js';
 
 describe('e2e -> parallel', async () => {
 
-  const credentials = { username: 'iggy', password: 'iggy' };
-  const c = new Client({
-    transport: 'TCP',
-    options: { port: 8090, host: '127.0.0.1' },
-    credentials
-  });
-
+  const c = getTestClient();
+  
   const baseGetMe = await c.client.getMe();
+  const credentials = { username: 'iggy', password: 'iggy' };
 
 
   it('e2e -> parallel::mix calls', async () => {
diff --git a/foreign/node/src/e2e/tcp.send-message.e2e.ts 
b/foreign/node/src/e2e/tcp.send-message.e2e.ts
index 7ef13a5c..281a5f5a 100644
--- a/foreign/node/src/e2e/tcp.send-message.e2e.ts
+++ b/foreign/node/src/e2e/tcp.send-message.e2e.ts
@@ -20,18 +20,15 @@
 
 import { after, describe, it } from 'node:test';
 import assert from 'node:assert/strict';
-import { Client } from '../client/client.js';
 import { ConsumerKind, PollingStrategy, Partitioning } from '../wire/index.js';
 import { generateMessages } from '../tcp.sm.utils.js';
+import { getTestClient } from './test-client.utils.js';
 
-describe('e2e -> message', async () => {
 
-  const c = new Client({
-    transport: 'TCP',
-    options: { port: 8090, host: '127.0.0.1' },
-    credentials: { username: 'iggy', password: 'iggy' }
-  });
+describe('e2e -> message', async () => {
 
+  const c = getTestClient();
+  
   const streamId = 934;
   const topicId = 832;
   const partitionId = 1;
diff --git a/foreign/node/src/e2e/tcp.stream.e2e.ts 
b/foreign/node/src/e2e/tcp.stream.e2e.ts
index 38fbc2c9..d2de80cb 100644
--- a/foreign/node/src/e2e/tcp.stream.e2e.ts
+++ b/foreign/node/src/e2e/tcp.stream.e2e.ts
@@ -20,16 +20,12 @@
 
 import { after, describe, it } from 'node:test';
 import assert from 'node:assert/strict';
-import { Client } from '../client/client.js';
+import { getTestClient } from './test-client.utils.js';
 
 describe('e2e -> stream', async () => {
 
-  const c = new Client({
-    transport: 'TCP',
-    options: { port: 8090, host: '127.0.0.1' },
-    credentials: { username: 'iggy', password: 'iggy' }
-  });
-
+  const c = getTestClient();
+  
   const streamId = 164;
   const name = 'e2e-tcp-stream';
   const name2 = `${name}-updated`;
diff --git a/foreign/node/src/e2e/tcp.system.e2e.ts 
b/foreign/node/src/e2e/tcp.system.e2e.ts
index 2fa1cac4..6945dfa9 100644
--- a/foreign/node/src/e2e/tcp.system.e2e.ts
+++ b/foreign/node/src/e2e/tcp.system.e2e.ts
@@ -20,15 +20,12 @@
 
 import { after, describe, it } from 'node:test';
 import assert from 'node:assert/strict';
-import { Client } from '../client/client.js';
+import { getTestClient } from './test-client.utils.js';
 
 describe('e2e -> system', async () => {
 
-  const c = new Client({
-    transport: 'TCP',
-    options: { port: 8090, host: '127.0.0.1' },
-    credentials: { username: 'iggy', password: 'iggy' }
-  });
+  
+  const c = getTestClient();
   
   it('e2e -> system::ping', async () => {
     assert.ok(await c.system.ping());
diff --git a/foreign/node/src/e2e/tcp.token.e2e.ts 
b/foreign/node/src/e2e/tcp.token.e2e.ts
index eae9e6af..f1d302d7 100644
--- a/foreign/node/src/e2e/tcp.token.e2e.ts
+++ b/foreign/node/src/e2e/tcp.token.e2e.ts
@@ -20,15 +20,11 @@
 
 import { after, describe, it } from 'node:test';
 import assert from 'node:assert/strict';
-import { Client } from '../client/client.js';
+import { getTestClient } from './test-client.utils.js';
 
 describe('e2e -> token', async () => {
 
-  const c = new Client({
-    transport: 'TCP',
-    options: { port: 8090, host: '127.0.0.1' },
-    credentials: { username: 'iggy', password: 'iggy' }
-  });
+  const c = getTestClient();
 
   const tokenName = 'yolo-token-test';
   
diff --git a/foreign/node/src/e2e/tcp.topic.e2e.ts 
b/foreign/node/src/e2e/tcp.topic.e2e.ts
index 6e174eeb..56b6d758 100644
--- a/foreign/node/src/e2e/tcp.topic.e2e.ts
+++ b/foreign/node/src/e2e/tcp.topic.e2e.ts
@@ -20,16 +20,13 @@
 
 import { after, describe, it } from 'node:test';
 import assert from 'node:assert/strict';
-import { Client } from '../client/client.js';
+import { getTestClient } from './test-client.utils.js';
 
-describe('e2e -> topic', async () => {
-
-  const c = new Client({
-    transport: 'TCP',
-    options: { port: 8090, host: '127.0.0.1' },
-    credentials: { username: 'iggy', password: 'iggy' }
-  });
 
+describe('e2e -> topic', async () => {
+  
+  const c = getTestClient();
+  
   const streamId = 111;
   const topicId = 123;
 
diff --git a/foreign/node/src/e2e/tcp.user.e2e.ts 
b/foreign/node/src/e2e/tcp.user.e2e.ts
index 5174948e..aec3ab11 100644
--- a/foreign/node/src/e2e/tcp.user.e2e.ts
+++ b/foreign/node/src/e2e/tcp.user.e2e.ts
@@ -20,15 +20,11 @@
 
 import { after, describe, it } from 'node:test';
 import assert from 'node:assert/strict';
-import { Client } from '../client/client.js';
+import { getTestClient } from './test-client.utils.js';
 
 describe('e2e -> user', async () => {
 
-  const c = new Client({
-    transport: 'TCP',
-    options: { port: 8090, host: '127.0.0.1' },
-    credentials: { username: 'iggy', password: 'iggy' }
-  });
+  const c = getTestClient();
 
   const userId = 42;
   const username = 'test-user';
diff --git a/foreign/node/src/bdd/auth.ts 
b/foreign/node/src/e2e/test-client.utils.ts
similarity index 60%
copy from foreign/node/src/bdd/auth.ts
copy to foreign/node/src/e2e/test-client.utils.ts
index 0b02f3c8..f65d185f 100644
--- a/foreign/node/src/bdd/auth.ts
+++ b/foreign/node/src/e2e/test-client.utils.ts
@@ -17,26 +17,14 @@
  * under the License.
  */
 
-
-import assert from 'node:assert/strict';
-import { Client } from '../client/index.js';
-import { Given } from "@cucumber/cucumber";
-import type { TestWorld } from './world.js';
+import { Client } from '../client/client.js';
+import { getIggyAddress } from '../tcp.sm.utils.js';
 
 const credentials = { username: 'iggy', password: 'iggy' };
-const opt = {
-  transport: 'TCP' as const,
-  options: { port: 8090, host: '127.0.0.1' },
-  credentials
-};
-
-Given('I have a running Iggy server', function () {
-  return true;
-});
-
+const [host, port] = getIggyAddress();
 
-Given('I am authenticated as the root user', async function(this: TestWorld) {
-  this.client = new Client(opt);
-  assert.deepEqual({ userId: 1 }, await 
this.client.session.login(credentials));
-  assert.equal(true, await this.client.system.ping());
+export const getTestClient = () => new Client({
+  transport: 'TCP',
+  options: { host, port },
+  credentials
 });
diff --git a/foreign/node/src/tcp.sm.utils.ts b/foreign/node/src/tcp.sm.utils.ts
index c68eda45..ec55d927 100644
--- a/foreign/node/src/tcp.sm.utils.ts
+++ b/foreign/node/src/tcp.sm.utils.ts
@@ -70,3 +70,11 @@ export const formatPolledMessages = (msgs: Message[]) =>
       checksum
     };
   });
+
+export const getIggyAddress = (host = '127.0.0.1', port = 8090): [string, 
number] => {
+  if (process.env.IGGY_TCP_ADDRESS) {
+    const s = (process.env.IGGY_TCP_ADDRESS || '').split(':');
+    [host, port] = [s[0], s[1] ? parseInt(s[1].toString(), 10) : port];
+  }
+  return [host, port];
+}
diff --git a/scripts/run-bdd-tests.sh b/scripts/run-bdd-tests.sh
index e3fc2e37..12cdb68d 100755
--- a/scripts/run-bdd-tests.sh
+++ b/scripts/run-bdd-tests.sh
@@ -43,6 +43,11 @@ case $SDK in
   docker compose build --no-cache iggy-server go-bdd
   docker compose up --abort-on-container-exit go-bdd
   ;;
+"node")
+  echo "🐢🚀 Running node BDD tests..."
+  docker compose build --no-cache iggy-server node-bdd
+  docker compose up --abort-on-container-exit node-bdd
+  ;;
 "all")
   echo "🚀 Running all SDK BDD tests..."
   echo "🦀 Starting with Rust tests..."
@@ -52,6 +57,8 @@ case $SDK in
   docker compose up --abort-on-container-exit python-bdd
   echo "🐹 Now running Go tests..."
   docker compose up --abort-on-container-exit go-bdd
+  echo "🐢🚀 Now unning node BDD tests..."
+  docker compose up --abort-on-container-exit node-bdd
   ;;
 "clean")
   echo "🧹 Cleaning up Docker resources..."
@@ -65,6 +72,7 @@ case $SDK in
   echo "   $0 rust                    # Run Rust tests only"
   echo "   $0 python                  # Run Python tests only"
   echo "   $0 go                      # Run Go tests only"
+  echo "   $0 node                    # Run Node.js tests only"
   echo "   $0 all                     # Run all SDK tests"
   echo "   $0 clean                   # Clean up Docker resources"
   exit 1

Reply via email to