Skip to content

Commit

Permalink
Merge pull request #18 from jorbush/test-routes
Browse files Browse the repository at this point in the history
Test API Routes and Server Actions
  • Loading branch information
jorbush authored Aug 12, 2024
2 parents 1e82453 + c6c2b0d commit 361ebb2
Show file tree
Hide file tree
Showing 120 changed files with 7,843 additions and 5,228 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/jest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Jest Unit Testing (API Routes & Server Actions)

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
jest:
runs-on: ubuntu-latest
environment: testing
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20'

- name: Install dependencies
run: npm install

- name: Run unit tests
run: npm run jest
2 changes: 1 addition & 1 deletion .github/workflows/vitest.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Vitest Unit Test
name: Vitest Unit Testing (Components & Pages)

on:
push:
Expand Down
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 60,
"printWidth": 80,
"singleAttributePerLine": true,
"plugins": ["prettier-plugin-tailwindcss"]
}
29 changes: 8 additions & 21 deletions __tests__/unit_test/components/Avatar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
import {
render,
screen,
fireEvent,
cleanup,
} from '@testing-library/react';
import {
describe,
it,
expect,
vi,
afterEach,
} from 'vitest';
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
import { describe, it, expect, vi, afterEach } from 'vitest';
import Avatar from '@/app/components/Avatar';
import React from 'react';

Expand Down Expand Up @@ -67,12 +56,10 @@ describe('<Avatar/>', () => {
});

it('should not have cursor-pointer class when onClick is not provided', () => {
render(
<Avatar src="https://example.com/avatar.jpg" />
render(<Avatar src="https://example.com/avatar.jpg" />);
expect(screen.getByAltText('Avatar')).not.toHaveProperty(
'cursor-pointer'
);
expect(
screen.getByAltText('Avatar')
).not.toHaveProperty('cursor-pointer');
});

it('should have cursor-pointer class when onClick is provided', () => {
Expand All @@ -82,8 +69,8 @@ describe('<Avatar/>', () => {
onClick={() => {}}
/>
);
expect(
screen.getByAltText('Avatar').className
).include('cursor-pointer');
expect(screen.getByAltText('Avatar').className).include(
'cursor-pointer'
);
});
});
30 changes: 6 additions & 24 deletions __tests__/unit_test/components/Button.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
import {
render,
screen,
fireEvent,
} from '@testing-library/react';
import {
describe,
it,
expect,
vi,
beforeEach,
} from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import Button from '@/app/components/Button';
import { FaUser } from 'react-icons/fa';
import React from 'react';
Expand All @@ -30,9 +20,7 @@ describe('<Button />', () => {
onClick={mockOnClick}
/>
);
expect(
screen.getByText('Test Button')
).toBeDefined();
expect(screen.getByText('Test Button')).toBeDefined();
});

it('calls onClick when clicked', () => {
Expand All @@ -54,9 +42,7 @@ describe('<Button />', () => {
disabled
/>
);
expect(screen.getByText('Disabled')).toHaveProperty(
'disabled'
);
expect(screen.getByText('Disabled')).toHaveProperty('disabled');
});

it('applies outline styles when outline prop is true', () => {
Expand Down Expand Up @@ -93,9 +79,7 @@ describe('<Button />', () => {
icon={FaUser}
/>
);
expect(
screen.getByTestId('button-icon')
).toBeDefined();
expect(screen.getByTestId('button-icon')).toBeDefined();
});

it('applies delay when withDelay prop is true', async () => {
Expand Down Expand Up @@ -127,9 +111,7 @@ describe('<Button />', () => {
/>
);
const button = screen.getByText('Delete');
expect(button.className).toContain(
'border-rose-500'
);
expect(button.className).toContain('border-rose-500');
expect(button.className).toContain('bg-rose-500');
});
});
47 changes: 10 additions & 37 deletions __tests__/unit_test/components/CategoryBox.test.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
import React from 'react';
import {
render,
screen,
fireEvent,
cleanup,
} from '@testing-library/react';
import {
describe,
it,
expect,
vi,
beforeEach,
afterEach,
} from 'vitest';
import {
useRouter,
useSearchParams,
} from 'next/navigation';
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { useRouter, useSearchParams } from 'next/navigation';
import CategoryBox from '@/app/components/CategoryBox';
import { FaHome } from 'react-icons/fa';

Expand Down Expand Up @@ -70,14 +55,9 @@ describe('<CategoryBox />', () => {
selected
/>
);
const container =
screen.getAllByText('home')[0].parentElement;
expect(container?.className).toContain(
'border-b-neutral-800'
);
expect(container?.className).toContain(
'text-neutral-800'
);
const container = screen.getAllByText('home')[0].parentElement;
expect(container?.className).toContain('border-b-neutral-800');
expect(container?.className).toContain('text-neutral-800');
});

