Skip to content

Commit e77e861

Browse files
committed
Add 3 documentation pages: coverage top, JavaScript testing, and Flutter testing
1 parent f4a3d4c commit e77e861

16 files changed

+591
-1136
lines changed

app/docs/coverage/CodeBlock.tsx

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"use client";
2+
import { useEffect, useState } from "react";
3+
4+
interface CodeBlockProps {
5+
code: string;
6+
language: string;
7+
filename?: string;
8+
}
9+
10+
export function CodeBlock({ code, language, filename }: CodeBlockProps) {
11+
const [copied, setCopied] = useState(false);
12+
const [highlighted, setHighlighted] = useState(code);
13+
const [mounted, setMounted] = useState(false);
14+
15+
useEffect(() => {
16+
setMounted(true);
17+
const initPrism = async () => {
18+
const Prism = (await import("prismjs")).default;
19+
await import("prismjs/components/prism-javascript");
20+
await import("prismjs/components/prism-json");
21+
await import("prismjs/components/prism-typescript");
22+
await import("prismjs/components/prism-yaml");
23+
await import("prismjs/themes/prism-tomorrow.css");
24+
25+
const highlightedCode = Prism.highlight(code, Prism.languages[language], language);
26+
setHighlighted(highlightedCode);
27+
};
28+
29+
initPrism();
30+
}, [code, language]);
31+
32+
if (!mounted) {
33+
return (
34+
<div className="relative font-mono text-[15px] leading-relaxed">
35+
{filename && (
36+
<div className="bg-[#1e1e1e] text-gray-400 px-4 py-2 rounded-t-lg border-b border-gray-700">
37+
{filename}
38+
</div>
39+
)}
40+
<div className="bg-[#1e1e1e] rounded-b-lg overflow-hidden">
41+
<pre className="p-4 m-0 overflow-x-auto text-zinc-200">
42+
<code>{code}</code>
43+
</pre>
44+
</div>
45+
</div>
46+
);
47+
}
48+
49+
return (
50+
<div className="relative font-mono text-[15px] leading-relaxed">
51+
{filename && (
52+
<div className="bg-[#1e1e1e] text-gray-400 px-4 py-2 rounded-t-lg border-b border-gray-700">
53+
{filename}
54+
</div>
55+
)}
56+
<div className="bg-[#1e1e1e] rounded-b-lg overflow-hidden">
57+
<div className="relative group">
58+
<button
59+
onClick={async () => {
60+
await navigator.clipboard.writeText(code);
61+
setCopied(true);
62+
setTimeout(() => setCopied(false), 2000);
63+
}}
64+
className="absolute right-2 top-2 bg-gray-700 hover:bg-gray-600 text-gray-200 px-3 py-1 rounded text-sm opacity-0 group-hover:opacity-100 transition-opacity"
65+
>
66+
{copied ? "Copied!" : "Copy"}
67+
</button>
68+
<pre className="p-4 m-0 overflow-x-auto">
69+
<code className="text-zinc-200" dangerouslySetInnerHTML={{ __html: highlighted }} />
70+
</pre>
71+
</div>
72+
</div>
73+
</div>
74+
);
75+
}
+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"use client";
2+
3+
import { CodeBlock } from "./CodeBlock";
4+
5+
interface CommonSectionsProps {
6+
framework: string;
7+
workflowCode: string;
8+
workflowFilename: string;
9+
configPoints: string[];
10+
setupCode?: {
11+
filename: string;
12+
language: string;
13+
code: string;
14+
}[];
15+
}
16+
17+
export function CommonSections({
18+
framework,
19+
workflowCode,
20+
workflowFilename,
21+
configPoints,
22+
setupCode,
23+
}: CommonSectionsProps) {
24+
return (
25+
<div className="space-y-12">
26+
{setupCode && (
27+
<section>
28+
<h2 className="text-2xl font-semibold mb-4 text-left">Framework Configuration</h2>
29+
<p className="text-gray-600 mb-4">
30+
Configure {framework} to generate LCOV coverage reports:
31+
</p>
32+
{setupCode.map((code, index) => (
33+
<CodeBlock
34+
key={index}
35+
code={code.code}
36+
language={code.language}
37+
filename={code.filename}
38+
/>
39+
))}
40+
</section>
41+
)}
42+
43+
<section>
44+
<h2 className="text-2xl font-semibold mb-4 text-left">Setting Up GitHub Actions</h2>
45+
<p className="text-gray-600 mb-4">
46+
Create a workflow file in{" "}
47+
<code className="bg-gray-100 px-2 py-1 rounded">.github/workflows/</code> directory. The
48+
filename can be anything you prefer (e.g.{" "}
49+
<code className="bg-gray-100 px-2 py-1 rounded">{workflowFilename}</code>). Add the
50+
following content to your workflow file:
51+
</p>
52+
<CodeBlock code={workflowCode} language="yaml" filename={workflowFilename} />
53+
<div className="bg-yellow-50 p-4 rounded-lg mb-6 mt-4">
54+
<h3 className="text-lg font-medium text-yellow-950 mb-2">Key Configuration Points</h3>
55+
<ul className="list-disc list-outside space-y-1 text-yellow-800 ml-5">
56+
{configPoints.map((point, index) => (
57+
<li key={index} dangerouslySetInnerHTML={{ __html: point }} />
58+
))}
59+
</ul>
60+
</div>
61+
</section>
62+
63+
<section>
64+
<h2 className="text-2xl font-semibold mb-4 text-left">Viewing Coverage Reports</h2>
65+
<p className="text-gray-600 mb-4">
66+
After your workflow runs successfully, GitAuto automatically processes the coverage
67+
reports and displays them in the Coverage Dashboard. The data updates whenever:
68+
</p>
69+
<ul className="list-disc list-outside space-y-2 text-gray-600 mb-6 ml-5">
70+
<li>You push to any branch (except master)</li>
71+
<li>You push additional commits to a pull request</li>
72+
<li>You manually trigger the workflow</li>
73+
</ul>
74+
</section>
75+
76+
<div className="bg-gray-50 p-4 rounded-lg mt-4">
77+
<p className="text-gray-700">
78+
<strong>About LCOV:</strong> LCOV (Linux Code Coverage) is a standard format for code
79+
coverage data. It's pronounced "el-cov" and is widely supported by various tools and
80+
services.
81+
</p>
82+
</div>
83+
</div>
84+
);
85+
}

