Repository: nightwatchjs/nightwatch (js)

Issue:
Cucumber steps don't work for Nightwatch 3.0.1
### Description of the bug/issue

When I changed a version of Nightwatch from 2.3.0 to 3.0.1, I see the issue that before/after hooks work correctly. 
But when trying to run cucumber steps, see the following error for every step  "Undefined. Implement with the following snippet:"
What should I change to fix that? For 2.3.0 everything works correctly

### Steps to reproduce

_No response_

### Sample test

./integrations.feature
@C7777777
    Scenario: test
        Given I see the Connectors page

./step_definitions/connectors.js
Given("I see the Connectors page", async () => {
    const connectors = browser.page.admin.connectors.connectors_page()
    await connectors.navigate()
    await connectors.isReady()
})

./page_objects/connectors_page.js
module.exports = {
    url() {
        return `${browser.launch_url}/#/admin/connectors`
    },
    commands: [{
        async isReady() {
            const connectorsPage = this.elements.connectorsPage.selector
            await browser.waitForElementPresent(connectorsPage)
        },
    }],
    elements: {
        connectorsPage: ".z-connectors-page-admin",
    },
    sections: {
    }
}

### Command to run

```bash
node_modules\nightwatch\bin\runner.js --env chrome --tags @C7777777
```


### Verbose Output

_No response_

### Nightwatch Configuration

```node
require("./config/globals")

const { timeouts } = global.config

const {
    TEST_TARGET,
    SELENIUM_HOST,
    USE_LOCAL_CHROMEDRIVER,
} = process.env

const chromeSettings = {
    browserName: "chrome",
    loggingPrefs: { browser: "ALL" },
    javascriptEnabled: true,
    acceptSslCerts: true,
    chromeOptions: {
        args: [
            "--incognito",
            "--start-maximized",
            "--no-sandbox",
            "--disable-web-security",
            "--ignore-certificate-errors",
            "--disable-dev-shm-usage"
        ],
        w3c: false
    }
}

const config = {
    src_folders: ["config/helpers/hooks", "step_definitions"],
    output_folder: "reports",
    page_objects_path: ["page_objects/pages", "page_objects/sections"],
    custom_commands_path: ["config/commands/", "node_modules/nightwatch-custom-commands-assertions/js/commands"],
    custom_assertions_path: ["config/assertions/"],
    test_workers: {
        enabled: false,
        workers: 2
    },
    test_settings: {
        default: {
            test_runner: {
                type: "cucumber",
                options: {
                    feature_path: "features"
                }
            },
            desiredCapabilities: chromeSettings,
            screenshots: {
                enabled: true,
                on_failure: true,
                path: "screenshots"
            },
            videos: {
                enabled: true,
                delete_on_success: true,
                path: "videos"
            },
            launch_url: TEST_TARGET || "http://localhost:8080",
            selenium_host: SELENIUM_HOST || "localhost",
            selenium_port: 4444,
            request_timeout_options: {
                // this affects navigation and pageload stuff
                timeout: timeouts.LONG_TIMEOUT,
                retry_attempts: 5,
            },
            globals: {
                // this affects waiting for elements to change
                waitForConditionTimeout: timeouts.BASE_TIMEOUT,
                retryAssertionTimeout: timeouts.BASE_TIMEOUT,
                asyncHookTimeout: timeouts.BASE_TIMEOUT,
            },
            end_session_on_fail: true
        },
        chromium: {
            desiredCapabilities: chromeSettings
        },
        chrome: {
            desiredCapabilities: chromeSettings
        },
        chromeHeadless: {
            desiredCapabilities: {
                browserName: "chrome",
                javascriptEnabled: true,
                acceptSslCerts: true,
                chromeOptions: {
                    args: [
                        "headless",
                        "disable-web-security",
                        "ignore-certificate-errors"
                    ]
                }
            }
        },
        firefox: {
            desiredCapabilities: {
                browserName: "firefox",
                javascriptEnabled: true,
                chromeOptions: null,
                marionette: true,
                acceptSslCerts: true,
                "moz:firefoxOptions": {
                    args: ["--no-sandbox", "disable-gpu", "--log", "debug"],
                },
            },
        },
    },
}

if (USE_LOCAL_CHROMEDRIVER) {
    config.test_settings.default.videos.enabled = false
    config.test_settings.default.selenium_host = "localhost"
}

module.exports = config
```


