diff options
| author | Armand Philippot <git@armandphilippot.com> | 2023-12-06 18:20:54 +0100 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2023-12-07 19:12:11 +0100 |
| commit | b8eb008dd5927fb736e56699637f5f8549965eae (patch) | |
| tree | 648274babea3d3d09ed3e0f5f1fef013f94158fb | |
| parent | 802285872a2c57e7a5e130f32a2b45497d7687f1 (diff) | |
refactor(hooks): replace useGithubApi with useGithubRepoMeta
* use GraphQL API instead of REST (the inconvenient however is that we
now need an authorization token...)
* move fetcher in services
* add tests
* mock response using MSW
36 files changed, 400 insertions, 114 deletions
diff --git a/.cspell/project-words.txt b/.cspell/project-words.txt index 869310d..12398c3 100644 --- a/.cspell/project-words.txt +++ b/.cspell/project-words.txt @@ -16,6 +16,7 @@ hexcode Jamstack LINKEDIN maxage +mkcert nextjs nosniff postbuild diff --git a/.env.example b/.env.example index dbfb664..12ac09a 100644 --- a/.env.example +++ b/.env.example @@ -33,6 +33,7 @@ APP_FEED_DESCRIPTION="What you want..." NEXT_PUBLIC_ACKEE_DOMAIN="www.ackeeDomain.com" NEXT_PUBLIC_ACKEE_FILENAME="tracker.js" NEXT_PUBLIC_ACKEE_SITE_ID="your-id-string" +NEXT_PUBLIC_GITHUB_TOKEN="your-token" # Use this only in development mode. It prevents "unable to verify the first # certificate" error when using a local domain with mkcert certificate for diff --git a/src/pages/projets/[slug].tsx b/src/pages/projets/[slug].tsx index b4bc906..cac6037 100644 --- a/src/pages/projets/[slug].tsx +++ b/src/pages/projets/[slug].tsx @@ -26,7 +26,7 @@ import { mdxComponents } from '../../components/mdx'; import styles from '../../styles/pages/project.module.scss'; import type { NextPageWithLayout, Project, Repos } from '../../types'; import { CONFIG } from '../../utils/config'; -import { ROUTES } from '../../utils/constants'; +import { GITHUB_PSEUDO, ROUTES } from '../../utils/constants'; import { getSchemaJson, getSinglePageSchema, @@ -40,7 +40,7 @@ import { } from '../../utils/helpers/server'; import { useBreadcrumb, - useGithubApi, + useGithubRepoMeta, useHeadingsTree, } from '../../utils/hooks'; @@ -115,31 +115,30 @@ const ProjectPage: NextPageWithLayout<ProjectPageProps> = ({ project }) => { id: 'RwI3B9', }); - const { isError, isLoading, data } = useGithubApi( - /* - * Repo should be defined for each project so for now it is safe for my - * use-case. However, I should refactored it to handle cases where it is - * not defined. The logic should be extracted in another component I think. - * - * TODO: fix this hardly readable argument - */ - meta.repos ? meta.repos.github ?? '' : '' - ); + const { + isError, + isLoading, + meta: githubMeta, + } = useGithubRepoMeta({ + name: repos.github?.substring(repos.github.lastIndexOf('/') + 1) ?? '', + owner: GITHUB_PSEUDO, + }); if (isError) return 'Error'; - if (isLoading || !data) return <Spinner aria-label={loadingRepoPopularity} />; + if (isLoading || !githubMeta) + return <Spinner aria-label={loadingRepoPopularity} />; const overviewMeta: Partial<ProjectMeta> = { - creationDate: data.created_at, - lastUpdateDate: data.updated_at, + creationDate: githubMeta.createdAt, + lastUpdateDate: githubMeta.updatedAt, license, - popularity: repos?.github + popularity: repos.github ? { - count: data.stargazers_count, + count: githubMeta.stargazerCount, url: `https://github.com/${repos.github}/stargazers`, } : undefined, - repositories: repos ? getRepos(repos) : undefined, + repositories: getRepos(repos), technologies, }; diff --git a/src/services/github/fetch-github-repo-meta.test.ts b/src/services/github/fetch-github-repo-meta.test.ts new file mode 100644 index 0000000..324db9a --- /dev/null +++ b/src/services/github/fetch-github-repo-meta.test.ts @@ -0,0 +1,47 @@ +import { afterEach, describe, expect, it } from '@jest/globals'; +import { githubRepos } from '../../../tests/fixtures'; +import { fetchGithubRepoMeta } from './fetch-github-repo-meta'; + +describe('fetch-github-repo-meta', () => { + afterEach(() => { + window.history.replaceState({}, '', '/'); + }); + + it('returns the Github repository meta using GraphQL', async () => { + const result = await fetchGithubRepoMeta({ + name: githubRepos[0].name, + owner: githubRepos[0].owner, + }); + + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + expect.assertions(3); + + expect(result.createdAt).toBe(githubRepos[0].createdAt); + expect(result.stargazerCount).toBe(githubRepos[0].stargazerCount); + expect(result.updatedAt).toBe(githubRepos[0].updatedAt); + }); + + it('rejects with an error when repository is not found', async () => { + const name = 'inexistent-repo'; + const owner = 'inexistent-owner'; + + window.history.replaceState({}, '', '/?error=true'); + expect.assertions(1); + + await expect(async () => + fetchGithubRepoMeta({ name, owner }) + ).rejects.toEqual( + new Error(`No data found for the following repository ${owner}/${name}.`) + ); + }); + + it('throws an error if the Github token is not defined', async () => { + process.env.NEXT_PUBLIC_GITHUB_TOKEN = ''; + + expect.assertions(1); + + await expect(async () => + fetchGithubRepoMeta({ name: 'any-name', owner: 'any-owner' }) + ).rejects.toThrowError(new Error('Github token is not defined.')); + }); +}); diff --git a/src/services/github/fetch-github-repo-meta.ts b/src/services/github/fetch-github-repo-meta.ts new file mode 100644 index 0000000..14c8516 --- /dev/null +++ b/src/services/github/fetch-github-repo-meta.ts @@ -0,0 +1,45 @@ +import type { GithubRepositoryMeta, Nullable } from '../../types'; +import { GITHUB_API } from '../../utils/constants'; +import { fetchGraphQL } from '../../utils/helpers'; + +export type GithubRepositoryResponse = { + repository: Nullable<GithubRepositoryMeta>; +}; + +const githubRepoQuery = `query GithubRepository($name: String!, $owner: String!) { + repository(name: $name, owner: $owner) { + createdAt + stargazerCount + updatedAt + } +}`; + +export type FetchGithubRepoMetaInput = { + name: string; + owner: string; +}; + +export const fetchGithubRepoMeta = async ({ + name, + owner, +}: FetchGithubRepoMetaInput) => { + const token = process.env.NEXT_PUBLIC_GITHUB_TOKEN; + + if (!token) throw new Error('Github token is not defined.'); + + const response = await fetchGraphQL<GithubRepositoryResponse>({ + headers: { + Authorization: `Bearer ${token}`, + }, + query: githubRepoQuery, + url: GITHUB_API, + variables: { name, owner }, + }); + + if (!response.repository) + return Promise.reject( + new Error(`No data found for the following repository ${owner}/${name}.`) + ); + + return response.repository; +}; diff --git a/src/services/github/index.ts b/src/services/github/index.ts new file mode 100644 index 0000000..44b0cbf --- /dev/null +++ b/src/services/github/index.ts @@ -0,0 +1 @@ +export * from './fetch-github-repo-meta'; diff --git a/src/types/data.ts b/src/types/data.ts index 1d0746d..f58d6e7 100644 --- a/src/types/data.ts +++ b/src/types/data.ts @@ -254,7 +254,7 @@ export type Repos = { export type ProjectMeta = Omit<PageMeta, 'wordsCount'> & { contexts?: string[]; license?: string; - repos?: Repos; + repos: Repos; tagline?: string; technologies?: string[]; }; @@ -288,3 +288,9 @@ export type Topic = Page & { id: number; meta: TopicMeta; }; + +export type GithubRepositoryMeta = { + createdAt: string; + stargazerCount: number; + updatedAt: string; +}; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 043a530..f9d6216 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -1,3 +1,7 @@ +export const GITHUB_API = 'https://api.github.com/graphql'; + +export const GITHUB_PSEUDO = 'ArmandPhilippot'; + export const PERSONAL_LINKS = { GITHUB: 'https://github.com/ArmandPhilippot', GITLAB: 'https://gitlab.com/ArmandPhilippot', diff --git a/src/utils/helpers/graphql.ts b/src/utils/helpers/graphql.ts index e07b151..2d78e00 100644 --- a/src/utils/helpers/graphql.ts +++ b/src/utils/helpers/graphql.ts @@ -20,6 +20,7 @@ type GraphQLResponse<T extends GraphQLData<unknown>> = { }; export type FetchGraphQLConfig = { + headers?: HeadersInit; query: string; url: string; variables?: Record<string, unknown>; @@ -35,6 +36,7 @@ export type FetchGraphQLConfig = { export const fetchGraphQL = async < T extends GraphQLData<unknown> = GraphQLData<unknown>, >({ + headers, query, url, variables, @@ -42,6 +44,7 @@ export const fetchGraphQL = async < const response = await fetch(url, { method: 'POST', headers: { + ...headers, 'content-type': 'application/json;charset=UTF-8', }, body: JSON.stringify({ diff --git a/src/utils/hooks/index.ts b/src/utils/hooks/index.ts index 1ee513d..f4d1583 100644 --- a/src/utils/hooks/index.ts +++ b/src/utils/hooks/index.ts @@ -5,7 +5,7 @@ export * from './use-boolean'; export * from './use-breadcrumb'; export * from './use-comments'; export * from './use-form'; -export * from './use-github-api'; +export * from './use-github-repo-meta'; export * from './use-headings-tree'; export * from './use-local-storage'; export * from './use-match-media'; diff --git a/src/utils/hooks/use-github-api.tsx b/src/utils/hooks/use-github-api.tsx deleted file mode 100644 index aa9e3f7..0000000 --- a/src/utils/hooks/use-github-api.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import useSWR, { Fetcher } from 'swr'; -import { SWRResult } from '../../types'; - -export type RepoData = { - created_at: string; - updated_at: string; - stargazers_count: number; -}; - -const fetcher: Fetcher<RepoData, string> = (...args) => - fetch(...args).then((res) => res.json()); - -/** - * Retrieve data from Github API. - * - * @param repo - The Github repo (`owner/repo-name`). - * @returns The repository data. - */ -export const useGithubApi = (repo: string): SWRResult<RepoData> => { - const apiUrl = repo ? `https://api.github.com/repos/${repo}` : null; - const { data, error } = useSWR<RepoData>(apiUrl, fetcher); - - return { - data, - isLoading: !error && !data, - isError: error, - }; -}; diff --git a/src/utils/hooks/use-github-repo-meta/index.ts b/src/utils/hooks/use-github-repo-meta/index.ts new file mode 100644 index 0000000..352adc9 --- /dev/null +++ b/src/utils/hooks/use-github-repo-meta/index.ts @@ -0,0 +1 @@ +export * from './use-github-repo-meta'; diff --git a/src/utils/hooks/use-github-repo-meta/use-github-repo-meta.test.ts b/src/utils/hooks/use-github-repo-meta/use-github-repo-meta.test.ts new file mode 100644 index 0000000..d796f69 --- /dev/null +++ b/src/utils/hooks/use-github-repo-meta/use-github-repo-meta.test.ts @@ -0,0 +1,59 @@ +import { + afterEach, + beforeEach, + describe, + expect, + it, + jest, +} from '@jest/globals'; +import { renderHook, waitFor } from '@testing-library/react'; +import { githubRepos } from '../../../../tests/fixtures'; +import { useGithubRepoMeta } from './use-github-repo-meta'; + +describe('useGithubRepoMeta', () => { + beforeEach(() => { + /* Not sure why it is needed, but without it Jest was complaining with + * `Jest worker encountered 4 child process exceptions`... Maybe because of + * useSWR? */ + jest.useFakeTimers({ + doNotFake: ['queueMicrotask'], + }); + }); + + afterEach(() => { + jest.runOnlyPendingTimers(); + jest.useRealTimers(); + }); + + /* eslint-disable max-statements */ + it('fetches the requested repository', async () => { + const { result } = renderHook(() => + useGithubRepoMeta({ + name: githubRepos[0].name, + owner: githubRepos[0].owner, + }) + ); + + // Inaccurate assertions count because of waitFor... + //expect.assertions(11); + expect.hasAssertions(); + + expect(result.current.meta).toBeUndefined(); + expect(result.current.isError).toBe(false); + expect(result.current.isLoading).toBe(true); + expect(result.current.isValidating).toBe(true); + + jest.advanceTimersToNextTimer(); + + await waitFor(() => expect(result.current.meta).toBeDefined()); + expect(result.current.meta?.createdAt).toBe(githubRepos[0].createdAt); + expect(result.current.meta?.stargazerCount).toBe( + githubRepos[0].stargazerCount + ); + expect(result.current.meta?.updatedAt).toBe(githubRepos[0].updatedAt); + expect(result.current.isError).toBe(false); + expect(result.current.isLoading).toBe(false); + expect(result.current.isValidating).toBe(false); + }); + /* eslint-enable max-statements */ +}); diff --git a/src/utils/hooks/use-github-repo-meta/use-github-repo-meta.ts b/src/utils/hooks/use-github-repo-meta/use-github-repo-meta.ts new file mode 100644 index 0000000..888682e --- /dev/null +++ b/src/utils/hooks/use-github-repo-meta/use-github-repo-meta.ts @@ -0,0 +1,37 @@ +import useSWR from 'swr'; +import { + type FetchGithubRepoMetaInput, + fetchGithubRepoMeta, +} from '../../../services/github'; +import type { GithubRepositoryMeta, Maybe } from '../../../types'; + +export type UseGithubRepoMetaReturn<T extends Maybe<GithubRepositoryMeta>> = { + isError: boolean; + isLoading: boolean; + isValidating: boolean; + meta: T extends undefined + ? Maybe<GithubRepositoryMeta> + : GithubRepositoryMeta; +}; + +export const useGithubRepoMeta = <T extends Maybe<GithubRepositoryMeta>>( + input: FetchGithubRepoMetaInput, + fallback?: T +) => { + const { data, error, isLoading, isValidating } = useSWR( + input, + fetchGithubRepoMeta, + { + fallbackData: fallback, + } + ); + + if (error) console.error(error); + + return { + isError: !!error, + isLoading, + isValidating, + meta: data, + } as UseGithubRepoMetaReturn<T>; +}; diff --git a/tests/fixtures/github-repos.fixture.ts b/tests/fixtures/github-repos.fixture.ts new file mode 100644 index 0000000..5eaa1ce --- /dev/null +++ b/tests/fixtures/github-repos.fixture.ts @@ -0,0 +1,30 @@ +import type { GithubRepositoryMeta } from '../../src/types'; + +type GithubRepository = GithubRepositoryMeta & { + name: string; + owner: string; +}; + +export const githubRepos = [ + { + createdAt: '2020-09-26', + name: 'laborum', + owner: 'Dion', + stargazerCount: 8, + updatedAt: '2023-05-05', + }, + { + createdAt: '2020-10-30', + name: 'quo', + owner: 'Brennan', + stargazerCount: 0, + updatedAt: '2022-03-01', + }, + { + createdAt: '2021-11-16', + name: 'soluta', + owner: 'Alex', + stargazerCount: 8, + updatedAt: '2023-08-10', + }, +] satisfies GithubRepository[]; diff --git a/tests/fixtures/index.ts b/tests/fixtures/index.ts index 2ae0185..249b608 100644 --- a/tests/fixtures/index.ts +++ b/tests/fixtures/index.ts @@ -1,3 +1,4 @@ +export * from './github-repos.fixture'; export * from './wp-comments.fixture'; export * from './wp-posts.fixture'; export * from './wp-thematics.fixture'; diff --git a/tests/msw/handlers/comments/comments-list.handler.ts b/tests/msw/handlers/comments/comments-list.handler.ts index e815a0e..ad760fc 100644 --- a/tests/msw/handlers/comments/comments-list.handler.ts +++ b/tests/msw/handlers/comments/comments-list.handler.ts @@ -1,13 +1,14 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { FetchCommentsListInput, CommentsListResponse, } from '../../../../src/services/graphql'; import { wpCommentsFixture } from '../../../fixtures'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const commentsListHandler = graphql.query< +export const commentsListHandler = wordpressAPI.query< CommentsListResponse, FetchCommentsListInput >('CommentsList', async ({ query, variables }) => { @@ -16,7 +17,7 @@ export const commentsListHandler = graphql.query< if (isError) return HttpResponse.json({ data: { comments: null } }); - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/handlers/index.ts b/tests/msw/handlers/index.ts index 85a2300..bfdeb95 100644 --- a/tests/msw/handlers/index.ts +++ b/tests/msw/handlers/index.ts @@ -1,11 +1,13 @@ import { commentsHandlers } from './comments'; import { postsHandlers } from './posts'; +import { repositoriesHandlers } from './repositories'; import { thematicsHandlers } from './thematics'; import { topicsHandlers } from './topics'; export const handlers = [ ...commentsHandlers, ...postsHandlers, + ...repositoriesHandlers, ...thematicsHandlers, ...topicsHandlers, ]; diff --git a/tests/msw/handlers/posts/last-post-cursor.handler.ts b/tests/msw/handlers/posts/last-post-cursor.handler.ts index 2f4b648..f5c58dc 100644 --- a/tests/msw/handlers/posts/last-post-cursor.handler.ts +++ b/tests/msw/handlers/posts/last-post-cursor.handler.ts @@ -1,11 +1,12 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { LastPostCursorResponse } from '../../../../src/services/graphql'; import { wpPostsFixture } from '../../../fixtures'; import { getConnection } from '../../../utils/graphql'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const lastPostCursorHandler = graphql.query< +export const lastPostCursorHandler = wordpressAPI.query< LastPostCursorResponse, Record<'first', number> >('LastPostCursor', async ({ query, variables }) => { @@ -14,7 +15,7 @@ export const lastPostCursorHandler = graphql.query< if (isError) return HttpResponse.json({ data: { posts: null } }); - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/handlers/posts/post.handler.ts b/tests/msw/handlers/posts/post.handler.ts index 4abdfed..72f7b95 100644 --- a/tests/msw/handlers/posts/post.handler.ts +++ b/tests/msw/handlers/posts/post.handler.ts @@ -1,21 +1,22 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { PostResponse } from '../../../../src/services/graphql'; import { wpPostsFixture } from '../../../fixtures'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const postHandler = graphql.query<PostResponse, Record<'slug', string>>( - 'Post', - async ({ query, variables }) => { - const { data, errors } = (await executeGraphql({ - schema, - source: query, - variableValues: variables, - rootValue: { - post: wpPostsFixture.find((wpPost) => wpPost.slug === variables.slug), - }, - })) as ExecutionResult<PostResponse>; +export const postHandler = wordpressAPI.query< + PostResponse, + Record<'slug', string> +>('Post', async ({ query, variables }) => { + const { data, errors } = (await graphql({ + schema, + source: query, + variableValues: variables, + rootValue: { + post: wpPostsFixture.find((wpPost) => wpPost.slug === variables.slug), + }, + })) as ExecutionResult<PostResponse>; - return HttpResponse.json({ data, errors }); - } -); + return HttpResponse.json({ data, errors }); +}); diff --git a/tests/msw/handlers/posts/posts-count.handler.ts b/tests/msw/handlers/posts/posts-count.handler.ts index 95fa105..a4425a5 100644 --- a/tests/msw/handlers/posts/posts-count.handler.ts +++ b/tests/msw/handlers/posts/posts-count.handler.ts @@ -1,12 +1,13 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { PostsCountResponse } from '../../../../src/services/graphql'; import type { GraphQLPostWhere } from '../../../../src/types'; import { wpPostsFixture } from '../../../fixtures'; import { getConnection } from '../../../utils/graphql'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const postsCountHandler = graphql.query< +export const postsCountHandler = wordpressAPI.query< PostsCountResponse, GraphQLPostWhere >('PostsCount', async ({ query, variables }) => { @@ -15,7 +16,7 @@ export const postsCountHandler = graphql.query< if (isError) return HttpResponse.json({ data: { posts: null } }); - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/handlers/posts/posts-list.handler.ts b/tests/msw/handlers/posts/posts-list.handler.ts index 7f8daf6..e4992d1 100644 --- a/tests/msw/handlers/posts/posts-list.handler.ts +++ b/tests/msw/handlers/posts/posts-list.handler.ts @@ -1,14 +1,15 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { FetchPostsListInput, PostsListResponse, } from '../../../../src/services/graphql'; import { wpPostsFixture } from '../../../fixtures'; import { getConnection } from '../../../utils/graphql'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const postsListHandler = graphql.query< +export const postsListHandler = wordpressAPI.query< PostsListResponse, FetchPostsListInput >('PostsList', async ({ query, variables }) => { @@ -17,7 +18,7 @@ export const postsListHandler = graphql.query< if (isError) return HttpResponse.json({ data: { posts: null } }); - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/handlers/posts/posts-slugs.handler.ts b/tests/msw/handlers/posts/posts-slugs.handler.ts index 9aadddb..69e300a 100644 --- a/tests/msw/handlers/posts/posts-slugs.handler.ts +++ b/tests/msw/handlers/posts/posts-slugs.handler.ts @@ -1,10 +1,11 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { PostsSlugsResponse } from '../../../../src/services/graphql'; import { wpPostsFixture } from '../../../fixtures'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const postsSlugsHandler = graphql.query< +export const postsSlugsHandler = wordpressAPI.query< PostsSlugsResponse, Record<'first', number> >('PostsSlugs', async ({ query, variables }) => { @@ -13,7 +14,7 @@ export const postsSlugsHandler = graphql.query< if (isError) return HttpResponse.json({ data: { posts: null } }); - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/handlers/posts/recent-posts.handler.ts b/tests/msw/handlers/posts/recent-posts.handler.ts index 34e0efb..eb89324 100644 --- a/tests/msw/handlers/posts/recent-posts.handler.ts +++ b/tests/msw/handlers/posts/recent-posts.handler.ts @@ -1,14 +1,15 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { FetchPostsListInput, RecentPostsResponse, } from '../../../../src/services/graphql'; import { wpPostsFixture } from '../../../fixtures'; import { getConnection } from '../../../utils/graphql'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const recentPostsHandler = graphql.query< +export const recentPostsHandler = wordpressAPI.query< RecentPostsResponse, FetchPostsListInput >('RecentPosts', async ({ query, variables }) => { @@ -17,7 +18,7 @@ export const recentPostsHandler = graphql.query< if (isError) return HttpResponse.json({ data: { posts: null } }); - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/handlers/repositories/index.ts b/tests/msw/handlers/repositories/index.ts new file mode 100644 index 0000000..b29a41f --- /dev/null +++ b/tests/msw/handlers/repositories/index.ts @@ -0,0 +1,3 @@ +import { repositoryHandler } from './repository.handler'; + +export const repositoriesHandlers = [repositoryHandler]; diff --git a/tests/msw/handlers/repositories/repository.handler.ts b/tests/msw/handlers/repositories/repository.handler.ts new file mode 100644 index 0000000..2c459c1 --- /dev/null +++ b/tests/msw/handlers/repositories/repository.handler.ts @@ -0,0 +1,32 @@ +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; +import type { + FetchGithubRepoMetaInput, + GithubRepositoryResponse, +} from '../../../../src/services/github'; +import { githubRepos } from '../../../fixtures'; +import { githubAPI } from '../../instances'; +import { githubSchema } from '../../schema'; + +export const repositoryHandler = githubAPI.query< + GithubRepositoryResponse, + FetchGithubRepoMetaInput +>('GithubRepository', async ({ query, variables }) => { + const pageParams = new URLSearchParams(window.location.search); + const isError = pageParams.get('error') === 'true'; + + if (isError) return HttpResponse.json({ data: { repository: null } }); + + const { data, errors } = (await graphql({ + schema: githubSchema, + source: query, + variableValues: variables, + rootValue: { + repository: githubRepos.find( + (repo) => repo.owner === variables.owner && repo.name === variables.name + ), + }, + })) as ExecutionResult<GithubRepositoryResponse>; + + return HttpResponse.json({ data, errors }); +}); diff --git a/tests/msw/handlers/thematics/thematic.handler.ts b/tests/msw/handlers/thematics/thematic.handler.ts index 1e7d129..ad82ea6 100644 --- a/tests/msw/handlers/thematics/thematic.handler.ts +++ b/tests/msw/handlers/thematics/thematic.handler.ts @@ -1,14 +1,15 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { ThematicResponse } from '../../../../src/services/graphql'; import { wpThematicsFixture } from '../../../fixtures'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const thematicHandler = graphql.query< +export const thematicHandler = wordpressAPI.query< ThematicResponse, Record<'slug', string> >('Thematic', async ({ query, variables }) => { - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/handlers/thematics/thematics-count.handler.ts b/tests/msw/handlers/thematics/thematics-count.handler.ts index 4bcdf2d..8a1f12e 100644 --- a/tests/msw/handlers/thematics/thematics-count.handler.ts +++ b/tests/msw/handlers/thematics/thematics-count.handler.ts @@ -1,12 +1,13 @@ import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { HttpResponse } from 'msw'; import type { ThematicsCountResponse } from '../../../../src/services/graphql'; import type { GraphQLPostWhere } from '../../../../src/types'; import { wpThematicsFixture } from '../../../fixtures'; import { getConnection } from '../../../utils/graphql'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const thematicsCountHandler = graphql.query< +export const thematicsCountHandler = wordpressAPI.query< ThematicsCountResponse, GraphQLPostWhere >('ThematicsCount', async ({ query, variables }) => { diff --git a/tests/msw/handlers/thematics/thematics-list.handler.ts b/tests/msw/handlers/thematics/thematics-list.handler.ts index 7afec4c..790fa5a 100644 --- a/tests/msw/handlers/thematics/thematics-list.handler.ts +++ b/tests/msw/handlers/thematics/thematics-list.handler.ts @@ -1,14 +1,15 @@ import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { HttpResponse } from 'msw'; import type { FetchThematicsListInput, ThematicsListResponse, } from '../../../../src/services/graphql'; import { wpThematicsFixture } from '../../../fixtures'; import { getConnection } from '../../../utils/graphql'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const thematicsListHandler = graphql.query< +export const thematicsListHandler = wordpressAPI.query< ThematicsListResponse, FetchThematicsListInput >('ThematicsList', async ({ query, variables }) => { diff --git a/tests/msw/handlers/thematics/thematics-slugs.handler.ts b/tests/msw/handlers/thematics/thematics-slugs.handler.ts index 3a71c8e..77bbeda 100644 --- a/tests/msw/handlers/thematics/thematics-slugs.handler.ts +++ b/tests/msw/handlers/thematics/thematics-slugs.handler.ts @@ -1,10 +1,11 @@ import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { HttpResponse } from 'msw'; import type { ThematicsSlugsResponse } from '../../../../src/services/graphql'; import { wpThematicsFixture } from '../../../fixtures'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const thematicsSlugsHandler = graphql.query< +export const thematicsSlugsHandler = wordpressAPI.query< ThematicsSlugsResponse, Record<'first', number> >('ThematicsSlugs', async ({ query, variables }) => { diff --git a/tests/msw/handlers/topics/topic.handler.ts b/tests/msw/handlers/topics/topic.handler.ts index 5df00ea..1cb565b 100644 --- a/tests/msw/handlers/topics/topic.handler.ts +++ b/tests/msw/handlers/topics/topic.handler.ts @@ -1,14 +1,15 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { TopicResponse } from '../../../../src/services/graphql'; import { wpTopicsFixture } from '../../../fixtures'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const topicHandler = graphql.query< +export const topicHandler = wordpressAPI.query< TopicResponse, Record<'slug', string> >('Topic', async ({ query, variables }) => { - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/handlers/topics/topics-count.handler.ts b/tests/msw/handlers/topics/topics-count.handler.ts index 7e3dab9..0a48d06 100644 --- a/tests/msw/handlers/topics/topics-count.handler.ts +++ b/tests/msw/handlers/topics/topics-count.handler.ts @@ -1,12 +1,13 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { TopicsCountResponse } from '../../../../src/services/graphql'; import type { GraphQLPostWhere } from '../../../../src/types'; import { wpTopicsFixture } from '../../../fixtures'; import { getConnection } from '../../../utils/graphql'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const topicsCountHandler = graphql.query< +export const topicsCountHandler = wordpressAPI.query< TopicsCountResponse, GraphQLPostWhere >('TopicsCount', async ({ query, variables }) => { @@ -15,7 +16,7 @@ export const topicsCountHandler = graphql.query< if (isError) return HttpResponse.json({ data: { topics: null } }); - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/handlers/topics/topics-list.handler.ts b/tests/msw/handlers/topics/topics-list.handler.ts index 4b09c5a..86a8dba 100644 --- a/tests/msw/handlers/topics/topics-list.handler.ts +++ b/tests/msw/handlers/topics/topics-list.handler.ts @@ -1,14 +1,15 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { FetchTopicsListInput, TopicsListResponse, } from '../../../../src/services/graphql'; import { wpTopicsFixture } from '../../../fixtures'; import { getConnection } from '../../../utils/graphql'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const topicsListHandler = graphql.query< +export const topicsListHandler = wordpressAPI.query< TopicsListResponse, FetchTopicsListInput >('TopicsList', async ({ query, variables }) => { @@ -17,7 +18,7 @@ export const topicsListHandler = graphql.query< if (isError) return HttpResponse.json({ data: { topics: null } }); - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/handlers/topics/topics-slugs.handler.ts b/tests/msw/handlers/topics/topics-slugs.handler.ts index 960e411..779a384 100644 --- a/tests/msw/handlers/topics/topics-slugs.handler.ts +++ b/tests/msw/handlers/topics/topics-slugs.handler.ts @@ -1,10 +1,11 @@ -import { type ExecutionResult, graphql as executeGraphql } from 'graphql'; -import { HttpResponse, graphql } from 'msw'; +import { type ExecutionResult, graphql } from 'graphql'; +import { HttpResponse } from 'msw'; import type { TopicsSlugsResponse } from '../../../../src/services/graphql'; import { wpTopicsFixture } from '../../../fixtures'; +import { wordpressAPI } from '../../instances'; import { schema } from '../../schema'; -export const topicsSlugsHandler = graphql.query< +export const topicsSlugsHandler = wordpressAPI.query< TopicsSlugsResponse, Record<'first', number> >('TopicsSlugs', async ({ query, variables }) => { @@ -13,7 +14,7 @@ export const topicsSlugsHandler = graphql.query< if (isError) return HttpResponse.json({ data: { topics: null } }); - const { data, errors } = (await executeGraphql({ + const { data, errors } = (await graphql({ schema, source: query, variableValues: variables, diff --git a/tests/msw/instances/index.ts b/tests/msw/instances/index.ts new file mode 100644 index 0000000..82218c3 --- /dev/null +++ b/tests/msw/instances/index.ts @@ -0,0 +1,10 @@ +import { graphql } from 'msw'; +import { GITHUB_API } from '../../../src/utils/constants'; + +const wordpressGraphQLUrl = process.env.NEXT_PUBLIC_STAGING_GRAPHQL_API; + +if (!wordpressGraphQLUrl) + throw new Error('You forgot to define an URL for the WordPress GraphQL API'); + +export const githubAPI = graphql.link(GITHUB_API); +export const wordpressAPI = graphql.link(wordpressGraphQLUrl); diff --git a/tests/msw/schema/index.ts b/tests/msw/schema/index.ts index 3763616..c818d50 100644 --- a/tests/msw/schema/index.ts +++ b/tests/msw/schema/index.ts @@ -36,3 +36,20 @@ export const schema = addResolversToSchema({ schema: schemaFromTypes, resolvers, }); + +export const githubSchema = buildSchema(` +scalar DateTime + +type Repository { + createdAt: DateTime! + stargazerCount: Int! + updatedAt: DateTime! +} + +type Query { + repository( + followRenames: Boolean = true + name: String! + owner: String! + ): Repository +}`); |
