{"id":33333998,"url":"https://github.com/KareemMostafa77/qc-auto-package","last_synced_at":"2025-11-21T14:03:55.367Z","repository":{"id":316953385,"uuid":"1065441899","full_name":"KareemMostafa77/qc-auto-package","owner":"KareemMostafa77","description":null,"archived":false,"fork":false,"pushed_at":"2025-10-29T09:56:41.000Z","size":287,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-10-29T11:42:16.353Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KareemMostafa77.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-27T18:28:24.000Z","updated_at":"2025-10-29T09:56:21.000Z","dependencies_parsed_at":"2025-09-27T21:05:54.635Z","dependency_job_id":"67a4059c-ef7e-4eed-b9e6-c8b667115e32","html_url":"https://github.com/KareemMostafa77/qc-auto-package","commit_stats":null,"previous_names":["kareemmostafa77/qc-auto-package"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/KareemMostafa77/qc-auto-package","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KareemMostafa77%2Fqc-auto-package","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KareemMostafa77%2Fqc-auto-package/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KareemMostafa77%2Fqc-auto-package/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KareemMostafa77%2Fqc-auto-package/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KareemMostafa77","download_url":"https://codeload.github.com/KareemMostafa77/qc-auto-package/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KareemMostafa77%2Fqc-auto-package/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285628306,"owners_count":27204436,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-21T02:00:06.175Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-11-21T01:00:29.350Z","updated_at":"2025-11-21T14:03:55.359Z","avatar_url":"https://github.com/KareemMostafa77.png","language":"TypeScript","funding_links":[],"categories":["Testing"],"sub_categories":["Helpers"],"readme":"# 📘 `ng-qcauto` v2.0\n\n**Effortless, stable test IDs for Angular apps, controlled by testers — not code.**\n\n---\n## 🔎 How IDs Are Generated (v2.0)\n\nIDs follow this pattern: **`qc_{route}_{tag}_{identifier}`**\n\n**Examples**:\n- `/dashboard` route → `qc_dashboard_button_abc123`\n- `/users/profile` route → `qc_users_profile_input_xyz789`\n- Root `/` route → `qc_home_form_loginForm`\n\n**Identifier Logic**:\n1. If element has `data-qc-key` → used directly (`qc_dashboard_li_42`)\n2. Else if element has `id` → reused (`qc_dashboard_form_loginForm`)  \n3. Else → deterministic hash (`qc_dashboard_button_1k9d2`)\n\nIDs remain stable across reloads as long as **route** and **structure** don't change. Overview\n`ng-qcauto` is an Angular utility library that **automatically injects stable `data-qcauto` attributes** into DOM elements.  \n\nIt empowers **QA and test automation teams** by providing **deterministic, human-friendly selectors** without requiring developers to clutter templates with `data-testid`.  \n\n### ✨ Key Features\n- 🔄 **Automatic injection** — works globally, no directives or template edits.  \n- 🎯 **Configurable** — track elements by **tag**, **class**, or **ID**.  \n- 🔑 **Route-based stable IDs** — IDs include route path for better organization.  \n- ⌨️ **Ctrl+Q Modal** — Easy configuration interface without DevTools.  \n- 🖱️ **Right-click to Copy** — Quickly copy QC IDs during testing.  \n- 🧑‍🤝‍🧑 **Tester-friendly** — configuration lives in `localStorage`, manageable via modal.  \n- 🚦 **Test-only mode** — enable in dev/staging, disable in prod.  \n- ⚡ **Lightweight** — observer-based, minimal performance impact.  \n- 🏗 **Angular v14 and below + v15+ support** — works in both module-based and standalone bootstraps.  \n\n---\n\n## 📐 Angular Version Support\n\n| Angular Version | Supported | Setup Type |\n|-----------------|-----------|------------|\n| **v15+**        | ✅ Yes    | Standalone bootstrap (`bootstrapApplication`) |\n| **v14 and below** | ✅ Yes | Module bootstrap (`bootstrapModule(AppModule)`) |\n\n---\n\n## 📦 Installation\n\n```bash\nnpm install ng-qcauto\n```\n\n---\n\n## 🚀 Usage\n\n### 🔹 Angular v14 and Below (Modules)\nFor module-bootstrapped apps:\n\n```ts\n// main.ts\nimport { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\nimport { AppModule } from './app/app.module';\nimport { initQcAutoGlobal } from 'ng-qcauto';\n\nplatformBrowserDynamic()\n  .bootstrapModule(AppModule)\n  .then(() =\u003e initQcAutoGlobal()) // init after Angular bootstraps\n  .catch(err =\u003e console.error(err));\n```\n\n---\n\n### 🔹 Angular v15+ (Standalone)\nFor standalone-bootstrapped apps:\n\n```ts\n// main.ts\nimport { bootstrapApplication } from '@angular/platform-browser';\nimport { AppComponent } from './app/app.component';\nimport { initQcAutoGlobal } from 'ng-qcauto';\n\nbootstrapApplication(AppComponent).then(() =\u003e {\n  initQcAutoGlobal(); // init after bootstrap\n});\n```\n\n---\n\n## 🧑‍💻 Tester Workflow\n\n`ng-qcauto` reads its configuration from **localStorage**.  \n\n### 1️⃣ Open Configuration Modal\nPress **Ctrl+Q** (or **Cmd+Q** on Mac) anywhere in the app to open the configuration modal:\n\n```\n┌─────────────────────────────────────┐\n│  QC Auto Configuration           ✕  │\n├─────────────────────────────────────┤\n│  Tags: button, input, a             │\n│  Classes: btn-primary               │\n│  IDs: saveBtn                       │\n│  ☑ Enable Click-to-Copy QC IDs     │\n│                                     │\n│         [Save \u0026 Reload] [Cancel]    │\n└─────────────────────────────────────┘\n```\n\n**OR** use DevTools Console:\n```js\nlocalStorage.setItem('qcAuto-tags', JSON.stringify(['button','input','a']));\nlocalStorage.setItem('qcAuto-classes', JSON.stringify(['btn-primary']));\nlocalStorage.setItem('qcAuto-ids', JSON.stringify(['saveBtn']));\nlocalStorage.setItem('qcAuto-clickToCopy', 'true');\nlocation.reload();\n```\n\n### 2️⃣ Example Template\n```html\n\u003c!-- On /dashboard route --\u003e\n\u003cbutton\u003eSave\u003c/button\u003e\n\u003cbutton class=\"btn-primary\"\u003eSubmit\u003c/button\u003e\n\u003cform id=\"loginForm\"\u003e ... \u003c/form\u003e\n\n\u003cul\u003e\n  \u003cli *ngFor=\"let user of users\" [attr.data-qc-key]=\"user.id\"\u003e\n    {{ user.name }}\n  \u003c/li\u003e\n\u003c/ul\u003e\n```\n\n### 3️⃣ After Render\n```html\n\u003c!-- On /dashboard route --\u003e\n\u003cbutton data-qcauto=\"qc_dashboard_button_1k9d2\"\u003eSave\u003c/button\u003e\n\u003cbutton class=\"btn-primary\" data-qcauto=\"qc_dashboard_button_btn-primary\"\u003eSubmit\u003c/button\u003e\n\u003cform id=\"loginForm\" data-qcauto=\"qc_dashboard_form_loginForm\"\u003e ... \u003c/form\u003e\n\n\u003cli data-qc-key=\"42\" data-qcauto=\"qc_dashboard_li_42\"\u003eJohn Doe\u003c/li\u003e\n```\n\n### 4️⃣ Copy QC IDs (NEW!)\nWhen **Click-to-Copy** is enabled:\n1. Elements with QC IDs show a **pointer cursor** 👆\n2. **Right-click** any element to copy its QC ID\n3. A toast notification appears: `✓ qc_dashboard_button_1k9d2`\n4. Paste anywhere: `Ctrl+V`\n\n---\n\n## 🔎 How IDs Are Generated\n- If element has `data-qc-key` → used directly (`qc_li_42`).  \n- Else if element has `id` → reused (`qc_form_loginForm`).  \n- Else → deterministic hash (`qc_button_1k9d2`).  \n\nIDs remain stable across reloads as long as structure doesn’t change.\n\n---\n\n## ⚙️ Configuration Reference\n\n### LocalStorage Keys\n- `qcAuto-tags` → Array of tag names (e.g. `['button','input']`)  \n- `qcAuto-classes` → Array of class names (e.g. `['btn-primary']`)  \n- `qcAuto-ids` → Array of element IDs (e.g. `['loginForm']`)  \n- `qcAuto-clickToCopy` → Boolean string (`'true'` or `'false'`) for right-click copy mode\n\n### ⌨️ Keyboard Shortcut\n- **Ctrl+Q** (Windows/Linux) or **Cmd+Q** (Mac) → Opens configuration modal\n- Press again to close modal\n\n### Reset Config\n```js\nlocalStorage.setItem('qcAuto-tags', JSON.stringify([]));\nlocalStorage.setItem('qcAuto-classes', JSON.stringify([]));\nlocalStorage.setItem('qcAuto-ids', JSON.stringify([]));\nlocalStorage.setItem('qcAuto-clickToCopy', 'false');\nlocation.reload();\n```\n\n---\n\n## 🧪 Testing Examples\n\n### Cypress\n```js\n// Full ID\ncy.get('[data-qcauto=\"qc_dashboard_form_loginForm\"]').should('be.visible');\n\n// Pattern matching (all buttons on dashboard)\ncy.get('[data-qcauto^=\"qc_dashboard_button\"]').click();\n\n// By route prefix\ncy.get('[data-qcauto^=\"qc_users_profile\"]').should('exist');\n```\n\nCustom command:\n```js\nCypress.Commands.add('qc', selector =\u003e\n  cy.get(`[data-qcauto=\"${selector}\"]`)\n);\n\n// Usage\ncy.qc('qc_dashboard_form_loginForm').submit();\ncy.qc('qc_users_profile_button_save').click();\n```\n\n### Playwright\n```ts\n// Direct selector\nawait page.locator('[data-qcauto=\"qc_dashboard_li_42\"]').click();\n\n// Route-based pattern\nawait page.locator('[data-qcauto^=\"qc_checkout\"]').count();\n```\n\n### Selenium\n```java\n// Java\nWebElement element = driver.findElement(\n  By.cssSelector(\"[data-qcauto='qc_dashboard_button_submit']\"));\nelement.click();\n```\n\n---\n\n## 🛡 Test-Only Mode\n\nTo disable in production, guard init with environment flags:\n\n```ts\nimport { environment } from './environments/environment';\nimport { initQcAutoGlobal } from 'ng-qcauto';\n\nbootstrapApplication(AppComponent).then(() =\u003e {\n  if (!environment.production) {\n    initQcAutoGlobal();\n  }\n});\n```\n\n---\n\n## ⚡ Performance Notes\n- **Startup**: one-time DOM scan (few ms even for large apps).  \n- **Runtime**: `MutationObserver` handles **only new nodes**.  \n- **Optimized**:\n  - Skips already tagged nodes.  \n  - Filters by config before hashing.  \n  - Uses `data-qc-key` for list stability.  \n\nOverhead is negligible compared to Angular rendering.\n\n---\n\n## 📜 License\nMIT © 2025 – Kareem Mostafa  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKareemMostafa77%2Fqc-auto-package","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FKareemMostafa77%2Fqc-auto-package","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKareemMostafa77%2Fqc-auto-package/lists"}