npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nodebug/selenium

v5.1.9

Published

implementation of seleniumjs to use with test automation

Downloads

3,253

Readme

🌐 WebBrowser

A fluent JavaScript library for browser automation with human-like element location strategy. Write tests and automation scripts that read like user instructions, powered by Selenium WebDriver.

✨ Why WebBrowser?

Traditional approach:

await driver
  .findElement(By.css('input[type="email"]'))
  .sendKeys('[email protected]')

WebBrowser approach:

await browser.textbox('Email').write('[email protected]')

Even better with spatial context:

// "Type in the Email field below the Personal Info section"
await browser
  .textbox('Email')
  .below.element('Personal Info')
  .write('[email protected]')

Quick Links: Installation | Quick Start | Docs | Examples | API Reference

🎯 Key Features

  • 🎯 Human-like element selection - Find elements by what they say, where they are, or their type—just like humans
  • 🔗 Fluent API - Chain methods for readable, maintainable code
  • 🗺️ Spatial context - Locate elements by position: above, below, toLeftOf, toRightOf, within, near
  • 🎭 Semantic selectors - 20+ element types: button, textbox, checkbox, dropdown, dialog, table, etc.
  • 🏗️ Multi-window/tab support - Manage multiple browser contexts and tabs seamlessly
  • 📍 Smart element prioritization - Searches text, placeholders, labels, test IDs, ARIA labels automatically
  • ⌨️ Rich interactions - Click, drag, type, hover, keyboard navigation, file uploads, alerts
  • 📦 Cross-browser - Chrome, Firefox, Safari with same code
  • 🖼️ Automatic iframe handling - Elements inside iframes are found automatically—no manual frame switching required
  • ⚙️ Flexible configuration - JSON config, environment variables, or CLI options
  • 🔍 AI-agent friendly - Clear, readable code that AI can understand and generate

Installation

npm install @nodebug/selenium

Quick Start

1. Configure Browser

Create .config/selenium.json:

{
  "browser": "chrome",
  "headless": false,
  "timeout": 10
}

2. Write Your First Script

import WebBrowser from '@nodebug/selenium'

async function main() {
  const browser = new WebBrowser()

  try {
    await browser.start()
    await browser.goto('https://example.com')

    // Fill login form
    await browser.textbox('Email').write('[email protected]')
    await browser.textbox('Password').write('password123')
    await browser.button('Login').click()

    // Verify success
    await browser.element('Dashboard').should.be.visible()

    console.log('✅ Login successful!')
  } finally {
    await browser.close()
  }
}

main()

📚 Examples

Example 1: Login Form

// Fill email field
await browser.textbox('Email').write('[email protected]')

// Fill password field below email
await browser.textbox('Password').below.textbox('Email').write('secret')

// Check "Remember me" checkbox
await browser.checkbox('Remember me').check()

// Click login button
await browser.button('Login').click()

// Wait for dashboard to appear
await browser.heading('Welcome').should.be.visible()

Example 2: Form with Dropdown

// Fill text field
await browser.textbox('Full Name').write('John Doe')

// Select from dropdown
await browser.dropdown('Country').option('United States').select()

// Check multiple checkboxes
await browser.checkbox('Subscribe').check()
await browser.checkbox('Accept Terms').check()

// Submit form
await browser.button('Register').click()

Example 3: Table Interaction

// Find button in specific row
await browser.button('Delete').within.row('John Doe').click()

// Click edit button for row with ID "user-123"
await browser.button('Edit').within.row('user-123').click()

// Get text from column in matching row
const email = await browser.column('Email').within.row('Jane Smith').get.text()

Example 4: Modal Dialog

// Fill form inside modal
await browser.textbox('Username').within.dialog('Settings').write('newuser')

// Click save button in modal
await browser.button('Save').within.dialog('Settings').click()

// Verify modal closes
await browser.dialog('Settings').should.not.be.visible()

Example 5: Multiple Tabs

// Open new tab
await browser.tab().new()

// Current tab is now the new one
await browser.goto('https://example2.com')

// Switch back to first tab
await browser.tab(0).switch()

// Get URL from first tab
const url = await browser.tab(0).get.url()

🎯 Core Concepts

Three Ways to Find Elements

1. By Type & Text (most common)

await browser.button('Submit').click()
await browser.textbox('Email').write('...')

2. By Position Relative to Others

await browser.button('Delete').below.element('Actions').click()
await browser.textbox('City').toRightOf.textbox('State').write('...')

