Skip to content

KareemMostafa77/qc-auto-package

Repository files navigation

πŸ“˜ ng-qcauto v2.0

Effortless, stable test IDs for Angular apps, controlled by testers β€” not code.


πŸ”Ž How IDs Are Generated (v2.0)

IDs follow this pattern: qc_{route}_{tag}_{identifier}

Examples:

  • /dashboard route β†’ qc_dashboard_button_abc123
  • /users/profile route β†’ qc_users_profile_input_xyz789
  • Root / route β†’ qc_home_form_loginForm

Identifier Logic:

  1. If element has data-qc-key β†’ used directly (qc_dashboard_li_42)
  2. Else if element has id β†’ reused (qc_dashboard_form_loginForm)
  3. Else β†’ deterministic hash (qc_dashboard_button_1k9d2)

IDs remain stable across reloads as long as route and structure don't change. 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.
  • πŸ”‘ Route-based stable IDs β€” IDs include route path for better organization.
  • ⌨️ Ctrl+Q Modal β€” Easy configuration interface without DevTools.
  • πŸ–±οΈ Right-click to Copy β€” Quickly copy QC IDs during testing.
  • πŸ§‘β€πŸ€β€πŸ§‘ Tester-friendly β€” configuration lives in localStorage, manageable via modal.
  • 🚦 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️⃣ Open Configuration Modal

Press Ctrl+Q (or Cmd+Q on Mac) anywhere in the app to open the configuration modal:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  QC Auto Configuration           βœ•  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Tags: button, input, a             β”‚
β”‚  Classes: btn-primary               β”‚
β”‚  IDs: saveBtn                       β”‚
β”‚  β˜‘ Enable Click-to-Copy QC IDs     β”‚
β”‚                                     β”‚
β”‚         [Save & Reload] [Cancel]    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

OR use DevTools Console:

localStorage.setItem('qcAuto-tags', JSON.stringify(['button','input','a']));
localStorage.setItem('qcAuto-classes', JSON.stringify(['btn-primary']));
localStorage.setItem('qcAuto-ids', JSON.stringify(['saveBtn']));
localStorage.setItem('qcAuto-clickToCopy', 'true');
location.reload();

2️⃣ Example Template

<!-- On /dashboard route -->
<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

<!-- On /dashboard route -->
<button data-qcauto="qc_dashboard_button_1k9d2">Save</button>
<button class="btn-primary" data-qcauto="qc_dashboard_button_btn-primary">Submit</button>
<form id="loginForm" data-qcauto="qc_dashboard_form_loginForm"> ... </form>

<li data-qc-key="42" data-qcauto="qc_dashboard_li_42">John Doe</li>

4️⃣ Copy QC IDs (NEW!)

When Click-to-Copy is enabled:

  1. Elements with QC IDs show a pointer cursor πŸ‘†
  2. Right-click any element to copy its QC ID
  3. A toast notification appears: βœ“ qc_dashboard_button_1k9d2
  4. Paste anywhere: Ctrl+V

πŸ”Ž 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'])
  • qcAuto-clickToCopy β†’ Boolean string ('true' or 'false') for right-click copy mode

⌨️ Keyboard Shortcut

  • Ctrl+Q (Windows/Linux) or Cmd+Q (Mac) β†’ Opens configuration modal
  • Press again to close modal

Reset Config

localStorage.setItem('qcAuto-tags', JSON.stringify([]));
localStorage.setItem('qcAuto-classes', JSON.stringify([]));
localStorage.setItem('qcAuto-ids', JSON.stringify([]));
localStorage.setItem('qcAuto-clickToCopy', 'false');
location.reload();

πŸ§ͺ Testing Examples

Cypress

// Full ID
cy.get('[data-qcauto="qc_dashboard_form_loginForm"]').should('be.visible');

// Pattern matching (all buttons on dashboard)
cy.get('[data-qcauto^="qc_dashboard_button"]').click();

// By route prefix
cy.get('[data-qcauto^="qc_users_profile"]').should('exist');

Custom command:

Cypress.Commands.add('qc', selector =>
  cy.get(`[data-qcauto="${selector}"]`)
);

// Usage
cy.qc('qc_dashboard_form_loginForm').submit();
cy.qc('qc_users_profile_button_save').click();

Playwright

// Direct selector
await page.locator('[data-qcauto="qc_dashboard_li_42"]').click();

// Route-based pattern
await page.locator('[data-qcauto^="qc_checkout"]').count();

Selenium

// Java
WebElement element = driver.findElement(
  By.cssSelector("[data-qcauto='qc_dashboard_button_submit']"));
element.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

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published