### Nightwatch.js Version

3.0.1

### Node Version

14.21.3

### Browser

_No response_

### Operating System

_No response_

### Additional Information

Cucumber version is 8.5.1

Folders structure:
![image](https://github.com/nightwatchjs/nightwatch/assets/81745152/7d30532e-743c-47b4-9ae8-97ce844fb5c3)


Pull request description:
Fixes/3781 fix cucumber step definition config
## Changes
- fixes multiple `step_definition` folder issue for cucumber.

## Impacts
- fixes #3781 

Patch:
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
new file mode 100644
index 00000000..f75928af
--- /dev/null
+++ b/.github/workflows/nightly.yml
@@ -0,0 +1,42 @@
+name: Nightly
+
+on:
+  workflow_dispatch:
+    inputs:
+      version:
+        description: Nightly version
+        required: false
+        type: string
+        default: ''
+      ref:
+        description: Branch, tag, or SHA to release
+        required: false
+        type: string
+        default: ''
+
+jobs:
+  nightly:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          ref: ${{ inputs.ref }}
+      - name: Setup Node
+        uses: actions/setup-node@v3
+        with:
+          node-version: '18.x'
+      - name: Install dependencies
+        run: npm install
+      - name: Build Nightwatch
+        run: npm run build
+      - name: Create publishable package 📦
+        run: npm pack
+      - name: Release Nightly
+        uses: marvinpinto/action-automatic-releases@latest
+        with:
+          repo_token: "${{ secrets.GITHUB_TOKEN }}"
+          automatic_release_tag: "nightly-${{ inputs.version }}"
+          title: "Nightly ${{ inputs.version }}"
+          prerelease: true
+          files: '*.tgz'
diff --git a/lib/runner/folder-walk.js b/lib/runner/folder-walk.js
index c447ff00..aec2f311 100644
--- a/lib/runner/folder-walk.js
+++ b/lib/runner/folder-walk.js
@@ -103,6 +103,10 @@ class Walker {
    * @param {Array} list
    */
   applyFilters(list) {
+    if (this.usingCucumber) {
+      return list;
+    }
+
     return list.sort().filter(filePath => {
       let matched = true;
 
@@ -125,7 +129,7 @@ class Walker {
   }
 
   async applyTagFilter(list) {
-    if (!this.tags.anyTagsDefined()) {
+    if (!this.tags.anyTagsDefined() || this.usingCucumber) {
       return list;
     }
 
@@ -177,11 +181,6 @@ class Walker {
           fullPath = [fullPath];
         }
 
-        // cucumber-runner manages it's own set of filters
-        if (this.usingCucumber) {
-          return resolve(fullPath);
-        }
-
         if (Array.isArray(fullPath)) {
           return this.applyFilters(fullPath);
         }
diff --git a/types/page-object.d.ts b/types/page-object.d.ts
index 8d06cd36..24326914 100644
--- a/types/page-object.d.ts
+++ b/types/page-object.d.ts
@@ -1,9 +1,14 @@
 import {MergeObjectsArray} from './utils';
 import {NightwatchCustomCommands} from './custom-command';
 import {
+  AlertsNsCommands,
+  Assert,
   ChromiumClientCommands,
+  CookiesNsCommands,
+  DocumentNsCommands,
   ElementCommands,
   ElementFunction,
+  Expect,
   LocateStrategy,
   NamespacedApi,
   NightwatchAPI,
@@ -167,8 +172,7 @@ export type EnhancedSectionInstance<
     | 'clickAndHold'
     | 'doubleClick'
     | 'rightClick'
-  > &
-  Pick<NamespacedApi<NightwatchAPI>, 'alerts' | 'cookies' | 'document' | 'assert' | 'verify' | 'expect'>;
+  >;
 
 interface PageObjectSection {
   commands?: Record<string, unknown>[];
@@ -254,6 +258,14 @@ interface EnhancedPageObjectSharedFields<
    * Nightwatch new element API.
    */
   element: ElementFunction;
+
+  // Namespaces directly available on page-objects and sections.
+  alerts: AlertsNsCommands<this>;
+  cookies: CookiesNsCommands<this>;
+  document: DocumentNsCommands<this>;
+  assert: Assert<this>;
+  verify: Assert<this>;
+  expect: Expect;
 }
 
 export interface ElementProperties {
@@ -457,7 +469,6 @@ export type EnhancedPageObject<
   URL = string
 > = SharedCommands &
   NightwatchCustomCommands &
-  Pick<NamespacedApi<NightwatchAPI>, 'alerts' | 'cookies' | 'document' | 'assert' | 'verify' | 'expect'> &
   EnhancedPageObjectSharedFields<
     Required<MergeObjectsArray<Commands>>,
     Required<MergeObjectsArray<Elements>>,


Test patch:
diff --git a/test/src/runner/cucumber-integration/testCucumberSampleTests.js b/test/src/runner/cucumber-integration/testCucumberSampleTests.js
index 08574c15..ade6c3db 100644
--- a/test/src/runner/cucumber-integration/testCucumberSampleTests.js
+++ b/test/src/runner/cucumber-integration/testCucumberSampleTests.js
@@ -16,7 +16,7 @@ describe('Cucumber integration', function() {
   });
 
   it('testCucumberSampleTests', function() {
-    const source = [path.join(__dirname, '../../../cucumber-integration-tests/sample_cucumber_tests/integration/testSample.js')];
+    const source = [path.join(__dirname, '../../../cucumber-integration-tests/sample_cucumber_tests/parallelWithMultipleDefinition/testExpect.js'), path.join(__dirname, '../../../cucumber-integration-tests/sample_cucumber_tests/integration/testSample.js')];
 
     return runTests({
       source,
diff --git a/types/tests/index.test-d.ts b/types/tests/index.test-d.ts
index 0d319fd8..fbc23afc 100644
--- a/types/tests/index.test-d.ts
+++ b/types/tests/index.test-d.ts
@@ -1,4 +1,4 @@
-import { expectError, expectType } from 'tsd';
+import { expectAssignable, expectError, expectType } from 'tsd';
 import { EventEmitter } from 'events';
 import {
   EnhancedPageObject,
@@ -414,7 +414,7 @@ const menuSection = {
 } satisfies SectionProperties;
 
 const googleCommands = {
-  submit(this: EnhancedPageObject) {
+  submit(this: GooglePage) {
     this.api.pause(1000);
     return this.waitForElementVisible('@submitButton', 1000)
       .click('@submitButton')
@@ -481,11 +481,19 @@ declare module '..' {
 const testPage = {
   'Test commands': () => {
     const google = browser.page.google();
-    google.setValue('@searchBar', 'nightwatch').submit();
+    google.setValue('@searchBar', 'nightwatch').submit().assert.titleContains('nightwatch');
 
     expectType<NightwatchAPI>(google.api);
     expectType<NightwatchClient>(google.client);
 
+    const result = google
+      .setValue('@searchBar', 'nightwatch')
+      .assert.titleContains('Google');
+    
+    expectAssignable<GooglePage>(result);
+    expectAssignable<GooglePage>(result.submit());
+    expectAssignable<GooglePage>(result.cookies.getAll());
+
     // test new element api
     google.element('@searchBar');
     google.element.findAll('@searchBar');
@@ -496,19 +504,21 @@ const testPage = {
   'Test sections': () => {
     const google = browser.page.google();
 
-    expectType<Awaitable<NightwatchAPI, null>>(google.cookies.deleteAll());
+    expectAssignable<GooglePage>(google.cookies.deleteAll());
     expectError(googlePage.window.maximize());
 
     const menuSection = google.section.menu;
 
-    menuSection
+    const result = menuSection
       .assert.visible('@mail')
       .assert.visible('@images');
 
+    expectAssignable<typeof menuSection>(result);
+
     menuSection.expect.element('@mail').to.be.visible;
     menuSection.expect.element('@images').to.be.visible;
 
-    expectType<Awaitable<NightwatchAPI, null>>(menuSection.alerts.accept());
+    expectAssignable<typeof menuSection>(menuSection.alerts.accept());
     expectType<NightwatchAPI>(menuSection.api);
     expectType<NightwatchClient>(menuSection.client);