Package Exports
- ng-qcauto
- ng-qcauto/package.json
Readme
π ng-qcauto
Effortless, stable test IDs for Angular apps, controlled by testers β not code.
π Overview
ng-qcauto is an Angular utility library that automatically injects stable data-qcauto attributes into DOM elements.
It empowers QA and test automation teams by providing deterministic, human-friendly selectors without requiring developers to clutter templates with data-testid.
β¨ Key Features
- π Automatic injection β works globally, no directives or template edits.
- π― Configurable β track elements by tag, class, or ID.
- π Stable IDs β deterministic hashes, with support for
data-qc-keyin lists. - π§βπ€βπ§ Tester-friendly β configuration lives in
localStorage, editable in DevTools. - π¦ Test-only mode β enable in dev/staging, disable in prod.
- β‘ Lightweight β observer-based, minimal performance impact.
- π Angular v14 and below + v15+ support β works in both module-based and standalone bootstraps.
π Angular Version Support
| Angular Version | Supported | Setup Type |
|---|---|---|
| v15+ | β Yes | Standalone bootstrap (bootstrapApplication) |
| v14 and below | β Yes | Module bootstrap (bootstrapModule(AppModule)) |
π¦ Installation
npm install ng-qcautoπ Usage
πΉ Angular v14 and Below (Modules)
For module-bootstrapped apps:
// main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { initQcAutoGlobal } from 'ng-qcauto';
platformBrowserDynamic()
.bootstrapModule(AppModule)
.then(() => initQcAutoGlobal()) // init after Angular bootstraps
.catch(err => console.error(err));πΉ Angular v15+ (Standalone)
For standalone-bootstrapped apps:
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { initQcAutoGlobal } from 'ng-qcauto';
bootstrapApplication(AppComponent).then(() => {
initQcAutoGlobal(); // init after bootstrap
});π§βπ» Tester Workflow
ng-qcauto reads its configuration from localStorage.
1. Add Targets in DevTools
localStorage.setItem('qcAuto-tags', JSON.stringify(['button','input','a']));
localStorage.setItem('qcAuto-classes', JSON.stringify(['btn-primary']));
localStorage.setItem('qcAuto-ids', JSON.stringify(['saveBtn']));
location.reload();2. Example Template
<button>Save</button>
<button class="btn-primary">Submit</button>
<form id="loginForm"> ... </form>
<ul>
<li *ngFor="let user of users" [attr.data-qc-key]="user.id">
{{ user.name }}
</li>
</ul>3. After Render
<button data-qcauto="qc_button_1k9d2">Save</button>
<button class="btn-primary" data-qcauto="qc_button_btn-primary">Submit</button>
<form id="loginForm" data-qcauto="qc_form_loginForm"> ... </form>
<li data-qc-key="42" data-qcauto="qc_li_42">John Doe</li>π How IDs Are Generated
- If element has
data-qc-keyβ used directly (qc_li_42). - Else if element has
idβ reused (qc_form_loginForm). - Else β deterministic hash (
qc_button_1k9d2).
IDs remain stable across reloads as long as structure doesnβt change.
βοΈ Configuration Reference
LocalStorage Keys
qcAuto-tagsβ Array of tag names (e.g.['button','input'])qcAuto-classesβ Array of class names (e.g.['btn-primary'])qcAuto-idsβ Array of element IDs (e.g.['loginForm'])
Reset Config
localStorage.setItem('qcAuto-tags', JSON.stringify([]));
localStorage.setItem('qcAuto-classes', JSON.stringify([]));
localStorage.setItem('qcAuto-ids', JSON.stringify([]));
location.reload();π§ͺ Testing Examples
Cypress
cy.get('[data-qcauto="qc_form_loginForm"]').should('be.visible');
cy.get('[data-qcauto^="qc_button"]').click();Custom command:
Cypress.Commands.add('qc', selector =>
cy.get(`[data-qcauto="${selector}"]`)
);
// Usage
cy.qc('qc_form_loginForm').submit();Playwright
await page.locator('[data-qcauto="qc_li_42"]').click();π‘ Test-Only Mode
To disable in production, guard init with environment flags:
import { environment } from './environments/environment';
import { initQcAutoGlobal } from 'ng-qcauto';
bootstrapApplication(AppComponent).then(() => {
if (!environment.production) {
initQcAutoGlobal();
}
});β‘ Performance Notes
- Startup: one-time DOM scan (few ms even for large apps).
- Runtime:
MutationObserverhandles only new nodes. - Optimized:
- Skips already tagged nodes.
- Filters by config before hashing.
- Uses
data-qc-keyfor list stability.
Overhead is negligible compared to Angular rendering.
π License
MIT Β© 2025 β Kareem Mostafa