acquiescence
v0.1.7
Published
Library for querying and waiting for element states
Readme
Acquiescence
A powerful TypeScript library for querying and waiting for element states in the browser
Overview
Acquiescence provides sophisticated element state querying and interaction readiness detection for web applications. It goes far beyond simple existence checks to determine if elements are truly ready for user interaction.
Perfect for:
- 🧪 End-to-end testing frameworks
- 🤖 Browser automation tools
- 🎨 Interactive UI frameworks
- ♿ Accessibility testing tools
- ✅ Any scenario requiring reliable element state detection
Features
- 🔍 Query Element States - Check visibility, enabled/disabled state, ability to enter text, viewport position, and more with a simple, intuitive API
- ⏱️ Wait for Interactions - Automatically wait for elements to be ready for interaction, with built-in stability detection and smart scrolling
- 🎯 Precise Hit Testing - Determine exact click points and detect element obstruction with accurate hit testing that respects Shadow DOM
- 🚀 TypeScript First - Built with TypeScript for excellent type safety and IntelliSense support in your IDE
- 🌐 Shadow DOM Support - Full support for Shadow DOM, including closed shadow roots and composed tree traversal
- ⚡ Performance Optimized - Smart caching of computed styles and efficient polling strategies for minimal performance impact
Installation
npm install acquiescenceyarn add acquiescencepnpm add acquiescenceQuick Start
import { ElementStateInspector } from 'acquiescence';
const inspector = new ElementStateInspector();
const button = document.querySelector('#submit-button');
// Check if an element is visible and enabled
const result = await inspector.queryElementStates(button, ['visible', 'enabled']);
if (result.status === 'success') {
console.log('Button is ready!');
} else {
console.log(`Button is ${result.missingState}`);
}
// Wait for an element to be ready for interaction
try {
const hitPoint = await inspector.waitForInteractionReady(
button,
'click',
5000 // 5 second timeout
);
console.log(`Element ready at point (${hitPoint.x}, ${hitPoint.y})`);
} catch (error) {
console.error('Element not ready within timeout');
}Usage Examples
Querying Element States
Check various states of DOM elements:
const input = document.querySelector('input');
// Check a single state
const visibleResult = await inspector.queryElementState(input, 'visible');
console.log(visibleResult.matches); // true or false
// Check multiple states
const result = await inspector.queryElementStates(
input,
['visible', 'enabled', 'editable']
);
if (result.status === 'success') {
console.log('Input is ready for typing!');
} else if (result.status === 'failure') {
console.log(`Input is not ready: ${result.missingState}`);
}Available Element States
| State | Description |
|-------|-------------|
| visible | Element is visible (has positive size, not hidden by CSS) |
| hidden | Element is not visible |
| enabled | Element is not disabled |
| disabled | Element is disabled (via disabled attribute or aria-disabled) |
| editable | Element can accept text input (not disabled or readonly) |
| inview | Element is currently visible in the viewport |
| notinview | Element is not in viewport but could be scrolled into view |
| unviewable | Element cannot be scrolled into view (hidden by overflow) |
| stable | Element's position hasn't changed for at least one animation frame |
Checking Interaction Readiness
const button = document.querySelector('button');
const result = await inspector.isInteractionReady(button, 'click');
if (result.status === 'ready') {
console.log('Ready to click at:', result.interactionPoint);
} else if (result.status === 'needsscroll') {
console.log('Element needs to be scrolled into view');
} else {
console.log('Element is not ready for interaction');
}Waiting for Interaction Readiness
const button = document.querySelector('button');
try {
const hitPoint = await inspector.waitForInteractionReady(
button,
'click',
5000 // 5 second timeout
);
console.log(`Ready to click at (${hitPoint.x}, ${hitPoint.y})`);
// Perform your click action here
} catch (error) {
console.error('Element not ready within timeout:', error.message);
}Note: waitForInteractionReady() automatically scrolls elements into view if they're not currently visible in the viewport.
Supported Interaction Types
click- Single clickdblclick- Double clickhover- Mouse hovertype- Text inputclear- Clear input fielddrag- Drag operationscreenshot- Screenshot capture
Helper Methods
For simple checks, use the helper methods:
const element = document.querySelector('.my-element');
// Check visibility
if (inspector.isElementVisible(element)) {
console.log('Element is visible');
}
// Check if disabled
if (inspector.isElementDisabled(element)) {
console.log('Element is disabled');
}
// Check if read-only
const readOnly = inspector.isElementReadOnly(element);
if (readOnly === true) {
console.log('Element is read-only');
} else if (readOnly === false) {
console.log('Element is editable');
}Browser Support
Acquiescence can be used in both Node.js environments (with jsdom) and directly in the browser.
Browser Bundle
For direct browser usage, a bundled version is available:
<script src="node_modules/acquiescence/dist/acquiescence.browser.js"></script>
<script>
const inspector = new Acquiescence.ElementStateInspector();
// Use the inspector
</script>API Reference
ElementStateInspector
The main class for querying element states and waiting for interactions.
Methods
queryElementState(element, state)- Check a single element statequeryElementStates(element, states)- Check multiple element statesisInteractionReady(element, interactionType)- Check if element is ready for interactionwaitForInteractionReady(element, interactionType, timeout)- Wait for element to be readyisElementVisible(element)- Helper to check visibilityisElementDisabled(element)- Helper to check disabled stateisElementReadOnly(element)- Helper to check read-only state
For complete API documentation, see the full API reference.
Documentation
For more detailed documentation, guides, and examples, visit:
Development
Setup
# Clone the repository
git clone https://github.com/jimevans/acquiescence.git
cd element-state
# Install dependencies
npm install
# Build the project
npm run build
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build documentation
npm run docs:build
# Serve documentation locally
npm run docs:devScripts
npm run build- Build the TypeScript projectnpm run build:browser- Build the browser bundlenpm test- Run testsnpm run test:watch- Run tests in watch modenpm run test:coverage- Run tests with coveragenpm run lint- Run linternpm run lint:fix- Fix linting issuesnpm run docs:dev- Start documentation dev servernpm run docs:build- Build documentation
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Why "Acquiescence"?
Acquiescence means "the reluctant acceptance of something without protest" - which perfectly describes what this library helps you do: wait patiently (but efficiently!) for elements to reach the state you need them to be in, without constantly polling or throwing errors.
Related Projects
- Selenium - Browser automation framework
- WebdriverIO - Browser and mobile automation
- Puppeteer - Chrome DevTools Protocol
- Testing Library - Simple and complete testing utilities
Made with ❤️ by the Acquiescence team