it('applies default styles when selected prop is false', () => {
Expand All @@ -87,14 +67,9 @@ describe('<CategoryBox />', () => {
label="Home"
/>
);
const container =
screen.getAllByText('home')[0].parentElement;
expect(container?.className).toContain(
'border-transparent'
);
expect(container?.className).toContain(
'text-neutral-500'
);
const container = screen.getAllByText('home')[0].parentElement;
expect(container?.className).toContain('border-transparent');
expect(container?.className).toContain('text-neutral-500');
});

it('calls router.push with correct URL when clicked and category is not selected', () => {
Expand All @@ -109,9 +84,7 @@ describe('<CategoryBox />', () => {
);
fireEvent.click(screen.getByText('home'));

expect(mockPush).toHaveBeenCalledWith(
'/?category=Home'
);
expect(mockPush).toHaveBeenCalledWith('/?category=Home');
});

it('calls router.push with correct URL when clicked and category is already selected', () => {
Expand Down
45 changes: 10 additions & 35 deletions __tests__/unit_test/components/ClientOnly.test.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,10 @@
import React from 'react';
import {
render,
screen,
act,
cleanup,
} from '@testing-library/react';
import {
describe,
it,
expect,
vi,
beforeEach,
afterEach,
} from 'vitest';
import { render, screen, act, cleanup } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import ClientOnly from '@/app/components/ClientOnly';

vi.mock('react-i18next', () => ({
I18nextProvider: ({
children,
}: {
children: React.ReactNode;
}) => (
I18nextProvider: ({ children }: { children: React.ReactNode }) => (
<div data-testid="i18next-provider">{children}</div>
),
initReactI18next: {
Expand Down Expand Up @@ -54,40 +38,31 @@ describe('<ClientOnly />', () => {
it('renders children immediately in testing environment', () => {
render(
<ClientOnly>
<div data-testid="child-component">
Child Component
</div>
<div data-testid="child-component">Child Component</div>
</ClientOnly>
);

const childComponents = screen.getAllByTestId(
'child-component'
);
const childComponents = screen.getAllByTestId('child-component');
expect(childComponents.length).toBe(1);
});

it('wraps children with I18nextProvider', () => {
render(
<ClientOnly>
<div data-testid="child-component">
Child Component
</div>
<div data-testid="child-component">Child Component</div>
</ClientOnly>
);

act(() => {
vi.runAllTimers();
});

const i18nextProviders = screen.getAllByTestId(
'i18next-provider'
);
const i18nextProviders = screen.getAllByTestId('i18next-provider');
expect(i18nextProviders.length).toBe(1);

const childComponent =
i18nextProviders[0].querySelector(
'[data-testid="child-component"]'
);
const childComponent = i18nextProviders[0].querySelector(
'[data-testid="child-component"]'
);
expect(childComponent).not.toBeNull();
expect(childComponent?.tagName).toBe('DIV');
});
Expand Down
7 changes: 2 additions & 5 deletions __tests__/unit_test/components/Container.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,10 @@ describe('<Container />', () => {
</Container>
);

const container =
screen.getByText('Test Content').parentElement;
const container = screen.getByText('Test Content').parentElement;
expect(container).toBeDefined();
expect(container?.className).toContain('mx-auto');
expect(container?.className).toContain(
'max-w-[2520px]'
);
expect(container?.className).toContain('max-w-[2520px]');
expect(container?.className).toContain('px-4');
expect(container?.className).toContain('sm:px-2');
expect(container?.className).toContain('md:px-10');
Expand Down
28 changes: 5 additions & 23 deletions __tests__/unit_test/components/EmptyState.test.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
import {
render,
screen,
fireEvent,
cleanup,
} from '@testing-library/react';
import {
describe,
it,
expect,
vi,
beforeEach,
afterEach,
} from 'vitest';
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import EmptyState from '@/app/components/EmptyState';
import React from 'react';

Expand All @@ -37,13 +25,9 @@ describe('<EmptyState />', () => {
it('renders with default props', () => {
render(<EmptyState />);

expect(screen.getByText('No exact matches')).toBeDefined();
expect(
screen.getByText('No exact matches')
).toBeDefined();
expect(
screen.getByText(
'Try changing or removing some of your filters.'
)
screen.getByText('Try changing or removing some of your filters.')
).toBeDefined();
expect(screen.queryByRole('button')).toBeNull();
});
Expand All @@ -60,9 +44,7 @@ describe('<EmptyState />', () => {
);

expect(screen.getByText(customTitle)).toBeDefined();
expect(
screen.getByText(customSubtitle)
).toBeDefined();
expect(screen.getByText(customSubtitle)).toBeDefined();
});

it('renders reset button when showReset is true', () => {
Expand Down
Loading

0 comments on commit 361ebb2

Please sign in to comment.