diff --git a/src/components/faq/__tests__/FaqItem.test.jsx b/src/components/faq/__tests__/FaqItem.test.jsx
new file mode 100644
index 00000000..5d82c80b
--- /dev/null
+++ b/src/components/faq/__tests__/FaqItem.test.jsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import FaqItem from '../FaqItem';
+
+describe('FaqItem', () => {
+ const faq = {
+ title: 'What is Syscoin?',
+ description: '
Syscoin is a blockchain protocol.
'
+ };
+
+ test('renders title and index, content collapsed by default (height 0)', () => {
+ const { container } = render();
+
+ expect(screen.getByText('1')).toBeInTheDocument();
+ expect(screen.getByText('What is Syscoin?')).toBeInTheDocument();
+ const collapse = container.querySelector('.ReactCollapse--collapse');
+ expect(collapse).toBeTruthy();
+ expect(collapse.style.height).toBe('0px');
+ });
+
+ test('toggles content height when clicking header', () => {
+ const { container } = render();
+
+ const header = screen.getByText('What is Syscoin?');
+ const collapse = container.querySelector('.ReactCollapse--collapse');
+ expect(collapse.style.height).toBe('0px');
+
+ userEvent.click(header);
+ // Opened: height should no longer be 0px (react-collapse sets pixel height during animation)
+ expect(collapse.style.height).not.toBe('0px');
+
+ userEvent.click(header);
+ // Closed again
+ expect(collapse.style.height).toBe('0px');
+ });
+});
+
+
diff --git a/src/components/faq/__tests__/FaqList.test.jsx b/src/components/faq/__tests__/FaqList.test.jsx
new file mode 100644
index 00000000..d7a20901
--- /dev/null
+++ b/src/components/faq/__tests__/FaqList.test.jsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import { render, screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import FaqList from '../FaqList';
+
+// Mock i18n hook
+jest.mock('react-i18next', () => ({
+ useTranslation: () => ({ t: (k) => k })
+}));
+
+// Mock request util
+jest.mock('../../../utils/request', () => ({
+ getPublicFaqs: jest.fn()
+}));
+
+describe('FaqList', () => {
+ const { getPublicFaqs } = require('../../../utils/request');
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test('renders loading then empty state', async () => {
+ getPublicFaqs.mockResolvedValue({ data: { faqs: [] } });
+
+ render();
+
+ expect(screen.getByText('admin.faqs.loading')).toBeInTheDocument();
+
+ expect(await screen.findByText('There are no questions.')).toBeInTheDocument();
+ });
+
+ test('renders list and allows toggling an item (via height)', async () => {
+ getPublicFaqs.mockResolvedValue({ data: { faqs: [
+ { title: 'Question A', description: 'Answer A
' },
+ { title: 'Question B', description: 'Answer B
' }
+ ] } });
+
+ const { container } = render();
+
+ // Wait for one of the items
+ await screen.findByText('Question A');
+
+ // Initially collapsed (height 0)
+ const collapse = container.querySelector('.ReactCollapse--collapse');
+ expect(collapse.style.height).toBe('0px');
+
+ // Toggle via clicking the title
+ userEvent.click(screen.getByText('Question A'));
+ expect(collapse.style.height).not.toBe('0px');
+ });
+
+ test('renders error state on request failure', async () => {
+ getPublicFaqs.mockRejectedValue(new Error('network'));
+
+ render();
+
+ expect(await screen.findByText("The data couldn't be fetched.")).toBeInTheDocument();
+ });
+});
+
+