JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 22
  • Score
    100M100P100Q74841F
  • License MIT

Effortless, stable test IDs for Angular apps - automatically injects data-qcauto attributes for reliable test automation and QA without cluttering templates

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-key in 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: MutationObserver handles only new nodes.
  • Optimized:
    • Skips already tagged nodes.
    • Filters by config before hashing.
    • Uses data-qc-key for list stability.

Overhead is negligible compared to Angular rendering.


πŸ“œ License

MIT Β© 2025 – Kareem Mostafa