diff --git a/.github/coverage-badge.svg b/.github/coverage-badge.svg
new file mode 100644
index 0000000..7230db3
--- /dev/null
+++ b/.github/coverage-badge.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c709d51..ff400a1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -6,7 +6,7 @@ on:
pull_request:
permissions:
- contents: read
+ contents: write
jobs:
verify:
@@ -30,5 +30,67 @@ jobs:
- name: Test with coverage
run: npm run test:coverage
+ - name: Publish coverage summary
+ if: always()
+ shell: bash
+ run: |
+ if [ -f coverage/coverage-summary.json ]; then
+ node <<'NODE'
+ const fs = require('fs');
+ const data = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8')).total;
+ const format = (value) => `${value.pct.toFixed(2)}%`;
+ const lines = [
+ '## Coverage',
+ '',
+ '| Metric | Coverage |',
+ '| --- | ---: |',
+ `| Statements | ${format(data.statements)} |`,
+ `| Branches | ${format(data.branches)} |`,
+ `| Functions | ${format(data.functions)} |`,
+ `| Lines | ${format(data.lines)} |`,
+ '',
+ ];
+ fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, lines.join('\n'));
+ NODE
+ else
+ printf '%s\n' '## Coverage' '' 'Coverage report was not generated.' >> "$GITHUB_STEP_SUMMARY"
+ fi
+
+ - name: Upload coverage report
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: dehtml-coverage
+ path: coverage/
+ if-no-files-found: warn
+ retention-days: 14
+
- name: Build
run: npm run build
+
+ - name: Update coverage badge
+ if: success() && github.ref == 'refs/heads/main'
+ shell: bash
+ run: |
+ node <<'NODE'
+ const fs = require('fs');
+ const data = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8')).total;
+ const pct = data.lines.pct.toFixed(2);
+ const numeric = Number(data.lines.pct);
+ const color = numeric >= 90 ? '#4c1' : numeric >= 75 ? '#dfb317' : '#e05d44';
+ const label = 'Coverage';
+ const value = `${pct}%`;
+ const left = 93;
+ const right = 117;
+ const svg = ``;
+ fs.writeFileSync('.github/coverage-badge.svg', svg);
+ NODE
+ git config user.name "github-actions[bot]"
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ git add .github/coverage-badge.svg
+ if git diff --cached --quiet; then
+ echo "Coverage badge is already current."
+ else
+ git commit -m "chore(ci): update coverage badge"
+ git push origin HEAD:main
+ fi
diff --git a/README.md b/README.md
index f33edfb..3464669 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# DeHTML Studio
+[](https://github.com/aaqib-hafeez-khan-in/DeHTML/actions/workflows/ci.yml) [](https://github.com/aaqib-hafeez-khan-in/DeHTML/actions/workflows/ci.yml)
+
A modern, fast, and secure toolkit for HTML manipulation built with React and Vite. Experience a clean, professional interface with powerful built-in tools.
## Features
@@ -52,12 +54,22 @@ The application is pre-configured for GitHub pages deployment (`base: '/DeHTML/'
## Testing
-This project uses Vitest and React Testing Library for standard unit tests. To run tests:
+This project uses Vitest and React Testing Library for unit tests and V8 coverage reporting.
+
+Run the tests:
```bash
npm test
```
+Run the tests with coverage:
+
+```bash
+npm run test:coverage
+```
+
+Every CI run publishes the coverage report as a downloadable artifact and displays Statements, Branches, Functions, and Lines coverage in the GitHub Actions job summary. Successful `main` runs also update the coverage badge above automatically.
+
## Legacy Support
The previous vanilla JavaScript implementation is preserved in the `/legacy` folder and remains accessible via the `/legacy/index.html` path in production.