app/docs/coverage/KeyRequirements.tsx

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"use client";
2+
3+
interface KeyRequirementsProps {
4+
className?: string;
5+
}
6+
7+
export function KeyRequirements({ className = "" }: KeyRequirementsProps) {
8+
return (
9+
<div className={`bg-yellow-50 p-4 rounded-lg mb-6 ${className}`}>
10+
<h3 className="text-lg font-medium text-yellow-950 mb-2">Key Requirements</h3>
11+
<ul className="list-disc list-outside space-y-1 text-yellow-800 ml-5">
12+
<li>Coverage report must be in LCOV format</li>
13+
<li>
14+
Report must be saved as <code className="bg-yellow-100 px-1">coverage/lcov.info</code>
15+
</li>
16+
<li>
17+
Report must be uploaded as a GitHub Actions artifact named{" "}
18+
<code className="bg-yellow-100 px-1">coverage-report</code>
19+
</li>
20+
</ul>
21+
</div>
22+
);
23+
}
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const pubspecYaml = `dev_dependencies:
2+
flutter_test:
3+
sdk: flutter`;
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
export const workflow = `name: Flutter Coverage
2+
3+
on:
4+
push:
5+
workflow_dispatch:
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
13+
- name: Setup Flutter
14+
uses: subosito/flutter-action@v2
15+
with:
16+
channel: "stable"
17+
18+
- name: Install dependencies
19+
run: flutter pub get
20+
21+
- name: Run tests with coverage
22+
run: flutter test --coverage
23+
24+
- name: Upload coverage report
25+
if: always()
26+
uses: actions/upload-artifact@v4
27+
with:
28+
name: coverage-report
29+
path: coverage/lcov.info`;