3. By Attributes (when text doesn't match)

await browser.element('auth-submit').click() // data-testid
await browser.element('user-name').write('...') // id or name

Intermediate vs Terminal Operations

Build selector with intermediate operations (no action yet):

await browser
  .button('Delete') // Select button
  .below // Add position filter
  .element('Actions') // Add anchor element
  .click() // Execute action (terminal)

Terminal operations end the chain and execute:

.click()          // Execute
.write('text')    // Execute
.should.be.visible()  // Assert and execute
.get.text()       // Get value and execute

Element State Methods

Check state (return boolean for conditionals):

const isChecked = await browser.checkbox('Subscribe').is.checked()
const isVisible = await browser.element('Item').is.visible()

if (!isVisible) {
  // Do something
}

Assert state (throw error if assertion fails):

await browser.element('Loading').should.not.be.visible()
await browser.button('Submit').should.be.enabled()

🔗 Spatial References

Find elements by their position—exactly how humans describe them:

| Position | Example | | ----------- | --------------------------------- | | below | button.below.element('Actions') | | above | field.above.heading('Section') | | toLeftOf | icon.toLeftOf.text('Label') | | toRightOf | field.toRightOf.label('Name') | | within | button.within.dialog('Confirm') | | near | button.near.text('Help') |

📖 Documentation Guide

| Document | Purpose | Start Here If... | | --------------------------------------------- | ------------------------ | ---------------------------------- | | GETTING-STARTED.md | Introduction & setup | New to WebBrowser | | CONCEPTS.md | Architecture & patterns | Want to understand how it works | | SELECTORS.md | Finding elements | Need element selection help | | INTERACTIONS.md | Clicks, typing, keyboard | Interacting with elements | | FORMS.md | Form elements | Working with checkboxes, dropdowns | | BROWSER.md | Navigation & windows | Managing browser sessions | | ADVANCED.md | Multi-tab, alerts | Advanced scenarios | | CONFIGURATION.md | Browser setup | Configuring WebBrowser | | API-REFERENCE.md | All methods | Looking up methods |

🤖 For AI Agents

This library is AI-agent friendly. Key points:

  • Readable syntax - Code reads like user instructions
  • Clear semantics - Element types (button, textbox, etc.) are explicit
  • Spatial context - Relationships between elements are obvious
  • Two operation modes - Intermediate (build) vs Terminal (execute) are distinct
  • Consistent patterns - Similar operations across all element types

Example: AI can easily generate this from user instruction "Type email and click submit":

await browser.textbox('Email').write('[email protected]')
await browser.button('Submit').click()

// Find submit button to the right of cancel await browser.button('Submit').toRightOf.button('Cancel').click()

// Find element inside a dialog await browser.textbox('Name').within.dialog('User Settings').write('John')


## Documentation

**Start Here:**

- **[Getting Started](docs/GETTING-STARTED.md)** - Installation, first test, quick examples
- **[Documentation Index](docs/README.md)** - Navigate all guides

**Learning Path:**

- **[Core Concepts](docs/CONCEPTS.md)** - Understand operations, element locators, architecture
- **[Selectors Guide](docs/SELECTORS.md)** - Find elements (text, position, type)
- **[Interactions Guide](docs/INTERACTIONS.md)** - Clicks, input, keyboard, drag-drop
- **[Forms Guide](docs/FORMS.md)** - Checkboxes, switches, dropdowns
- **[Browser Guide](docs/BROWSER.md)** - Navigation, windows, tabs, configuration
- **[Advanced Guide](docs/ADVANCED.md)** - Multi-window, multi-tab, alerts

**Reference:**

- **[API Reference](docs/API-REFERENCE.md)** - Complete method signatures
- **[Configuration](docs/CONFIGURATION.md)** - Browser setup options

## Examples

## Browser Support

| Browser | Status             |
| ------- | ------------------ |
| Chrome  | ✅ Fully supported |
| Firefox | ✅ Fully supported |
| Safari  | ✅ Fully supported |

## Best Practices

1. **Use semantic types** - `button()`, `textbox()` vs generic `element()`
2. **Leverage text matching** - Target visible text when possible
3. **Apply spatial context** - Use `within`, `below`, etc. for precise targeting
4. **Check state before acting** - Verify visibility/disabled state before interaction
5. **Chain operations** - Build fluent chains for readability
6. **Use `is.*` for conditionals** - Returns boolean for branching logic
7. **Use `should.*` for assertions** - Throws error on failure (good for tests)

## Common Patterns

### Waiting for Elements (Implicit Waits)

```javascript
// Will wait up to 30 seconds (configured timeout)
await browser.element('Loading').should.not.be.visible()

Form Submission Pattern

// Fill form fields
await browser.textbox('Email').write('[email protected]')
await browser.textbox('Password').write('password')
await browser.checkbox('Accept Terms').check()

// Submit and wait for success
await browser.button('Submit').click()
await browser.element('Success Message').should.be.visible()

Conditional Logic

// Check state and act accordingly
if (await browser.element('Premium').is.visible()) {
  await browser.button('Upgrade').click()
} else {
  await browser.button('Try Now').click()
}

Table Row Operations

// Find and click button in specific row
await browser.button('Edit').within.row('John Doe').click()

// Verify row is deleted
await browser.row('John Doe').should.not.be.visible()

API Quick Reference

Element Types: button, textbox, checkbox, radio, dropdown, link, heading, image, file, dialog, row, column, and more

Clicks: click(), doubleClick(), tripleClick(), rightClick(), multipleClick(times)

Text Input: write(), clear(), overwrite(), type(), press(), left(), right(), up(), down()

Form Elements: check(), uncheck(), set(), on(), off(), option(), select()

Element State: is.visible(), is.enabled(), is.checked(), should.be.visible(), should.be.disabled()

Data Retrieval: get.text(), get.value(), get.attribute(), get.screenshot()

Navigation: goto(), refresh(), goBack(), goForward(), scroll()

Visibility: hide(), unhide()

Windows/Tabs/Alerts: window(), tab(), alert()

Spatial Positioning: above, below, toLeftOf, toRightOf, within, near, exactly, or, exact, atIndex()

Drag & Drop: drag(), onto(), drop()

Upload: upload(filePath)

Keyboard Modifiers: ctrl, alt, meta, shift (chain before actions)

See API-REFERENCE.md for complete reference.

Troubleshooting

Element not found? - Check SELECTORS.md for matching strategy

Element found but not clickable? - Try spatial context: .within.dialog(), .below.element()

Timeout waiting for element? - Increase timeout in config or add should.be.visible() explicitly

Need more help? - See docs/README.md for complete documentation index

License

MPL-2.0

Contributing

Issues and pull requests welcome on GitHub.