Skip to content

Commit

Permalink
Use spies to replace the activeDataProvider for testing
Browse files Browse the repository at this point in the history
  • Loading branch information
abel-castro committed Aug 19, 2024
1 parent 31da494 commit 2768e45
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 41 deletions.
14 changes: 4 additions & 10 deletions app/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';

import { activeDataProvider } from '../../data-providers/active';
import { IDataProvider } from '../../data-providers/interface';
import activeDataProvider from '../../data-providers/active';
import PostSingle from '../components/posts/post-single';

export interface SinglePostPageProps {
dataProvider?: IDataProvider;
params: { slug: string };
}

export async function generateMetadata({
dataProvider = activeDataProvider,
params,
}: SinglePostPageProps): Promise<Metadata | null> {
const slug = params.slug;
const post = await dataProvider.getBySlug(slug);
const post = await activeDataProvider.getBySlug(slug);

if (!post) {
return null;
Expand All @@ -27,12 +24,9 @@ export async function generateMetadata({
};
}

export default async function SinglePostPage({
dataProvider = activeDataProvider,
params,
}: SinglePostPageProps) {
export default async function SinglePostPage({ params }: SinglePostPageProps) {
const slug = params.slug;
const post = await dataProvider.getBySlug(slug);
const post = await activeDataProvider.getBySlug(slug);

if (!post) {
notFound();
Expand Down
14 changes: 5 additions & 9 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Suspense } from 'react';

import { activeDataProvider } from '../data-providers/active';
import { IDataProvider, PostSearchOptions } from '../data-providers/interface';
import activeDataProvider from '../data-providers/active';
import { PostSearchOptions } from '../data-providers/interface';
import BlogFooter from './components/blog-footer';
import BlogHeader from './components/blog-header';
import PostList from './components/posts/post-list';
Expand All @@ -14,21 +14,17 @@ export type HomeSearchParams = {
};

interface HomeProps {
dataProvider?: IDataProvider;
searchParams?: HomeSearchParams;
searchParams: HomeSearchParams;
}

export default async function Home({
dataProvider = activeDataProvider,
searchParams,
}: HomeProps) {
export default async function Home({ searchParams }: HomeProps) {
const query = searchParams?.query || '';
const currentPage = Number(searchParams?.page) || 1;
const options: PostSearchOptions = {
currentPage: currentPage,
query: query,
};
const { posts, totalPages } = await dataProvider.getAll(options);
const { posts, totalPages } = await activeDataProvider.getAll(options);

return (
<>
Expand Down
2 changes: 1 addition & 1 deletion app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IDataProvider } from '@/data-providers/interface';
import { MetadataRoute } from 'next';

import { activeDataProvider } from '../data-providers/active';
import activeDataProvider from '../data-providers/active';
import { Post } from './lib/definitions';

interface SitemapProps {
Expand Down
4 changes: 3 additions & 1 deletion data-providers/active.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@
// Rest-API Data Provider
import { RestAPIDataProvider } from './rest-api';

export const activeDataProvider = new RestAPIDataProvider();
const activeDataProvider = new RestAPIDataProvider();

export default activeDataProvider;
56 changes: 36 additions & 20 deletions tests/unit-tests/pages.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@ import { render, screen } from '@testing-library/react';
import { readFileSync } from 'fs';
import { Metadata } from 'next';
import React, { Suspense } from 'react';
import { describe, expect, it, test, vi } from 'vitest';
import { beforeEach, describe, expect, test, vi } from 'vitest';

import SinglePostPage, {
SinglePostPageProps,
generateMetadata,
} from '../../app/[slug]/page';
import Home from '../../app/page';
import PrivacyPolicyPage from '../../app/privacy-policy/page';
import activeDataProvider from '../../data-providers/active';
import { MemoryDataProvider } from '../../data-providers/memory';

const jsonData = JSON.parse(readFileSync('tests/test-data.json', 'utf-8'));
const testDataProvider = new MemoryDataProvider(jsonData);

//Mock Next.js useSearchParams
vi.mock('next/navigation', () => {
const actual = vi.importActual('next/navigation');
Expand All @@ -34,15 +32,21 @@ vi.mock('next-mdx-remote/rsc', () => ({
MDXRemote: ({ source }: { source: string }) => <div>{source}</div>,
}));

const jsonData = JSON.parse(readFileSync('tests/test-data.json', 'utf-8'));
const memoryDataProvider = new MemoryDataProvider(jsonData);

test('Home page component should match the snapshot', async () => {
const searchParams = {
query: '',
page: '1',
};

vi.spyOn(activeDataProvider, 'getPostsFromStorage').mockImplementation(() =>
memoryDataProvider.getPostsFromStorage(searchParams),
);
const { container } = render(
<Suspense>
<Home searchParams={searchParams} dataProvider={testDataProvider} />
<Home searchParams={searchParams} />
</Suspense>,
);

Expand All @@ -54,16 +58,21 @@ test('Home page component should match the snapshot', async () => {

describe('Single Post Page', () => {
test('Component should match the snapshot', async () => {
const postSlug = 'post-1';
const params = {
slug: 'post-1',
slug: postSlug,
};

vi.spyOn(
activeDataProvider,
'getSinglePostFromStorage',
).mockImplementation(() =>
memoryDataProvider.getSinglePostFromStorage(postSlug),
);

const { container } = render(
<Suspense>
<SinglePostPage
params={params}
dataProvider={testDataProvider}
/>
<SinglePostPage params={params} />
</Suspense>,
);

Expand All @@ -73,35 +82,42 @@ describe('Single Post Page', () => {
expect(container).toMatchSnapshot();
});

it('generateMetadata should return metadata for a valid post', async () => {
test('generateMetadata should return metadata for a valid post', async () => {
const postSlug = 'post-1';

vi.spyOn(
activeDataProvider,
'getSinglePostFromStorage',
).mockImplementation(() =>
memoryDataProvider.getSinglePostFromStorage(postSlug),
);

const props: SinglePostPageProps = {
dataProvider: testDataProvider,
params: { slug: 'post-1' },
params: { slug: postSlug },
};

// Expected metadata
const expectedMetadata: Metadata = {
title: 'Post 1',
description: 'Post 1 meta description',
};

// Call the generateMetadata function
const result = await generateMetadata(props);

// Verify the result
expect(result).toEqual(expectedMetadata);
});

it('generateMetadata should return null if the post is not found', async () => {
test('generateMetadata should return null if the post is not found', async () => {
const props: SinglePostPageProps = {
dataProvider: testDataProvider,
params: { slug: 'non-existent-post' },
};

// Call the generateMetadata function
vi.spyOn(
activeDataProvider,
'getSinglePostFromStorage',
).mockResolvedValue(null);

const result = await generateMetadata(props);

// Verify the result
expect(result).toBeNull();
});
});
Expand Down

0 comments on commit 2768e45

Please sign in to comment.