An open API service indexing awesome lists of open source software.

https://github.com/KareemMostafa77/qc-auto-package


https://github.com/KareemMostafa77/qc-auto-package

Last synced: 7 days ago
JSON representation

Awesome Lists containing this project

README

          

# πŸ“˜ `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

```bash
npm install ng-qcauto
```

---

## πŸš€ Usage

### πŸ”Ή Angular v14 and Below (Modules)
For module-bootstrapped apps:

```ts
// 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:

```ts
// 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:
```js
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
```html

Save
Submit
...



  • {{ user.name }}


```

### 3️⃣ After Render
```html

Save
Submit
...

  • John Doe

  • ```

    ### 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
    ```js
    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
    ```js
    // 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:
    ```js
    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
    ```ts
    // 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
    // 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:

    ```ts
    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