Skip to content
Back to skills

Nightwatchjs Testing

ASecurity

Comprehensive NightwatchJS end-to-end testing skill with integrated Selenium WebDriver, built-in assertions, page objects, and parallel test execution for reliable browser automation in JavaScript and TypeScript.

  • 230 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added June 4, 2026
testingjavascripttypescriptgojavabashnodeexpresstestingdebugginggit

Works with

  • cursor
  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned June 4, 2026

npx -y skills add PramodDutta/qaskills --skill nightwatchjs-testing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Nightwatchjs Testing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Nightwatchjs Testing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/pramoddutta-nightwatchjs-testing/badge)](https://www.skillsdirectory.com/skills/pramoddutta-nightwatchjs-testing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: "NightwatchJS Testing"
description: "Comprehensive NightwatchJS end-to-end testing skill with integrated Selenium WebDriver, built-in assertions, page objects, and parallel test execution for reliable browser automation in JavaScript and TypeScript."
version: 1.0.0
author: thetestingacademy
license: MIT
tags: [nightwatch, nightwatchjs, selenium, e2e, browser-testing, page-objects, automation]
testingTypes: [e2e, integration, visual]
frameworks: [nightwatchjs]
languages: [javascript, typescript]
domains: [web]
agents: [claude-code, cursor, github-copilot, windsurf, codex, aider, continue, cline, zed, bolt]
---

# NightwatchJS Testing

You are an expert QA engineer specializing in NightwatchJS end-to-end testing. When the user asks you to write, review, debug, or set up NightwatchJS-related tests or configurations, follow these detailed instructions.

## Core Principles

1. **Built-in Assertions First** -- Use Nightwatch's rich built-in assertion library (`.assert.visible()`, `.assert.textContains()`, `.assert.urlContains()`) before reaching for custom assertion logic.
2. **Page Object Architecture** -- Structure all tests around Nightwatch's native page object support. Define selectors using `elements` blocks and actions using `commands`.
3. **Implicit Waits with Explicit Controls** -- Nightwatch provides automatic retry on assertions. Configure `waitForConditionTimeout` globally and use `waitForElementVisible()` for explicit synchronization.
4. **Test Isolation** -- Each test file must be independent. Use `before`, `beforeEach`, `after`, and `afterEach` hooks for setup/teardown rather than relying on test execution order.
5. **Parallel Execution** -- Design tests to run in parallel across multiple browsers. Use `--parallel` flag and ensure tests do not share mutable state.
6. **CSS Selector Strategy** -- Prefer `data-testid` attributes and semantic selectors. Use Nightwatch's `@element` syntax from page objects to keep selectors centralized.
7. **Descriptive Test Names** -- Write test names that describe the expected behavior: `'should display error when login fails with invalid credentials'` rather than `'test login error'`.

## When to Use This Skill

- When setting up NightwatchJS for a new or existing project
- When writing end-to-end browser tests with Nightwatch
- When implementing Nightwatch page objects and commands
- When configuring Nightwatch for cross-browser testing
- When debugging flaky Nightwatch tests
- When integrating Nightwatch into CI/CD pipelines
- When working with `nightwatch.conf.js`, `browser.url()`, `.assert`, or `.verify` commands

## Project Structure

```
project-root/
├── nightwatch.conf.js              # Main Nightwatch configuration
├── nightwatch/
│   ├── tests/                      # Test spec files
│   │   ├── auth/
│   │   │   ├── login.ts
│   │   │   └── registration.ts
│   │   ├── checkout/
│   │   │   └── purchase-flow.ts
│   │   └── search/
│   │       └── product-search.ts
│   ├── page-objects/               # Page Object definitions
│   │   ├── loginPage.ts
│   │   ├── dashboardPage.ts
│   │   └── checkoutPage.ts
│   ├── custom-commands/            # Reusable custom commands
│   │   ├── loginViaApi.ts
│   │   └── clearSession.ts
│   ├── custom-assertions/          # Custom assertion definitions
│   │   └── elementHasCount.ts
│   ├── globals/                    # Global hooks and settings
│   │   └── globals.ts
│   └── fixtures/                   # Test data
│       └── users.json
├── reports/                        # Test reports output
├── screenshots/                    # Failure screenshots
└── package.json
```

## Configuration

### nightwatch.conf.js

```javascript
module.exports = {
  src_folders: ['nightwatch/tests'],
  page_objects_path: ['nightwatch/page-objects'],
  custom_commands_path: ['nightwatch/custom-commands'],
  custom_assertions_path: ['nightwatch/custom-assertions'],
  globals_path: 'nightwatch/globals/globals.js',

  webdriver: {},
  test_workers: {
    enabled: true,
    workers: 'auto',
  },
  test_settings: {
    default: {
      disable_error_log: false,
      launch_url: process.env.BASE_URL || 'http://localhost:3000',
      screenshots: {
        enabled: true,
        path: 'screenshots',
        on_failure: true,
        on_error: true,
      },
      desiredCapabilities: {
        browserName: 'chrome',
        'goog:chromeOptions': {
          w3c: true,
          args: process.env.CI
            ? ['--headless', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage']
            : [],
        },
      },
      globals: {
        waitForConditionTimeout: 10000,
        retryAssertionTimeout: 5000,
      },
    },
    firefox: {
      desiredCapabilities: {
        browserName: 'firefox',
        'moz:firefoxOptions': {
          args: process.env.CI ? ['--headless'] : [],
        },
      },
    },
  },
};
```

## Page Objects

### Login Page Object

```javascript
module.exports = {
  url: function () {
    return `${this.api.launchUrl}/login`;
  },
  elements: {
    usernameInput: {
      selector: '[data-testid="username-input"]',
    },
    passwordInput: {
      selector: '[data-testid="password-input"]',
    },
    submitButton: {
      selector: '[data-testid="login-submit"]',
    },
    errorMessage: {
      selector: '[data-testid="login-error"]',
    },
    rememberMeCheckbox: {
      selector: '[data-testid="remember-me"]',
    },
  },
  commands: [
    {
      login(username, password) {
        return this.waitForElementVisible('@usernameInput')
          .clearValue('@usernameInput')
          .setValue('@usernameInput', username)
          .clearValue('@passwordInput')
          .setValue('@passwordInput', password)
          .click('@submitButton');
      },
      getErrorText(callback) {
        return this.waitForElementVisible('@errorMessage').getText('@errorMessage', (result) => {
          callback(result.value);
        });
      },
    },
  ],
};
```

### Dashboard Page Object

```javascript
module.exports = {
  url: function () {
    return `${this.api.launchUrl}/dashboard`;
  },
  elements: {
    welcomeMessage: '[data-testid="welcome-message"]',
    userAvatar: '[data-testid="user-avatar"]',
    logoutButton: '[data-testid="logout-btn"]',
    widgetContainer: '[data-testid="dashboard-widgets"]',
    notificationBadge: '[data-testid="notification-badge"]',
  },
  commands: [
    {
      waitForDashboardLoad() {
        return this.waitForElementVisible('@welcomeMessage').waitForElementVisible(
          '@widgetContainer'
        );
      },
      logout() {
        return this.click('@logoutButton');
      },
    },
  ],
};
```

## Writing Tests

### Basic Authentication Test

```javascript
describe('User Authentication', function () {
  let loginPage;
  let dashboardPage;

  before(function (browser) {
    loginPage = browser.page.loginPage();
    dashboardPage = browser.page.dashboardPage();
  });

  it('should login with valid credentials', function () {
    loginPage
      .navigate()
      .login('testuser@example.com', 'SecurePass123!')
      .assert.urlContains('/dashboard');

    dashboardPage.waitForDashboardLoad().assert.visible('@welcomeMessage');
  });

  it('should show error with invalid credentials', function (browser) {
    loginPage.navigate().login('invalid@example.com', 'wrongpassword');

    loginPage.getErrorText(function (text) {
      browser.assert.ok(text.includes('Invalid email or password'));
    });
  });

  it('should validate required fields', function () {
    loginPage.navigate().click('@submitButton');
    loginPage.assert.visible('@errorMessage');
  });

  after(function (browser) {
    browser.end();
  });
});
```

### Element Assertions

```javascript
describe('Product Listing Page', function () {
  it('should display products with correct structure', function (browser) {
    browser
      .url(`${browser.launchUrl}/products`)
      .waitForElementVisible('[data-testid="product-grid"]')
      .assert.elementPresent('[data-testid="product-card"]')
      .assert.textContains('[data-testid="page-title"]', 'Products')
      .assert.elementsCount('[data-testid="product-card"]', 12)
      .assert.attributeContains('[data-testid="product-image"]', 'src', 'https://');
  });

  it('should filter products by category', function (browser) {
    browser
      .url(`${browser.launchUrl}/products`)
      .waitForElementVisible('[data-testid="category-filter"]')
      .click('[data-testid="category-electronics"]')
      .waitForElementVisible('[data-testid="product-card"]')
      .assert.textContains('[data-testid="active-filter"]', 'Electronics');

    browser.elements('css selector', '[data-testid="product-card"]', function (result) {
      this.assert.ok(result.value.length > 0, 'Should have filtered products');
    });
  });

  it('should sort products by price', function (browser) {
    browser
      .url(`${browser.launchUrl}/products`)
      .waitForElementVisible('[data-testid="sort-dropdown"]')
      .click('[data-testid="sort-dropdown"]')
      .click('[data-testid="sort-price-asc"]')
      .pause(500) // Wait for re-render
      .assert.textContains('[data-testid="sort-dropdown"]', 'Price: Low to High');
  });
});
```

### Custom Commands

```javascript
// nightwatch/custom-commands/loginViaApi.js
module.exports = {
  command: async function (username, password) {
    const baseUrl = this.api.launchUrl;

    await this.execute(
      function (url, user, pass) {
        return fetch(`${url}/api/auth/login`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ email: user, password: pass }),
        })
          .then((res) => res.json())
          .then((data) => {
            document.cookie = `auth_token=${data.token}; path=/`;
            return data;
          });
      },
      [baseUrl, username, password]
    );

    return this.refresh();
  },
};

// Usage in tests:
// browser.loginViaApi('admin@example.com', 'AdminPass123!')
//   .url(`${browser.launchUrl}/admin`)
//   .assert.visible('[data-testid="admin-panel"]');
```

### Custom Assertions

```javascript
// nightwatch/custom-assertions/elementHasCount.js
exports.assertion = function (selector, expectedCount) {
  this.message = `Testing if element <${selector}> appears ${expectedCount} times`;
  this.expected = expectedCount;

  this.pass = function (value) {
    return value === expectedCount;
  };

  this.value = function (result) {
    return result.value.length;
  };

  this.command = function (callback) {
    return this.api.elements('css selector', selector, callback);
  };
};

// Usage: browser.assert.elementHasCount('[data-testid="cart-item"]', 3)
```

### Multi-Browser Testing

```javascript
describe('Cross-Browser Compatibility', function () {
  it('should render header consistently', function (browser) {
    browser
      .url(browser.launchUrl)
      .waitForElementVisible('[data-testid="site-header"]')
      .assert.visible('[data-testid="logo"]')
      .assert.visible('[data-testid="nav-menu"]')
      .assert.cssProperty('[data-testid="site-header"]', 'display', 'flex');
  });
});
```

## Best Practices

1. **Use Nightwatch's `@element` syntax** from page objects to keep selectors centralized and maintainable. Reference elements as `'@usernameInput'` rather than repeating raw selectors.
2. **Configure `waitForConditionTimeout` globally** in the `globals` section rather than adding explicit waits to every command.
3. **Enable `test_workers`** for parallel execution. Set `workers: 'auto'` to use all available CPU cores for maximum throughput.
4. **Use `assert` for hard assertions** (fail immediately) and `verify` for soft assertions (continue execution and report at the end).
5. **Capture screenshots on failure** via the `screenshots` configuration. Enable both `on_failure` and `on_error` for comprehensive visual debugging.
6. **Implement custom commands** for repetitive multi-step operations like API-based login, clearing sessions, or seeding test data.
7. **Leverage Nightwatch's built-in Selenium manager** -- modern Nightwatch auto-manages browser drivers, eliminating manual driver installation.
8. **Use `--env` flag for multi-browser runs**: `npx nightwatch --env chrome,firefox` to execute tests across browsers in a single command.
9. **Structure tests by feature domain** (auth, checkout, search) rather than by page name. This keeps related behavior tests together.
10. **Set `retryAssertionTimeout`** in globals to automatically retry failing assertions, which handles minor timing issues without explicit waits.

## Anti-Patterns

1. **Using `browser.pause()` for synchronization** -- Arbitrary sleeps make tests slow and unreliable. Use `waitForElementVisible()` or `waitForElementPresent()` instead.
2. **Writing tests that depend on execution order** -- Tests should be fully independent. Use `before`/`beforeEach` hooks for setup, not prior test results.
3. **Hardcoding selectors in test files** -- Duplicating selectors across tests means changing one selector requires updating dozens of files. Use page objects.
4. **Not using page object commands** -- Putting multi-step interactions directly in tests creates duplication. Encapsulate sequences like login flows in page object commands.
5. **Ignoring test worker compatibility** -- Tests that share global variables or browser state fail when run in parallel. Ensure full isolation.
6. **Using `.verify` when `.assert` is needed** -- Soft assertions can mask failures. Use `.assert` for critical checks and `.verify` only when continuing execution is truly desired.
7. **Skipping `browser.end()` in teardown** -- Not closing the browser session causes resource leaks and can make subsequent tests fail.
8. **Nesting describes too deeply** -- More than two levels of nesting makes tests hard to read and maintain. Keep the hierarchy flat.
9. **Using complex XPath expressions** -- XPath is slower and harder to maintain than CSS selectors. Only use XPath when CSS cannot express the query.
10. **Not setting up globals for environment config** -- Hardcoding URLs, timeouts, and credentials in test files prevents running tests across different environments.

## CLI Reference

```bash
# Run all tests
npx nightwatch

# Run specific test file
npx nightwatch nightwatch/tests/auth/login.ts

# Run tests in a specific folder
npx nightwatch --group auth

# Run tests matching a tag
npx nightwatch --tag smoke

# Run against specific browser
npx nightwatch --env firefox

# Run multi-browser
npx nightwatch --env chrome,firefox

# Run in parallel
npx nightwatch --parallel

# Run with verbose output
npx nightwatch --verbose

# Run specific test by name
npx nightwatch --testcase "should login with valid credentials"
```

## Setup

```bash
# Initialize a new Nightwatch project
npm init nightwatch@latest

# Or install manually
npm install --save-dev nightwatch

# For Chrome testing
npm install --save-dev chromedriver

# For TypeScript support
npm install --save-dev typescript ts-node @types/nightwatch

# Create configuration file
npx nightwatch --init
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.