Skip to content

Commit

Permalink
add tests for useProfile and usePublication
Browse files Browse the repository at this point in the history
  • Loading branch information
krzysu committed Oct 9, 2023
1 parent 17b1b2c commit 614574b
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 5 deletions.
53 changes: 53 additions & 0 deletions packages/api-bindings/src/apollo/cache/createProfileFieldPolicy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
defaultDataIdFromObject,
FieldFunctionOptions,
FieldPolicy,
Reference,
StoreObject,
} from '@apollo/client';
import { never } from '@lens-protocol/shared-kernel';

import { Profile, ProfileRequest } from '../../lens';

function isProfile(value: StoreObject | undefined): value is Profile {
return value?.__typename === 'Profile';
}

const identifierPattern =
defaultDataIdFromObject({ __typename: 'Profile', id: '0x[a-fA-F0-9]{2,}' }) ?? never();
const identifierMatcher = new RegExp(`^${identifierPattern}$`);

export function createProfileFieldPolicy(): FieldPolicy<
Profile,
Profile,
Reference,
FieldFunctionOptions<{ request: ProfileRequest }>
> {
return {
keyArgs: [['request', ['forProfileId', 'forHandle']]],

read(_, { args, toReference, cache }) {
if (args?.request.forProfileId) {
return toReference({
__typename: 'Profile',
id: args.request.forProfileId,
});
}

const normalizedCacheObject = cache.extract(true);

for (const key in normalizedCacheObject) {
const value = normalizedCacheObject[key];

if (
identifierMatcher.test(key) &&
isProfile(value) &&
value.handle === args?.request.forHandle
) {
return toReference(value);
}
}
return;
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { StrictTypedTypePolicies } from '../../lens';

export function createProfileTypePolicy(): StrictTypedTypePolicies['Profile'] {
return {
fields: {},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { FieldFunctionOptions, FieldPolicy, Reference } from '@apollo/client';

import { AnyPublication, PublicationRequest } from '../../lens';

export function createPublicationFieldPolicy(): FieldPolicy<
AnyPublication,
AnyPublication,
Reference,
FieldFunctionOptions<{ request: PublicationRequest }>
> {
return {
keyArgs: [['request', ['forId', 'forHandle']]],

read(_, { args, toReference }) {
if (args?.request.forId) {
return toReference({
__typename: 'Publication',
id: args.request.forId,
});
}

return;
},
};
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { StoreObject } from '@apollo/client';

const publicationTypename = 'Publication';

export function createPublicationTypePolicy() {
return {
keyFields: ({ id }: Readonly<StoreObject>) => `${publicationTypename}:${String(id)}`,
keyFields: ({ id }: Readonly<StoreObject>) => `Publication:${String(id)}`,
} as const;
}
9 changes: 8 additions & 1 deletion packages/api-bindings/src/apollo/cache/createTypePolicies.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { TypePolicy } from '@apollo/client';
import { FieldPolicy, TypePolicy } from '@apollo/client';

import { StrictTypedTypePolicies } from '../../lens';
import { createFeedFieldPolicy } from './createFeedFieldPolicy';
import { createProfileFieldPolicy } from './createProfileFieldPolicy';
import { createProfileTypePolicy } from './createProfileTypePolicy';
import { createPublicationFieldPolicy } from './createPublicationFieldPolicy';
import { createPublicationTypePolicy } from './createPublicationTypePolicy';
import { createQueryParamsLocalFields, QueryParams } from './createQueryParamsLocalFields';
import {
Expand All @@ -27,6 +30,7 @@ export function createTypePolicies(
params?: QueryParams,
): StrictTypedTypePolicies & InheritedTypePolicies {
return {
Profile: createProfileTypePolicy(),
Publication: createPublicationTypePolicy(),
Post: notNormalizedType(),
Comment: notNormalizedType(),
Expand All @@ -43,13 +47,16 @@ export function createTypePolicies(
following: createFollowingFieldPolicy(),
mutualFollowers: createMutualFollowersFieldPolicy(),
profileActionHistory: createProfileActionHistoryFieldPolicy(),
profile: createProfileFieldPolicy() as FieldPolicy<unknown>,
profileRecommendations: createProfileRecommendationsFieldPolicy(),
profiles: createProfilesFieldPolicy(),
publication: createPublicationFieldPolicy() as FieldPolicy<unknown>,
publications: createPublicationsFieldPolicy(),
searchProfiles: createSearchProfilesFieldPolicy(),
searchPublications: createSearchPublicationsFieldPolicy(),
whoActedOnPublication: createWhoActedOnPublicationFieldPolicy(),
whoReactedPublication: createWhoReactedPublicationFieldPolicy(),

...createQueryParamsLocalFields(params),
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
ProfileRecommendationsDocument,
ProfileRecommendationsVariables,
ProfileWhoReactedResult,
ProfileDocument,
ProfilesDocument,
ProfilesVariables,
ProfileVariables,
Expand All @@ -23,6 +22,7 @@ import {
WhoActedOnPublicationVariables,
WhoReactedPublicationDocument,
WhoReactedPublicationVariables,
ProfileDocument,
} from '../../graphql/generated';
import { mockPaginatedResultInfo } from '../fragments';
import { mockAnyPaginatedResponse, mockAnyResponse } from './mockAnyPaginatedResponse';
Expand Down
54 changes: 54 additions & 0 deletions packages/react/src/profile/__tests__/useProfile.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { mockProfileFragment, mockProfileResponse } from '@lens-protocol/api-bindings/mocks';
import { waitFor } from '@testing-library/react';

import { NotFoundError } from '../../NotFoundError';
import { setupHookTestScenario } from '../../__helpers__/setupHookTestScenario';
import { useProfile } from '../useProfile';

describe(`Given the ${useProfile.name} hook`, () => {
const profile = mockProfileFragment();
const expectations = { __typename: 'Profile', id: profile.id };

describe.each([
{
description: 'when invoked with a profile id',
args: { forProfileId: profile.id },
},
{
description: 'when invoked with a profile handle',
args: { forHandle: profile.handle },
},
])('$description', ({ args }) => {
it('should settle with the profile data', async () => {
const { renderHook } = setupHookTestScenario([
mockProfileResponse({
variables: {
request: args,
},
result: profile,
}),
]);

const { result } = renderHook(() => useProfile(args));

await waitFor(() => expect(result.current.loading).toBeFalsy());
expect(result.current.data).toMatchObject(expectations);
});

it(`should settle with a ${NotFoundError.name} if not found`, async () => {
const { renderHook } = setupHookTestScenario([
mockProfileResponse({
variables: {
request: args,
},
result: null,
}),
]);

const { result } = renderHook(() => useProfile(args));

await waitFor(() => expect(result.current.loading).toBeFalsy());
expect(result.current.error).toBeInstanceOf(NotFoundError);
});
});
});
51 changes: 51 additions & 0 deletions packages/react/src/publication/__tests__/usePublication.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { mockPostFragment, mockPublicationResponse } from '@lens-protocol/api-bindings/mocks';
import { waitFor } from '@testing-library/react';

import { NotFoundError } from '../../NotFoundError';
import { setupHookTestScenario } from '../../__helpers__/setupHookTestScenario';
import { usePublication } from '../usePublication';

describe(`Given the ${usePublication.name} hook`, () => {
const publication = mockPostFragment();
const expectations = { __typename: 'Post', id: publication.id };

describe('when the queried publication exists', () => {
const { renderHook } = setupHookTestScenario([
mockPublicationResponse({
variables: {
request: {
forId: publication.id,
},
},
publication,
}),
]);

it('should settle with the publication data', async () => {
const { result } = renderHook(() => usePublication({ forId: publication.id }));

await waitFor(() => expect(result.current.loading).toBeFalsy());
expect(result.current.data).toMatchObject(expectations);
});
});

describe('when the queried publication does not exist', () => {
const { renderHook } = setupHookTestScenario([
mockPublicationResponse({
variables: {
request: {
forId: publication.id,
},
},
publication: null,
}),
]);

it(`should settle with a ${NotFoundError.name} state`, async () => {
const { result } = renderHook(() => usePublication({ forId: publication.id }));

await waitFor(() => expect(result.current.loading).toBeFalsy());
expect(result.current.error).toBeInstanceOf(NotFoundError);
});
});
});

0 comments on commit 614574b

Please sign in to comment.