diff --git a/src/renderer/__helpers__/jest.setup.ts b/src/renderer/__helpers__/jest.setup.ts
index c98149063..76f263eda 100644
--- a/src/renderer/__helpers__/jest.setup.ts
+++ b/src/renderer/__helpers__/jest.setup.ts
@@ -78,3 +78,41 @@ Object.defineProperty(navigator, 'clipboard', {
},
configurable: true,
});
+
+// Simple IntersectionObserver mock for test environments (jsdom)
+class MockIntersectionObserver {
+ readonly root: Element | Document | null;
+ readonly rootMargin: string;
+ readonly thresholds: number | number[];
+
+ constructor(
+ // callback unused in this mock
+ _callback: IntersectionObserverCallback,
+ options?: IntersectionObserverInit,
+ ) {
+ this.root = (options?.root as Element | Document) ?? null;
+ this.rootMargin = options?.rootMargin ?? '';
+ this.thresholds = options?.threshold ?? 0;
+ }
+
+ observe() {
+ return null;
+ }
+
+ unobserve() {
+ return null;
+ }
+
+ disconnect() {
+ return null;
+ }
+
+ takeRecords(): IntersectionObserverEntry[] {
+ return [];
+ }
+}
+
+// Attach to global if not present
+if (typeof (globalThis as any).IntersectionObserver === 'undefined') {
+ (globalThis as any).IntersectionObserver = MockIntersectionObserver;
+}
diff --git a/src/renderer/components/metrics/CommentsPill.test.tsx b/src/renderer/components/metrics/CommentsPill.test.tsx
index 58d0eaa6d..2b4180c88 100644
--- a/src/renderer/components/metrics/CommentsPill.test.tsx
+++ b/src/renderer/components/metrics/CommentsPill.test.tsx
@@ -1,38 +1,32 @@
import { renderWithAppContext } from '../../__helpers__/test-utils';
-import { mockGitifyNotification } from '../../__mocks__/notifications-mocks';
-import { CommentsPill } from './CommentsPill';
+import { CommentsPill, type CommentsPillProps } from './CommentsPill';
describe('renderer/components/metrics/CommentsPill.tsx', () => {
it('renders with no comments (null)', () => {
- const mockNotification = { ...mockGitifyNotification };
- mockNotification.subject.commentCount = null;
+ const props: CommentsPillProps = null;
- const tree = renderWithAppContext(
- ,
- );
+ const tree = renderWithAppContext();
expect(tree).toMatchSnapshot();
});
it('renders with 1 comment', () => {
- const mockNotification = { ...mockGitifyNotification };
- mockNotification.subject.commentCount = 1;
+ const props: CommentsPillProps = {
+ commentCount: 1,
+ };
- const tree = renderWithAppContext(
- ,
- );
+ const tree = renderWithAppContext();
expect(tree).toMatchSnapshot();
});
it('renders with multiple comments', () => {
- const mockNotification = { ...mockGitifyNotification };
- mockNotification.subject.commentCount = 2;
+ const props: CommentsPillProps = {
+ commentCount: 2,
+ };
- const tree = renderWithAppContext(
- ,
- );
+ const tree = renderWithAppContext();
expect(tree).toMatchSnapshot();
});
diff --git a/src/renderer/components/metrics/CommentsPill.tsx b/src/renderer/components/metrics/CommentsPill.tsx
index 310883965..9352cfb7e 100644
--- a/src/renderer/components/metrics/CommentsPill.tsx
+++ b/src/renderer/components/metrics/CommentsPill.tsx
@@ -21,9 +21,9 @@ export const CommentsPill: FC = ({ commentCount }) => {
return (
);
};
diff --git a/src/renderer/components/metrics/LabelsPill.test.tsx b/src/renderer/components/metrics/LabelsPill.test.tsx
index 9e0b0207f..02c39ca9b 100644
--- a/src/renderer/components/metrics/LabelsPill.test.tsx
+++ b/src/renderer/components/metrics/LabelsPill.test.tsx
@@ -1,16 +1,25 @@
import { renderWithAppContext } from '../../__helpers__/test-utils';
-import { mockGitifyNotification } from '../../__mocks__/notifications-mocks';
-import { LabelsPill } from './LabelsPill';
+import { LabelsPill, type LabelsPillProps } from './LabelsPill';
describe('renderer/components/metrics/LabelsPill.tsx', () => {
- it('renders labels pill', () => {
- const mockNotification = { ...mockGitifyNotification };
- mockNotification.subject.labels = ['enhancement', 'good-first-issue'];
+ it('renders without labels', () => {
+ const props: LabelsPillProps = { labels: [] };
- const tree = renderWithAppContext(
- ,
- );
+ const tree = renderWithAppContext();
+
+ expect(tree).toMatchSnapshot();
+ });
+
+ it('renders with labels', () => {
+ const props: LabelsPillProps = {
+ labels: [
+ { name: 'enhancement', color: 'a2eeef' },
+ { name: 'good-first-issue', color: '7057ff' },
+ ],
+ };
+
+ const tree = renderWithAppContext();
expect(tree).toMatchSnapshot();
});
diff --git a/src/renderer/components/metrics/LabelsPill.tsx b/src/renderer/components/metrics/LabelsPill.tsx
index 42443a1b2..5276c5a1a 100644
--- a/src/renderer/components/metrics/LabelsPill.tsx
+++ b/src/renderer/components/metrics/LabelsPill.tsx
@@ -1,14 +1,14 @@
import type { FC } from 'react';
import { TagIcon } from '@primer/octicons-react';
+import { IssueLabelToken, LabelGroup } from '@primer/react';
-import { IconColor } from '../../types';
+import { type GitifyLabels, IconColor } from '../../types';
-import { formatMetricDescription } from '../../utils/notifications/formatters';
import { MetricPill } from './MetricPill';
export interface LabelsPillProps {
- labels: string[];
+ labels: GitifyLabels[];
}
export const LabelsPill: FC = ({ labels }) => {
@@ -16,22 +16,27 @@ export const LabelsPill: FC = ({ labels }) => {
return null;
}
- const description = formatMetricDescription(
- labels.length,
- 'label',
- (count, noun) => {
- const formatted = labels.map((label) => `🏷️ ${label}`).join(', ');
-
- return `${count} ${noun}: ${formatted}`;
- },
+ const labelsContent = (
+
+ {labels.map((label) => {
+ return (
+
+ );
+ })}
+
);
return (
);
};
diff --git a/src/renderer/components/metrics/LinkedIssuesPill.test.tsx b/src/renderer/components/metrics/LinkedIssuesPill.test.tsx
index 8b2d90d2f..3f50254ad 100644
--- a/src/renderer/components/metrics/LinkedIssuesPill.test.tsx
+++ b/src/renderer/components/metrics/LinkedIssuesPill.test.tsx
@@ -1,27 +1,31 @@
import { renderWithAppContext } from '../../__helpers__/test-utils';
-import { mockGitifyNotification } from '../../__mocks__/notifications-mocks';
-import { LinkedIssuesPill } from './LinkedIssuesPill';
+import {
+ LinkedIssuesPill,
+ type LinkedIssuesPillProps,
+} from './LinkedIssuesPill';
describe('renderer/components/metrics/LinkedIssuesPill.tsx', () => {
+ it('renders when no linked issues/prs', () => {
+ const props: LinkedIssuesPillProps = { linkedIssues: [] };
+
+ const tree = renderWithAppContext();
+
+ expect(tree).toMatchSnapshot();
+ });
+
it('renders when linked to one issue/pr', () => {
- const mockNotification = { ...mockGitifyNotification };
- mockNotification.subject.linkedIssues = ['#1'];
+ const props: LinkedIssuesPillProps = { linkedIssues: ['#1'] };
- const tree = renderWithAppContext(
- ,
- );
+ const tree = renderWithAppContext();
expect(tree).toMatchSnapshot();
});
it('renders when linked to multiple issues/prs', () => {
- const mockNotification = { ...mockGitifyNotification };
- mockNotification.subject.linkedIssues = ['#1', '#2'];
+ const props: LinkedIssuesPillProps = { linkedIssues: ['#1', '#2'] };
- const tree = renderWithAppContext(
- ,
- );
+ const tree = renderWithAppContext();
expect(tree).toMatchSnapshot();
});
diff --git a/src/renderer/components/metrics/LinkedIssuesPill.tsx b/src/renderer/components/metrics/LinkedIssuesPill.tsx
index f5c82bc04..22ba7b60a 100644
--- a/src/renderer/components/metrics/LinkedIssuesPill.tsx
+++ b/src/renderer/components/metrics/LinkedIssuesPill.tsx
@@ -21,15 +21,15 @@ export const LinkedIssuesPill: FC = ({
const description = formatMetricDescription(
linkedIssues.length,
'issue',
- (count, noun) => `Linked to ${count} ${noun}: ${linkedIssues.join(', ')}`,
+ (noun) => `Linked to ${noun}: ${linkedIssues.join(', ')}`,
);
return (
);
};
diff --git a/src/renderer/components/metrics/MetricGroup.test.tsx b/src/renderer/components/metrics/MetricGroup.test.tsx
index e94a216cc..4450d8a1f 100644
--- a/src/renderer/components/metrics/MetricGroup.test.tsx
+++ b/src/renderer/components/metrics/MetricGroup.test.tsx
@@ -5,18 +5,29 @@ import { mockSettings } from '../../__mocks__/state-mocks';
import { MetricGroup, type MetricGroupProps } from './MetricGroup';
describe('renderer/components/metrics/MetricGroup.tsx', () => {
- describe('showPills disabled', () => {
- it('should not render any pills when showPills is disabled', async () => {
- const mockNotification = mockGitifyNotification;
- const props: MetricGroupProps = {
- notification: mockNotification,
- };
+ it('should not render any pills when showPills is disabled', async () => {
+ const mockNotification = mockGitifyNotification;
+ const props: MetricGroupProps = {
+ notification: mockNotification,
+ };
- const tree = renderWithAppContext(, {
- settings: { ...mockSettings, showPills: false },
- });
+ const tree = renderWithAppContext(, {
+ settings: { ...mockSettings, showPills: false },
+ });
+
+ expect(tree).toMatchSnapshot();
+ });
- expect(tree).toMatchSnapshot();
+ it('should render pills when showPills is enabled', async () => {
+ const mockNotification = mockGitifyNotification;
+ const props: MetricGroupProps = {
+ notification: mockNotification,
+ };
+
+ const tree = renderWithAppContext(, {
+ settings: { ...mockSettings, showPills: true },
});
+
+ expect(tree).toMatchSnapshot();
});
});
diff --git a/src/renderer/components/metrics/MetricGroup.tsx b/src/renderer/components/metrics/MetricGroup.tsx
index 7661be473..1dde4cdca 100644
--- a/src/renderer/components/metrics/MetricGroup.tsx
+++ b/src/renderer/components/metrics/MetricGroup.tsx
@@ -37,9 +37,9 @@ export const MetricGroup: FC = ({ notification }) => {
-
-
+
+
);
};
diff --git a/src/renderer/components/metrics/MetricPill.test.tsx b/src/renderer/components/metrics/MetricPill.test.tsx
index e4abfcf7b..6ca357a46 100644
--- a/src/renderer/components/metrics/MetricPill.test.tsx
+++ b/src/renderer/components/metrics/MetricPill.test.tsx
@@ -9,7 +9,7 @@ import { MetricPill, type MetricPillProps } from './MetricPill';
describe('renderer/components/metrics/MetricPill.tsx', () => {
it('should render with metric', () => {
const props: MetricPillProps = {
- title: 'Mock Pill',
+ contents: 'Mock Pill',
metric: 1,
icon: MarkGithubIcon,
color: IconColor.GREEN,
@@ -22,7 +22,7 @@ describe('renderer/components/metrics/MetricPill.tsx', () => {
it('should render without metric', () => {
const props: MetricPillProps = {
- title: 'Mock Pill',
+ contents: 'Mock Pill',
icon: MarkGithubIcon,
color: IconColor.GREEN,
};
diff --git a/src/renderer/components/metrics/MetricPill.tsx b/src/renderer/components/metrics/MetricPill.tsx
index 9371fe6aa..ba758a2de 100644
--- a/src/renderer/components/metrics/MetricPill.tsx
+++ b/src/renderer/components/metrics/MetricPill.tsx
@@ -1,4 +1,4 @@
-import type { FC } from 'react';
+import type { FC, ReactNode } from 'react';
import type { Icon } from '@primer/octicons-react';
import { Label, Stack, Text, Tooltip } from '@primer/react';
@@ -6,7 +6,7 @@ import { Label, Stack, Text, Tooltip } from '@primer/react';
import { type IconColor, Size } from '../../types';
export interface MetricPillProps {
- title: string;
+ contents: string | ReactNode;
metric?: number;
icon: Icon;
color: IconColor;
@@ -16,7 +16,8 @@ export const MetricPill: FC = (props: MetricPillProps) => {
const Icon = props.icon;
return (
-
+ // @ts-expect-error: We overload text with a ReactNode
+