Repository: nightwatchjs/nightwatch
Pull request #3780 (2023-06-26 13:14:36)

Add types for Firefox namespace commands
Added Firefox namespace commands:
1. `getContext()`
2. `setContext()`
3. `installAddon()`
4. `uninstallAddon()`


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/index.d.ts b/types/index.d.ts
index 41c27c56..3c8286b9 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -515,6 +515,7 @@ export interface NamespacedApi<ReturnType = unknown> {
   alerts: AlertsNsCommands<ReturnType>;
   document: DocumentNsCommands<ReturnType>;
   window: WindowNsCommands<ReturnType>;
+  firefox: FirefoxNsCommands<ReturnType>;
 
   assert: Assert<ReturnType>;
   verify: Assert<ReturnType>;
@@ -5205,6 +5206,14 @@ export interface CookiesNsCommands<ReturnType = unknown> {
   ): Awaitable<IfUnknown<ReturnType, this>, null>;
 }
 
+type FirefoxContext = 'content' | 'chrome';
+export interface FirefoxNsCommands<ReturnType = unknown> {
+  getContext(): Awaitable<IfUnknown<ReturnType, this>, FirefoxContext>;
+  setContext(ctx: FirefoxContext | PromiseLike<FirefoxContext>): Awaitable<IfUnknown<ReturnType, this>, null>;
+  installAddon(path:string, temporary?: boolean): Awaitable<IfUnknown<ReturnType, this>, string>;
+  uninstallAddon(addonId: string | PromiseLike<string>): Awaitable<IfUnknown<ReturnType, this>, null>;
+} 
+
 export interface AlertsNsCommands<ReturnType = unknown> {
   /**
    * Accepts the currently displayed alert dialog. Usually, this is equivalent to clicking on the 'OK' button in the dialog.
@@ -7559,6 +7568,7 @@ export const cookies: CookiesNsCommands;
 export const alerts: AlertsNsCommands;
 export const document: DocumentNsCommands;
 export const window: WindowNsCommands;
+export const firefox: FirefoxNsCommands;
 
 export const assert: Assert;
 export const verify: Assert;
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);