Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 9 additions & 17 deletions .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,15 @@ jobs:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Run tests with coverage
run: npm run test:coverage
- name: Install jest-junit for JUnit XML output
run: npm install --save-dev jest-junit
- name: Run tests with coverage and JUnit output
run: |
# Generate JUnit XML file for Test Analytics
JEST_JUNIT_CLASSNAME="{filepath}" npx jest --reporters=jest-junit --coverage --outputFile=junit.xml
env:
NODE_ENV: test
- name: Generate test results in JUnit format
run: |
# Install jest-junit if not already available
npm install --save-dev jest-junit
# Run tests with JUnit output for better test analytics
npx jest --coverage --testResultsProcessor=jest-junit --outputFile=test-results.xml
continue-on-error: true # Allow flaky tests to not fail the build
# Remove continue-on-error to let tests fail and trigger Test Analytics
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
Expand All @@ -41,13 +39,7 @@ jobs:
name: codecov-umbrella
fail_ci_if_error: false # Don't fail CI if coverage upload fails
- name: Upload test results to Codecov
uses: codecov/codecov-action@v5
if: always() # Run even if tests fail
if: ${{ !cancelled() }}
uses: codecov/test-results-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: ./
slug: sfanahata/fitfest
files: ./test-results.xml
flags: test-results
name: test-results
fail_ci_if_error: false
1 change: 1 addition & 0 deletions app/src/app/activities/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export default function ActivitiesPage() {
<div className="w-full max-w-2xl flex flex-col gap-6">
<div className="flex justify-between items-center mb-4">
<h1 className="text-2xl font-bold text-fitfest-text dark:text-fitfest-subtle">Your Activities</h1>
<span className="text-sm text-fitfest-subtle dark:text-fitfest-subtle/70 ml-2">({activities.length} total)</span>
<Link href="/activities/new" passHref legacyBehavior>
<Button className="bg-fitfest-deep text-white hover:bg-fitfest-bright dark:bg-fitfest-bright dark:hover:bg-fitfest-deep">
Log Activity
Expand Down
59 changes: 59 additions & 0 deletions app/src/tests/DefinitelyFailingTest.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import Button from '@/components/Button';

describe('Definitely Failing Tests for Test Analytics Demo', () => {
it('should fail due to incorrect math', () => {
// This test will always fail to demonstrate failure detection
expect(1 + 1).toBe(3);
});

it('should fail due to wrong string comparison', () => {
const message = 'Hello, World!';
expect(message).toBe('Goodbye, World!');
});

it('should fail due to missing DOM element', () => {
render(<Button>Click Me</Button>);
// This will fail because the text doesn't exist
expect(screen.getByText('Click Me Not')).toBeInTheDocument();
});

it('should fail due to array comparison', () => {
const array = [1, 2, 3];
expect(array).toEqual([1, 2, 3, 4]);
});

it('should fail due to object property check', () => {
const obj = { name: 'John', age: 30 };
expect(obj).toHaveProperty('email');
});

it('should fail due to async operation timeout', async () => {
// This will timeout and fail
await new Promise(resolve => setTimeout(resolve, 2000));
expect(true).toBe(true);
}, 100); // 100ms timeout

it('should fail due to exception handling', () => {
const obj: any = null;
// This will throw an exception
expect(obj.nonExistentProperty.value).toBeDefined();
});

it('should fail due to regex mismatch', () => {
const email = 'invalid-email';
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
expect(emailRegex.test(email)).toBe(true);
});

it('should fail due to type assertion', () => {
const value: number = 42;
expect(value).toBe('42');
});

it('should fail due to promise rejection', async () => {
const promise = Promise.reject(new Error('Intentional failure'));
await expect(promise).resolves.toBe('success');
});
});
32 changes: 21 additions & 11 deletions app/src/tests/FlakyTestExample.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import Button from '@/components/Button';
describe('Flaky Test Examples for Codecov Test Analytics', () => {
it('should sometimes fail due to timing issues', () => {
const random = Math.random();
// This test will pass consistently but demonstrates timing variability
expect(random).toBeGreaterThan(0);
// This test will fail approximately 20% of the time for flaky detection
expect(random).toBeGreaterThan(0.8);
});

it('should fail when environment variables are missing', () => {
Expand Down Expand Up @@ -48,19 +48,29 @@ describe('Flaky Test Examples for Codecov Test Analytics', () => {
document.documentElement.classList.remove('dark');
});

it('should handle network requests successfully', async () => {
// Mock fetch to always succeed for stable merge
it('should be flaky due to network issues', async () => {
// Mock fetch to sometimes fail for flaky behavior
const mockFetch = jest.fn();
global.fetch = mockFetch;

mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ data: 'success' }),
});
// Simulate network failure 15% of the time
if (Math.random() < 0.15) {
mockFetch.mockRejectedValue(new Error('Network timeout'));
} else {
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ data: 'success' }),
});
}

const response = await fetch('/api/test');
const data = await response.json();
expect(data.data).toBe('success');
try {
const response = await fetch('/api/test');
const data = await response.json();
expect(data.data).toBe('success');
} catch (error) {
// This will fail when network error occurs
expect(error).toBeUndefined();
}
});