app/docs/coverage/flutter/page.tsx

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { CodeBlock } from "../CodeBlock";
2+
import { CommonSections } from "../CommonConfiguration";
3+
import { KeyRequirements } from "../KeyRequirements";
4+
import { pubspecYaml } from "./code/config";
5+
import { workflow } from "./code/workflow";
6+
7+
export default function FlutterConfigurationPage() {
8+
return (
9+
<>
10+
<h1 className="text-4xl font-bold mb-8">Flutter Testing</h1>
11+
12+
<div className="space-y-12">
13+
<section>
14+
<h2 className="text-2xl font-semibold mb-4 text-left">Framework Configuration</h2>
15+
<KeyRequirements />
16+
<p className="text-gray-600 mb-4">
17+
Flutter's built-in test framework can generate LCOV coverage reports.
18+
</p>
19+
20+
<CodeBlock code={pubspecYaml} language="yaml" filename="pubspec.yaml" />
21+
</section>
22+
23+
<CommonSections
24+
framework="Flutter"
25+
workflowCode={workflow}
26+
workflowFilename="flutter-coverage.yml"
27+
configPoints={[
28+
"Run tests with <code>--coverage</code> flag",
29+
"Upload the report as an artifact named <code>coverage-report</code>",
30+
"Ensure the report is saved as <code>coverage/lcov.info</code>",
31+
]}
32+
/>
33+
</div>
34+
</>
35+
);
36+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const packageJson = `{
2+
"scripts": {
3+
"test": "jest"
4+
}
5+
}`;
6+
7+
export const jestConfig = `/** @type {import('jest').Config} */
8+
module.exports = {
9+
collectCoverage: true,
10+
coverageReporters: ["lcov"],
11+
collectCoverageFrom: [
12+
"**/*.{js,jsx,ts,tsx}",
13+
"!**/*.d.ts",
14+
"!**/node_modules/**"
15+
]
16+
}`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export const packageJson = `{
2+
"scripts": {
3+
"test": "vitest run --coverage"
4+
}
5+
}`;
6+
7+
export const vitestConfig = `/// <reference types="vitest" />
8+
import { defineConfig } from 'vite'
9+
10+
// https://vitest.dev/guide/coverage.html#coverage-setup
11+
export default defineConfig({
12+
test: {
13+
coverage: {
14+
provider: 'v8',
15+
reporter: ['lcov'],
16+
},
17+
},
18+
})`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
export const workflow = `name: Test Coverage
2+
3+
on:
4+
push:
5+
workflow_dispatch:
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
13+
- name: Setup Node.js
14+
uses: actions/setup-node@v4
15+
with:
16+
node-version: "22"
17+
18+
- name: Install dependencies
19+
run: npm ci
20+
21+
- name: Run tests with coverage
22+
run: npm test
23+
24+
- name: Upload coverage report
25+
if: always()
26+
uses: actions/upload-artifact@v4
27+
with:
28+
name: coverage-report
29+
path: coverage/lcov.info`;

app/docs/coverage/javascript/page.tsx

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { CodeBlock } from "../CodeBlock";
2+
import { CommonSections } from "../CommonConfiguration";
3+
import { KeyRequirements } from "../KeyRequirements";
4+
import { packageJson as jestPackageJson, jestConfig } from "./code/jest";
5+
import { packageJson as vitestPackageJson, vitestConfig } from "./code/vitest";
6+
import { workflow } from "./code/workflow";
7+
8+
export default function JavaScriptConfigurationPage() {
9+
return (
10+
<>
11+
<h1 className="text-4xl font-bold mb-8">JavaScript/TypeScript Testing</h1>
12+
13+
<div className="space-y-12">
14+
<section>
15+
<h2 className="text-2xl font-semibold mb-4 text-left">Framework Configuration</h2>
16+
<p className="text-gray-600 mb-4">
17+
Any JavaScript/TypeScript test framework that can generate LCOV reports is supported.
18+
While we provide examples for Jest and Vitest below, you can use any framework of your
19+
choice (Mocha, AVA, Jasmine, etc.) as long as it generates coverage reports in LCOV
20+
format.
21+
</p>
22+
23+
<KeyRequirements />
24+
25+
<h3 className="text-xl font-semibold mt-6 mb-3">Jest</h3>
26+
<div className="space-y-4">
27+
<CodeBlock code={jestPackageJson} language="json" filename="package.json" />
28+
<CodeBlock code={jestConfig} language="javascript" filename="jest.config.js" />
29+
</div>
30+
31+
<h3 className="text-xl font-semibold mt-8 mb-3">Vitest</h3>
32+
<div className="space-y-4">
33+
<CodeBlock code={vitestPackageJson} language="json" filename="package.json" />
34+
<CodeBlock code={vitestConfig} language="typescript" filename="vitest.config.ts" />
35+
</div>
36+
</section>
37+
38+
<CommonSections
39+
framework="JavaScript/TypeScript"
40+
workflowCode={workflow}
41+
workflowFilename="coverage.yml"
42+
configPoints={[
43+
"Configure your test framework to generate LCOV reports",
44+
"Upload the report as an artifact named <code>coverage-report</code>",
45+
"Ensure the report is saved as <code>coverage/lcov.info</code>",
46+
]}
47+
/>
48+
</div>
49+
</>
50+
);
51+
}

0 commit comments

Comments
 (0)