Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PWA-989: Real Data Wishlists and Wishlist Create #3041

Merged
merged 19 commits into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

exports[`should return properly 1`] = `
Object {
"formErrors": Map {
"createWishlistMutation" => undefined,
},
"handleCreateList": [Function],
"handleHideModal": [Function],
"handleShowModal": [Function],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,57 +1,95 @@
import React from 'react';

import createTestInstance from '../../../util/createTestInstance';
import { useCreateWishlist } from '../useCreateWishlist';
import { MockedProvider } from '@apollo/client/testing';
import { renderHook, act } from '@testing-library/react-hooks';
import { InMemoryCache } from '@apollo/client';

const Component = props => {
const talonProps = useCreateWishlist(props);
import { useCreateWishlist } from '../useCreateWishlist';
import defaultOperations from '../createWishlist.gql';

return <i talonProps={talonProps} />;
const createWishlistVariables = {
name: 'Test WishList',
visibility: 'PUBLIC'
};

const getTalonProps = props => {
const tree = createTestInstance(<Component {...props} />);
const { root } = tree;
const { talonProps } = root.findByType('i').props;

const update = newProps => {
tree.update(<Component {...{ ...props, ...newProps }} />);
const cache = new InMemoryCache().restore({
ROOT_QUERY: {
customer: {
id: 'customerId',
firstName: 'Veronica',
wishlists: []
}
}
});

return root.findByType('i').props.talonProps;
};
const createWishlistMock = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you test the loading state of this mutation? I'm trying to do this in my PR but I'm having trouble...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nvm, found it :D Just don't await the act'ed click.

request: {
query: defaultOperations.createWishlistMutation,
variables: createWishlistVariables
},
result: () => {
return {
data: {
createWishlist: {
wishlist: {
id: '42',
name: 'Test WishList',
visibility: 'PUBLIC'
}
}
}
};
}
};

return { talonProps, tree, update };
const renderHookWithProviders = ({
renderHookOptions = {},
mocks = [createWishlistMock]
} = {}) => {
const wrapper = ({ children }) => (
<MockedProvider mocks={mocks} cache={cache}>
{children}
</MockedProvider>
);

return renderHook(useCreateWishlist, { wrapper, ...renderHookOptions });
};

test('should return properly', () => {
const { talonProps } = getTalonProps();

expect(talonProps).toMatchSnapshot();
const { result } = renderHookWithProviders();
expect(result.current).toMatchSnapshot();
});

test('handleShowModal should set isModalOpen to true', () => {
const { talonProps, update } = getTalonProps();

talonProps.handleShowModal();
const { isModalOpen } = update();

expect(isModalOpen).toBeTruthy();
test('should return error', async () => {
const createWishlistErrorMock = {
request: createWishlistMock.request,
error: new Error('Only 5 wish list(s) can be created.')
};
const { result } = renderHookWithProviders({
mocks: [createWishlistErrorMock]
});
await act(() => result.current.handleCreateList(createWishlistVariables));
expect(
result.current.formErrors.get('createWishlistMutation')
).toMatchInlineSnapshot(`[Error: Only 5 wish list(s) can be created.]`);
});

test('handleHideModal should set isModalOpen to false', () => {
const { talonProps, update } = getTalonProps();

talonProps.handleHideModal();
const { isModalOpen } = update();

expect(isModalOpen).toBeFalsy();
test('handleShowModal should set isModalOpen to true', async () => {
const { result } = renderHookWithProviders();
await act(() => result.current.handleShowModal());
expect(result.current.isModalOpen).toBe(true);
});

test('handleCreateList should set isModalOpen to false', () => {
const { talonProps, update } = getTalonProps();

talonProps.handleCreateList();
const { isModalOpen } = update();
test('handleHideModal should set isModalOpen to false', async () => {
const { result } = renderHookWithProviders();
await act(() => result.current.handleHideModal());
expect(result.current.isModalOpen).toBe(false);
});

expect(isModalOpen).toBeFalsy();
test('handleCreateList should update cache and set isModalOpen to false', async () => {
const { result } = renderHookWithProviders();
await act(() => result.current.handleCreateList(createWishlistVariables));
const updatedCache = cache.extract();
expect(updatedCache[`ROOT_QUERY`].customer.wishlists[0].id).toBe('42');
expect(result.current.isModalOpen).toBe(false);
});
38 changes: 38 additions & 0 deletions packages/peregrine/lib/talons/WishlistPage/createWishlist.gql.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { gql } from '@apollo/client';

export const CREATE_WISHLIST = gql`
mutation createWishlist(
$name: String!
$visibility: WishlistVisibilityEnum!
) {
createWishlist(input: { name: $name, visibility: $visibility }) {
tjwiebell marked this conversation as resolved.
Show resolved Hide resolved
wishlist {
id
items_count
name
visibility
sharing_code
}
}
}
`;

export const GET_CUSTOMER_WISHLISTS = gql`
query GetCustomerWishlist {
customer {
id
wishlists {
id
items_count
name
visibility
sharing_code
}
}
}
`;

export default {
createWishlistMutation: CREATE_WISHLIST,
getCustomerWishlistsQuery: GET_CUSTOMER_WISHLISTS
};
69 changes: 60 additions & 9 deletions packages/peregrine/lib/talons/WishlistPage/useCreateWishlist.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,45 @@
import { useState, useCallback } from 'react';
import { useState, useCallback, useMemo } from 'react';
import { useMutation, useApolloClient } from '@apollo/client';
import mergeOperations from '../../util/shallowMerge';

import DEFAULT_OPERATIONS from './createWishlist.gql';

/**
* @function
*
* @returns {CreateWishListProps}
*/
export const useCreateWishlist = () => {
export const useCreateWishlist = (props = {}) => {
const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
const { createWishlistMutation, getCustomerWishlistsQuery } = operations;
const apolloClient = useApolloClient();
const [isModalOpen, setIsModalOpen] = useState(false);
const [createWishlist, { error: createWishlistError }] = useMutation(
createWishlistMutation,
{
update(
cache,
{
data: { createWishlist }
}
) {
const { customer } = apolloClient.readQuery({
query: getCustomerWishlistsQuery
});
apolloClient.writeQuery({
tjwiebell marked this conversation as resolved.
Show resolved Hide resolved
query: getCustomerWishlistsQuery,
data: {
customer: {
...customer,
wishlists: customer.wishlists.concat([
createWishlist.wishlist
])
}
}
});
}
}
);

const handleShowModal = useCallback(() => {
setIsModalOpen(true);
Expand All @@ -16,18 +49,36 @@ export const useCreateWishlist = () => {
setIsModalOpen(false);
}, []);

const handleCreateList = useCallback(data => {
// TODO create list mutation is not available yet
// Will be handled in PWA-989
console.log('Creating wish list with data: ', data);
setIsModalOpen(false);
}, []);
const handleCreateList = useCallback(
async data => {
try {
await createWishlist({
variables: {
name: data.name,
visibility: data.visibility
}
tjwiebell marked this conversation as resolved.
Show resolved Hide resolved
});
setIsModalOpen(false);
} catch (error) {
if (process.env.NODE_ENV !== 'production') {
console.error(error);
}
}
},
[createWishlist, setIsModalOpen]
);

const errors = useMemo(
() => new Map([['createWishlistMutation', createWishlistError]]),
[createWishlistError]
);

return {
handleCreateList,
handleHideModal,
handleShowModal,
isModalOpen
isModalOpen,
formErrors: errors
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useHistory } from 'react-router-dom';
import { useQuery } from '@apollo/client';

import { useUserContext } from '../../context/user';
import { useTypePolicies } from '../../hooks/useTypePolicies';

/**
* @function
Expand All @@ -14,11 +13,9 @@ import { useTypePolicies } from '../../hooks/useTypePolicies';
* @returns {WishlistPageProps}
*/
export const useWishlistPage = props => {
const { queries, types } = props;
const { queries } = props;
const { getCustomerWishlistQuery } = queries;

useTypePolicies(types);

const history = useHistory();
const [{ isSignedIn }] = useUserContext();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ exports[`renders correctly 1`] = `
formProps={
Object {
"initialValues": Object {
"sharing_code": "private",
"visibility": "PRIVATE",
},
}
}
Expand All @@ -87,6 +87,15 @@ exports[`renders correctly 1`] = `
<div
className="form"
>
<div
className="root"
>
<span
className="errorMessage"
>
Form Error
</span>
</div>
<div
className="root"
>
Expand Down Expand Up @@ -139,7 +148,7 @@ exports[`renders correctly 1`] = `
onBlur={[Function]}
onChange={[Function]}
type="radio"
value="private"
value="PRIVATE"
/>
<span
className="icon"
Expand Down Expand Up @@ -177,7 +186,7 @@ exports[`renders correctly 1`] = `
onBlur={[Function]}
onChange={[Function]}
type="radio"
value="public"
value="PUBLIC"
/>
<span
className="icon"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ exports[`render closed with items 1`] = `
<span
className="visibility"
>
Public
Private
</span>
</div>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ jest.mock(
handleCreateList: jest.fn().mockName('handleCreateList'),
handleHideModal: jest.fn().mockName('handleHideModal'),
handleShowModal: jest.fn().mockName('handleShowModal'),
isModalOpen: false
isModalOpen: false,
formErrors: new Map([['error', new Error('Form Error')]])
})
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ test('render open with no items', () => {
const props = {
data: {
items_count: 0,
items_v2: [],
items_v2: { items: [] },
name: 'Favorites List',
sharing_code: null
}
Expand All @@ -38,7 +38,7 @@ test('render closed with items', () => {
const props = {
data: {
items_count: 20,
items_v2: ['item1', 'item2'],
items_v2: { items: ['item1', 'item2'] },
name: 'Favorites List',
sharing_code: 'abc123'
}
Expand Down
Loading