it('should validate form validation logic', () => {
Expand Down
100 changes: 100 additions & 0 deletions app/src/tests/TestAnalyticsDemo.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import Button from '@/components/Button';

describe('Test Analytics Demo - Intentionally Problematic Tests', () => {
it('should fail consistently to demonstrate test failure detection', () => {
// This test will always fail to show how Codecov identifies failures
expect(2 + 2).toBe(5);
});

it('should fail due to missing element', () => {
render(<Button>Test Button</Button>);
// This will fail because the text doesn't exist
expect(screen.getByText('Non-existent button text')).toBeInTheDocument();
});

it('should fail due to incorrect assertion', () => {
const result = Math.random();
// This will fail because the assertion is wrong
expect(result).toBeGreaterThan(1.0);
});

it('should be flaky due to timing issues', async () => {
// This test will fail approximately 30% of the time due to timing
const startTime = Date.now();
await new Promise(resolve => setTimeout(resolve, Math.random() * 50));
const endTime = Date.now();

// This assertion might fail if timing is too fast
expect(endTime - startTime).toBeGreaterThan(100);
});

it('should be flaky due to network simulation', async () => {
// Mock fetch to fail 25% of the time
const mockFetch = jest.fn();
global.fetch = mockFetch;

if (Math.random() < 0.25) {
mockFetch.mockRejectedValue(new Error('Simulated network failure'));
} else {
mockFetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ data: 'success' }),
});
}

try {
const response = await fetch('/api/test');
const data = await response.json();
expect(data.data).toBe('success');
} catch (error) {
// This will fail when network error occurs
expect(error).toBeUndefined();
}
});

it('should be flaky due to environment dependencies', () => {
// This test will fail if certain conditions aren't met
const currentHour = new Date().getHours();
// Will fail approximately 50% of the time depending on when tests run
expect(currentHour).toBeLessThan(12);
});

it('should fail due to async timeout', async () => {
// This test will fail due to timeout
const promise = new Promise((resolve) => {
setTimeout(resolve, 10000); // 10 second delay
});

await expect(promise).resolves.toBeDefined();
}, 1000); // 1 second timeout

it('should fail due to exception', () => {
// This test will fail due to an exception
const obj: any = null;
expect(obj.someProperty).toBeDefined();
});

it('should be flaky due to race conditions', async () => {
// Multiple async operations that might race
const promises = Array.from({ length: 5 }, (_, i) =>
new Promise(resolve => setTimeout(() => resolve(i), Math.random() * 100))
);

const results = await Promise.all(promises);

// This might fail due to race conditions
expect(results).toEqual([0, 1, 2, 3, 4]);
});

it('should fail due to strict validation', () => {
// Very strict validation that might fail
const email = 'test@example.com';
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
expect(regex.test(email)).toBe(true);

// This assertion is too strict and will fail
expect(email).toHaveLength(16);
});
});
Loading