Skip to content
Draft
133 changes: 133 additions & 0 deletions .github/scripts/ui-code-coverage.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import fs from "fs";

const readJson = (filePath) => {
try {
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
} catch (e) {
throw new Error(`Failed to read or parse JSON at ${filePath}: ${e.message}`);
}
};


const findTotalPercentage = (rawData) => {
let totalLineCovered = 0;
let totalLineTotal = 0;
let totalBranchCovered = 0;
let totalBranchTotal = 0;

for (const [, data] of Object.entries(rawData)) {
const lineData = data.lines;
const branchData = data.branches;

totalLineCovered += lineData.covered;
totalLineTotal += lineData.total;

totalBranchCovered += branchData.covered;
totalBranchTotal += branchData.total;
}

const totalLinePct =
totalLineTotal === 0 ? 100 : (totalLineCovered / totalLineTotal) * 100;
const totalBranchPct =
totalBranchTotal === 0
? 100
: (totalBranchCovered / totalBranchTotal) * 100;


return [totalLinePct, totalBranchPct];
};


// @ts-check
/** @param {import('@actions/github-script').AsyncFunctionArguments} AsyncFunctionArguments */
export default async ({ github, context }) => {
const prCoveragePath = "/tmp/pr-coverage.json";
const developCoveragePath = "/tmp/develop-coverage.json";

console.log("🧪 Loaded latest ui-code-coverage.mjs script version");

// const developCoveragePath = '../../ui/coverage/coverage-summary.json';
// const prCoveragePath = '../../ui/coverage/coverage-summary.json';

// const prCoverage = JSON.parse(fs.readFileSync('/tmp/pr-coverage.json', 'utf8'));
// const devCoverage = JSON.parse(fs.readFileSync('/tmp/develop-coverage.json', 'utf8'));

const developCoverage = readJson(developCoveragePath);
const prCoverage = readJson(prCoveragePath);

const [prLinePct, prBranchPct] = findTotalPercentage(prCoverage);
const [developLinePct, developBranchPct] = findTotalPercentage(developCoverage);

// core.info("📊 Total Coverage Summary For PR");
// core.info("--------------------------");
// core.info(`✅ Line Coverage: ${prLinePct.toFixed(2)}%`);
// core.info(`✅ Branch Coverage: ${prBranchPct.toFixed(2)}%`);

// core.info("📊 Total Coverage Summary For Develop");
// core.info("--------------------------");
// core.info(`✅ Line Coverage: ${developLinePct.toFixed(2)}%`);
// core.info(`✅ Branch Coverage: ${developBranchPct.toFixed(2)}%`);

const lineDiff = prLinePct - developLinePct;
const branchDiff = prBranchPct - developBranchPct;

let status = "unchanged";
if (lineDiff > 0 || branchDiff > 0) {
status = "increased";
} else if (lineDiff < 0 || branchDiff < 0) {
status = "decreased";
}

const lineStatus =
lineDiff > 0
? "🟢 Increased"
: lineDiff < 0
? "🔴 Decreased"
: "⚪ Unchanged";
const branchStatus =
branchDiff > 0
? "🟢 Increased"
: branchDiff < 0
? "🔴 Decreased"
: "⚪ Unchanged";

const message = `
## 🧪 Frontend Code Coverage Report ${status === 'increased' ? '🎉' : status === 'decreased' ? '⚠️' : '🔄'}\n\n

| Metric | PR | Base (develop) | Change | Status |
|--------|----|----------------|--------|--------|
| Line Coverage | ${prLinePct.toFixed(2)}% | ${developLinePct.toFixed(2)}% | ${lineDiff.toFixed(2)}% | ${lineStatus} |
| Branch Coverage | ${prBranchPct.toFixed(2)}% | ${developBranchPct.toFixed(2)}% | ${branchDiff.toFixed(2)}% | ${branchStatus} |
`;

const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});

const oldComment = comments.find(
(c) =>
c.user.login === "github-actions[bot]" &&
c.body.startsWith("## 🧪 Frontend Code Coverage Report")
);

if (oldComment) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: oldComment.id,
});
}

await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: message.trim(),
});

if (lineDiff < 0 || branchDiff < 0) {
// core.setFailed("Coverage has decreased. Please improve test coverage.");
}
};
56 changes: 56 additions & 0 deletions .github/workflows/ui-cod-cov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: UI Code Coverage

on:
pull_request:
branches:
- develop
paths:
- 'ui/src/**'
- 'tests/ui/**'
types: [opened, synchronize, reopened]

jobs:
compare-frontend-coverage:
runs-on: ubuntu-22.04
permissions:
pull-requests: write
contents: read

steps:
- name: Checkout PR
uses: actions/checkout@v4

- name: Install Node
uses: actions/setup-node@v4
with:
node-version: '20'

- name: install UI deps
uses: ./.github/actions/cached-ui-deps

- name: Generate coverage for PR branch
run: |
cd ui
npx jest --coverage --coverageReporters=json-summary
cp coverage/coverage-summary.json /tmp/pr-coverage.json

- name: Checkout develop branch
uses: actions/checkout@v4
with:
ref: develop

- name: install UI deps
uses: ./.github/actions/cached-ui-deps

- name: Generate coverage for develop branch
run: |
cd ui
npx jest --coverage --coverageReporters=json-summary
cp coverage/coverage-summary.json /tmp/develop-coverage.json

- name: Compare and comment coverage
uses: actions/github-script@v7
with:
script: |
const { default: compareDiff } = await import('.github/scripts/ui-code-coverage.mjs')
await compareDiff({ github, context })
1 change: 1 addition & 0 deletions ui/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default {
restoreMocks: true,
// Coverage
collectCoverage: true,
coverageReporters: ['json', 'text', 'lcov', 'json-summary'],
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}'],
coveragePathIgnorePatterns: [
'/node_modules/',
Expand Down
5 changes: 5 additions & 0 deletions ui/src/components/CheckboxTree/CheckboxTree.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ describe('CheckboxTree Component', () => {
expect(screen.getByLabelText('Row without group')).toBeInTheDocument();
expect(screen.getByLabelText('Row under Group 1')).toBeInTheDocument();
expect(screen.getByLabelText('First row under Group 3')).toBeInTheDocument();
expect(screen.getByLabelText('First row under Group 3')).toBeInTheDocument();
expect(screen.getByLabelText('First row under Group 3')).toBeInTheDocument();
expect(screen.getByLabelText('First row under Group 3')).toBeInTheDocument();
expect(screen.getByLabelText('First row under Group 3')).toBeInTheDocument();
expect(screen.getByLabelText('First row under Group 3')).toBeInTheDocument();
expect(screen.getByLabelText('Second row under Group 3')).toBeInTheDocument();
});

Expand Down
Loading