neverbroken
v3.2.0
Published
Semantic DOM selector library with built-in fallbacks. Use meaningful names instead of fragile CSS selectors!
Maintainers
Readme
neverbroken
Semantic DOM selector library with built-in fallbacks. Use meaningful names instead of fragile CSS selectors - works instantly!
Installation
npm install neverbrokenQuick Start
// Multiple import styles - works instantly, no setup required!
// Option 1: Class-based (purist-friendly)
import NeverBroken from 'neverbroken';
const nb = NeverBroken.create();
// Option 2: Short instance (pragmatic)
import { nb } from 'neverbroken';
// Option 3: Factory function
import { createNeverBroken } from 'neverbroken';
const nb = createNeverBroken();
// Option 4: Document augmentation (optional)
import 'neverbroken/augment';
// Ready to use immediately!
// Use semantic selectors that work instantly
const submitButton = nb.submitButton(); // Note: call as function
const userAvatar = nb.user.avatar();
const loginForm = nb.forms.login();Two Main Use Cases
🎯 Script Injection (Primary Purpose)
For automating external websites by injecting scripts:
// Injected into target website
const nb = NeverBroken.create({ debug: true });
const loginButton = nb.submitButton(); // Finds login button on target site
loginButton.click(); // Automate the external site🏠 Self-DOM Usage (Your Own App)
For testing or automating your own application:
// In your own Svelte/React/Vue app
const nb = NeverBroken.create({ debug: true });
// Scan your DOM to discover available selectors
const available = nb.scan();
console.table(available); // Shows what NeverBroken can find
// Add custom mappings for your components
nb.addComponentMapping('myButton', '.my-custom-btn-class');
nb.addComponentMapping('userCard', '[data-testid="user-card"]');
// Now use your custom semantic names
const button = nb.myButton();
const card = nb.userCard();API Reference
Import Styles (Pick Your Preference)
// 🎓 JavaScript Purist Style
import NeverBroken from 'neverbroken';
const nb = new NeverBroken();
// or
const nb = NeverBroken.create();
// 🚀 Pragmatic Style
import { nb, createNeverBroken } from 'neverbroken';
const selector = createNeverBroken();
// 📖 Document Augmentation Style
import 'neverbroken/augment';
const button = document.nb.submitButton;
// or
const button = document.neverbroken.submitButton;
const element = document.nbQuerySelector('userAvatar');
// 🔗 Legacy Compatibility
import { neverbroken } from 'neverbroken';
// Ready to use immediately!Multiple Syntax Options
// Using any instance (nb, selector, document.nb, etc.):
// Option 1: Familiar DOM API (easy migration)
const avatar = nb.querySelector('userAvatar');
const buttons = nb.querySelectorAll('submitButton');
// Option 2: Clean semantic properties
const avatar = nb.userAvatar;
const submitBtn = nb.submitButton;
// Option 3: Nested semantic organization
const avatar = nb.user.avatar;
const submitBtn = nb.form.submitButton;
const closeBtn = nb.modal.closeButton;
// Option 4: Fluent/chainable API
const modal = nb.find('modalDialog')
.waitFor(1000)
.withAttribute('open')
.first();Configuration
// Optional configuration (works instantly without any config!)
nb.configure({
fallbackStrategy: 'graceful', // 'graceful' or 'strict'
cacheTimeout: 5000, // Cache timeout in ms
debug: true // Enable debug logging
});
// Or configure during creation
const nb = NeverBroken.create({
debug: process.env.NODE_ENV === 'development',
fallbackStrategy: 'graceful'
});Convenience Methods
// Direct element interaction (works with any instance)
nb.submitButton.click();
nb.searchInput.focus();
nb.emailInput.value('[email protected]');
// Async resolution for dynamic content
const element = await nb.userAvatar.async();
// Document augmentation style (both work)
document.nb.submitButton.click();
document.neverbroken.submitButton.click();
const modal = await document.nbFind('modal').first();TypeScript Support
// Extend with your app-specific selectors
declare module 'neverbroken' {
interface NeverBrokenSelectors {
myCustomButton: ElementGetter<HTMLButtonElement>;
myApp: {
header: ElementGetter<HTMLElement>;
sidebar: ElementGetter<HTMLElement>;
};
}
}
// Full type safety and autocomplete
const button: HTMLButtonElement = nb.myCustomButton;
const header: HTMLElement = nb.myApp.header;How It Works
- Semantic Mapping - Use meaningful names instead of fragile CSS selectors
- Built-in Fallbacks - Smart built-in mapping for common UI elements
- Smart Caching - Intelligent caching with TTL for optimal performance
- Instant Use - Works immediately without any configuration or API keys
- Extensible - Add your own semantic mappings for custom elements
Common Semantic Selectors
Forms
submitButton,cancelButton,closeButtonemailInput,passwordInput,searchInputloginForm,registerForm,contactForm
Navigation
navigationMenu,headerLogo,userMenu,cartIconbreadcrumbs,searchInput
Content
mainContent,sidebar,footermodal,modalContent,modalOverlay
User Elements
userAvatar,userName,userProfile,userSettings
Advanced Features
Built-in Semantic Mappings
NeverBroken includes smart built-in mappings for common UI patterns:
// These work instantly out of the box
const button = nb.submitButton; // → button[type="submit"]
const input = nb.emailInput; // → input[type="email"]
const avatar = nb.userAvatar; // → .avatar, .user-avatar, .profile-pictureSelf-DOM Utilities
Perfect for testing and automating your own applications:
Scan Your DOM
// Discover available selectors in your app
const available = nb.scan({
includeClasses: true,
includeIds: true,
includeDataAttributes: true,
maxResults: 20
});
console.table(available);
// Shows: type, selector, suggested semantic name, element, textCustom Component Mappings
// Add mappings for your specific components
nb.addComponentMapping('myButton', '.my-custom-button-class');
nb.addComponentMapping('userCard', '[data-testid="user-card"]');
nb.addComponentMapping('navMenu', '#navigation-menu');
// Batch add multiple mappings
nb.addComponentMappings({
'submitBtn': '.submit-button',
'cancelBtn': '.cancel-button',
'userProfile': '[data-user-profile]'
});
// Now use your semantic names
const button = nb.myButton();
const card = nb.userCard();Smart Error Messages
When NeverBroken can't find elements in self-DOM usage, it provides helpful suggestions:
// Enable debug mode for helpful error messages
const nb = NeverBroken.create({ debug: true });
// If this fails, you'll get suggestions
const missing = nb.nonExistentButton();
// Console output:
// [NeverBroken] Self-DOM Warning: Could not find element for 'nonExistentButton'
// [NeverBroken] Suggestions for self-DOM usage:
// 1. Add custom mapping: nb.addComponentMapping('nonExistentButton', 'your-selector')
// 2. Scan your DOM: nb.scan() to discover available selectors
// 3. Use data attributes: <div data-automation="nonExistentButton">...</div>
// 4. Similar selectors found: ['.existing-button', '#submit-btn']Fallback Strategies
nb.configure({
fallbackStrategy: 'graceful' // Uses semantic name as CSS selector if no mapping found
// fallbackStrategy: 'strict' // Throws error if no mapping found
});Examples
E-commerce Site
const addToCart = nb.product.addToCartButton;
const priceDisplay = nb.product.price;
const cartCounter = nb.navigation.cartCounter;Form Handling
const email = nb.forms.login.emailInput;
const password = nb.forms.login.passwordInput;
const submit = nb.forms.login.submitButton;
submit.click();Modal Interactions
const confirmDialog = nb.modal;
const confirmBtn = nb.modal.confirmButton;
const cancelBtn = nb.modal.cancelButton;Migration from Standard DOM Selectors
// Before
const button = document.querySelector('.btn-primary.submit-form');
const inputs = document.querySelectorAll('input[type="text"]');
// After (any style works)
const button = nb.submitButton;
const inputs = nb.textInputs;
// Or with document augmentation (both work)
const button = document.nb.submitButton;
const button = document.neverbroken.submitButton;
const inputs = document.nb.textInputs;Why These Import Styles?
We provide multiple import patterns to respect different JavaScript philosophies:
🎓 Purist-Friendly (NeverBroken class)
- ✅ Follows PascalCase class conventions
- ✅ Clear factory pattern with
.create() - ✅ No global pollution
- ✅ Explicit instantiation
🚀 Pragmatic ({ nb } instance)
- ✅ Short, easy to type
- ✅ Ready to use immediately
- ✅ No ceremony, just results
- ✅ Similar to jQuery
$
📖 Document Augmentation (opt-in)
- ✅ Familiar
document.*pattern - ✅ Non-invasive (requires explicit import)
- ✅ Both
document.nbanddocument.neverbrokenavailable - ✅ Zero naming conflicts
- ✅ Works with existing codebases
🔗 Legacy Compatibility (neverbroken)
- ✅ Maintains backward compatibility
- ✅ Smooth migration path
- ✅ No breaking changes
License
Proprietary - See LICENSE.txt for full terms
