summaryrefslogtreecommitdiffstats
path: root/finished-application/frontend/__tests__
diff options
context:
space:
mode:
authorWes Bos <wesbos@gmail.com>2018-09-14 12:18:12 -0400
committerWes Bos <wesbos@gmail.com>2018-09-14 12:18:12 -0400
commit2d145b026cfdf54a63bef0b9d6324b6785390307 (patch)
treef6c1d8f987437803a5c026e70535bf9ff244e885 /finished-application/frontend/__tests__
parent8a5825d52271d712ec7c8348447d433067e13ef2 (diff)
move finished folder
Diffstat (limited to 'finished-application/frontend/__tests__')
-rw-r--r--finished-application/frontend/__tests__/AddToCart.test.js97
-rw-r--r--finished-application/frontend/__tests__/Cart.test.js39
-rw-r--r--finished-application/frontend/__tests__/CartCount.test.js21
-rw-r--r--finished-application/frontend/__tests__/CreateItem.test.js112
-rw-r--r--finished-application/frontend/__tests__/Item.test.js39
-rw-r--r--finished-application/frontend/__tests__/Nav.test.js76
-rw-r--r--finished-application/frontend/__tests__/Order.test.js27
-rw-r--r--finished-application/frontend/__tests__/Pagination.test.js89
-rw-r--r--finished-application/frontend/__tests__/PleaseSignIn.test.js51
-rw-r--r--finished-application/frontend/__tests__/RemoveFromCart.test.js67
-rw-r--r--finished-application/frontend/__tests__/RequestReset.test.js46
-rw-r--r--finished-application/frontend/__tests__/Signup.test.js80
-rw-r--r--finished-application/frontend/__tests__/SingleItem.test.js57
-rw-r--r--finished-application/frontend/__tests__/TakeMyMoney.test.js98
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/AddToCart.test.js.snap11
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/Cart.test.js.snap32
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/CartCount.test.js.snap79
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/CreateItem.test.js.snap77
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/Item.test.js.snap58
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/Nav.test.js.snap37
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/Order.test.js.snap118
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/Pagination.test.js.snap67
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/RemoveFromCart.test.js.snap12
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/RequestReset.test.js.snap39
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/Signup.test.js.snap62
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/SingleItem.test.js.snap32
-rw-r--r--finished-application/frontend/__tests__/__snapshots__/TakeMyMoney.test.js.snap67
-rw-r--r--finished-application/frontend/__tests__/formatMoney.test.js23
-rw-r--r--finished-application/frontend/__tests__/mocking.test.js36
-rw-r--r--finished-application/frontend/__tests__/sample.test.js19
30 files changed, 1668 insertions, 0 deletions
diff --git a/finished-application/frontend/__tests__/AddToCart.test.js b/finished-application/frontend/__tests__/AddToCart.test.js
new file mode 100644
index 0000000..cfc2e3e
--- /dev/null
+++ b/finished-application/frontend/__tests__/AddToCart.test.js
@@ -0,0 +1,97 @@
+import { mount } from 'enzyme';
+import wait from 'waait';
+import toJSON from 'enzyme-to-json';
+import { MockedProvider } from 'react-apollo/test-utils';
+import { ApolloConsumer } from 'react-apollo';
+import AddToCart, { ADD_TO_CART_MUTATION } from '../components/AddToCart';
+import { CURRENT_USER_QUERY } from '../components/User';
+import { fakeUser, fakeCartItem } from '../lib/testUtils';
+
+const mocks = [
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: {
+ data: {
+ me: {
+ ...fakeUser(),
+ cart: [],
+ },
+ },
+ },
+ },
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: {
+ data: {
+ me: {
+ ...fakeUser(),
+ cart: [fakeCartItem()],
+ },
+ },
+ },
+ },
+ {
+ request: { query: ADD_TO_CART_MUTATION, variables: { id: 'abc123' } },
+ result: {
+ data: {
+ addToCart: {
+ ...fakeCartItem(),
+ quantity: 1,
+ },
+ },
+ },
+ },
+];
+
+describe('<AddToCart/>', () => {
+ it('renders and matches the snap shot', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <AddToCart id="abc123" />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ expect(toJSON(wrapper.find('button'))).toMatchSnapshot();
+ });
+
+ it('adds an item to cart when clicked', async () => {
+ let apolloClient;
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <ApolloConsumer>
+ {client => {
+ apolloClient = client;
+ return <AddToCart id="abc123" />;
+ }}
+ </ApolloConsumer>
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ const { data: { me } } = await apolloClient.query({ query: CURRENT_USER_QUERY });
+ // console.log(me);
+ expect(me.cart).toHaveLength(0);
+ // add an item to the cart
+ wrapper.find('button').simulate('click');
+ await wait();
+ // check if the item is in the cart
+ const { data: { me: me2 } } = await apolloClient.query({ query: CURRENT_USER_QUERY });
+ expect(me2.cart).toHaveLength(1);
+ expect(me2.cart[0].id).toBe('omg123');
+ expect(me2.cart[0].quantity).toBe(3);
+ });
+
+ it('changes from add to adding when clicked', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <AddToCart id="abc123" />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ expect(wrapper.text()).toContain('Add To Cart');
+ wrapper.find('button').simulate('click');
+ expect(wrapper.text()).toContain('Adding To Cart');
+ });
+});
diff --git a/finished-application/frontend/__tests__/Cart.test.js b/finished-application/frontend/__tests__/Cart.test.js
new file mode 100644
index 0000000..b8afc88
--- /dev/null
+++ b/finished-application/frontend/__tests__/Cart.test.js
@@ -0,0 +1,39 @@
+import { mount } from 'enzyme';
+import wait from 'waait';
+import toJSON from 'enzyme-to-json';
+import { MockedProvider } from 'react-apollo/test-utils';
+import Cart, { LOCAL_STATE_QUERY } from '../components/Cart';
+import { CURRENT_USER_QUERY } from '../components/User';
+import { fakeUser, fakeCartItem } from '../lib/testUtils';
+
+const mocks = [
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: {
+ data: {
+ me: {
+ ...fakeUser(),
+ cart: [fakeCartItem()],
+ },
+ },
+ },
+ },
+ {
+ request: { query: LOCAL_STATE_QUERY },
+ result: { data: { cartOpen: true } },
+ },
+];
+
+describe('<Cart/>', () => {
+ it('renders and matches snappy', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <Cart />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ expect(toJSON(wrapper.find('header'))).toMatchSnapshot();
+ expect(wrapper.find('CartItem')).toHaveLength(1);
+ });
+});
diff --git a/finished-application/frontend/__tests__/CartCount.test.js b/finished-application/frontend/__tests__/CartCount.test.js
new file mode 100644
index 0000000..8ace3da
--- /dev/null
+++ b/finished-application/frontend/__tests__/CartCount.test.js
@@ -0,0 +1,21 @@
+import { shallow, mount } from 'enzyme';
+import toJSON from 'enzyme-to-json';
+import CartCount from '../components/CartCount';
+
+describe('<CartCount/>', () => {
+ it('renders', () => {
+ shallow(<CartCount count={10} />);
+ });
+
+ it('matches the snapshot', () => {
+ const wrapper = shallow(<CartCount count={11} />);
+ expect(toJSON(wrapper)).toMatchSnapshot();
+ });
+
+ it('updates via props', () => {
+ const wrapper = shallow(<CartCount count={50} />);
+ expect(toJSON(wrapper)).toMatchSnapshot();
+ wrapper.setProps({ count: 10 });
+ expect(toJSON(wrapper)).toMatchSnapshot();
+ });
+});
diff --git a/finished-application/frontend/__tests__/CreateItem.test.js b/finished-application/frontend/__tests__/CreateItem.test.js
new file mode 100644
index 0000000..6e88d94
--- /dev/null
+++ b/finished-application/frontend/__tests__/CreateItem.test.js
@@ -0,0 +1,112 @@
+import { mount } from 'enzyme';
+import wait from 'waait';
+import toJSON from 'enzyme-to-json';
+import Router from 'next/router';
+import { MockedProvider } from 'react-apollo/test-utils';
+import CreateItem, { CREATE_ITEM_MUTATION } from '../components/CreateItem';
+import { fakeItem } from '../lib/testUtils';
+
+const dogImage = 'https://dog.com/dog.jpg';
+
+// mock the global fetch API
+global.fetch = jest.fn().mockResolvedValue({
+ json: () => ({
+ secure_url: dogImage,
+ eager: [{ secure_url: dogImage }],
+ }),
+});
+
+describe('<CreateItem/>', () => {
+ it('renders and matches snapshot', async () => {
+ const wrapper = mount(
+ <MockedProvider>
+ <CreateItem />
+ </MockedProvider>
+ );
+ const form = wrapper.find('form[data-test="form"]');
+ expect(toJSON(form)).toMatchSnapshot();
+ });
+
+ it('uploads a file when changed', async () => {
+ const wrapper = mount(
+ <MockedProvider>
+ <CreateItem />
+ </MockedProvider>
+ );
+ const input = wrapper.find('input[type="file"]');
+ input.simulate('change', { target: { files: ['fakedog.jpg'] } });
+ await wait();
+ const component = wrapper.find('CreateItem').instance();
+ expect(component.state.image).toEqual(dogImage);
+ expect(component.state.largeImage).toEqual(dogImage);
+ expect(global.fetch).toHaveBeenCalled();
+ global.fetch.mockReset();
+ });
+
+ it('handles state updating', async () => {
+ const wrapper = mount(
+ <MockedProvider>
+ <CreateItem />
+ </MockedProvider>
+ );
+ wrapper.find('#title').simulate('change', { target: { value: 'Testing', name: 'title' } });
+ wrapper
+ .find('#price')
+ .simulate('change', { target: { value: 50000, name: 'price', type: 'number' } });
+ wrapper
+ .find('#description')
+ .simulate('change', { target: { value: 'This is a really nice item', name: 'description' } });
+
+ expect(wrapper.find('CreateItem').instance().state).toMatchObject({
+ title: 'Testing',
+ price: 50000,
+ description: 'This is a really nice item',
+ });
+ });
+ it('creates an item when the form is submitted', async () => {
+ const item = fakeItem();
+ const mocks = [
+ {
+ request: {
+ query: CREATE_ITEM_MUTATION,
+ variables: {
+ title: item.title,
+ description: item.description,
+ image: '',
+ largeImage: '',
+ price: item.price,
+ },
+ },
+ result: {
+ data: {
+ createItem: {
+ ...fakeItem,
+ id: 'abc123',
+ __typename: 'Item',
+ },
+ },
+ },
+ },
+ ];
+
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <CreateItem />
+ </MockedProvider>
+ );
+ // simulate someone filling out the form
+ wrapper.find('#title').simulate('change', { target: { value: item.title, name: 'title' } });
+ wrapper
+ .find('#price')
+ .simulate('change', { target: { value: item.price, name: 'price', type: 'number' } });
+ wrapper
+ .find('#description')
+ .simulate('change', { target: { value: item.description, name: 'description' } });
+ // mock the router
+ Router.router = { push: jest.fn() };
+ wrapper.find('form').simulate('submit');
+ await wait(50);
+ expect(Router.router.push).toHaveBeenCalled();
+ expect(Router.router.push).toHaveBeenCalledWith({ pathname: '/item', query: { id: 'abc123' } });
+ });
+});
diff --git a/finished-application/frontend/__tests__/Item.test.js b/finished-application/frontend/__tests__/Item.test.js
new file mode 100644
index 0000000..692b913
--- /dev/null
+++ b/finished-application/frontend/__tests__/Item.test.js
@@ -0,0 +1,39 @@
+import ItemComponent from '../components/Item';
+import { shallow, mount } from 'enzyme';
+import toJSON from 'enzyme-to-json';
+
+const fakeItem = {
+ id: 'ABC123',
+ title: 'A Cool Item',
+ price: 4000,
+ description: 'This item is really cool!',
+ image: 'dog.jpg',
+ largeImage: 'largedog.jpg',
+};
+
+describe('<Item/>', () => {
+ it('renders and matches the snapshot', () => {
+ const wrapper = shallow(<ItemComponent item={fakeItem} />);
+ expect(toJSON(wrapper)).toMatchSnapshot();
+ });
+ // it('renders the image properly', () => {
+ // const wrapper = shallow(<ItemComponent item={fakeItem} />);
+ // const img = wrapper.find('img');
+ // expect(img.props().src).toBe(fakeItem.image);
+ // expect(img.props().alt).toBe(fakeItem.title);
+ // });
+ // it('renders the pricetag and title', () => {
+ // const wrapper = shallow(<ItemComponent item={fakeItem} />);
+ // const PriceTag = wrapper.find('PriceTag');
+ // expect(PriceTag.children().text()).toBe('$50');
+ // expect(wrapper.find('Title a').text()).toBe(fakeItem.title);
+ // });
+ // it('renders out the buttons properly', () => {
+ // const wrapper = shallow(<ItemComponent item={fakeItem} />);
+ // const buttonList = wrapper.find('.buttonList');
+ // expect(buttonList.children()).toHaveLength(3);
+ // expect(buttonList.find('Link')).toHaveLength(1);
+ // expect(buttonList.find('AddToCart').exists()).toBe(true);
+ // expect(buttonList.find('DeleteItem').exists()).toBe(true);
+ // });
+});
diff --git a/finished-application/frontend/__tests__/Nav.test.js b/finished-application/frontend/__tests__/Nav.test.js
new file mode 100644
index 0000000..d30cb39
--- /dev/null
+++ b/finished-application/frontend/__tests__/Nav.test.js
@@ -0,0 +1,76 @@
+import { mount } from 'enzyme';
+import wait from 'waait';
+import toJSON from 'enzyme-to-json';
+import Nav from '../components/Nav';
+import { CURRENT_USER_QUERY } from '../components/User';
+import { MockedProvider } from 'react-apollo/test-utils';
+import { fakeUser, fakeCartItem } from '../lib/testUtils';
+
+const notSignedInMocks = [
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: { data: { me: null } },
+ },
+];
+
+const signedInMocks = [
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: { data: { me: fakeUser() } },
+ },
+];
+
+const signedInMocksWithCartItems = [
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: {
+ data: {
+ me: {
+ ...fakeUser(),
+ cart: [fakeCartItem(), fakeCartItem(), fakeCartItem()],
+ },
+ },
+ },
+ },
+];
+
+describe('<Nav/>', () => {
+ it('renders a minimal nav when signed out', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={notSignedInMocks}>
+ <Nav />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ // console.log(wrapper.debug());
+ const nav = wrapper.find('ul[data-test="nav"]');
+ expect(toJSON(nav)).toMatchSnapshot();
+ });
+
+ it('renders full nav when signed in', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={signedInMocks}>
+ <Nav />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ const nav = wrapper.find('ul[data-test="nav"]');
+ expect(nav.children().length).toBe(6);
+ expect(nav.text()).toContain('Sign Out');
+ });
+
+ it('renders the amount of items in the cart', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={signedInMocksWithCartItems}>
+ <Nav />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ const nav = wrapper.find('[data-test="nav"]');
+ const count = nav.find('div.count');
+ expect(toJSON(count)).toMatchSnapshot();
+ });
+});
diff --git a/finished-application/frontend/__tests__/Order.test.js b/finished-application/frontend/__tests__/Order.test.js
new file mode 100644
index 0000000..71accfa
--- /dev/null
+++ b/finished-application/frontend/__tests__/Order.test.js
@@ -0,0 +1,27 @@
+import { mount } from 'enzyme';
+import toJSON from 'enzyme-to-json';
+import wait from 'waait';
+import { MockedProvider } from 'react-apollo/test-utils';
+import Order, { SINGLE_ORDER_QUERY } from '../components/Order';
+import { fakeOrder } from '../lib/testUtils';
+
+const mocks = [
+ {
+ request: { query: SINGLE_ORDER_QUERY, variables: { id: 'ord123' } },
+ result: { data: { order: fakeOrder() } },
+ },
+];
+
+describe('<Order/>', () => {
+ it('renders the order', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <Order id="ord123" />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ const order = wrapper.find('div[data-test="order"]');
+ expect(toJSON(order)).toMatchSnapshot();
+ });
+});
diff --git a/finished-application/frontend/__tests__/Pagination.test.js b/finished-application/frontend/__tests__/Pagination.test.js
new file mode 100644
index 0000000..7117db8
--- /dev/null
+++ b/finished-application/frontend/__tests__/Pagination.test.js
@@ -0,0 +1,89 @@
+import { mount } from 'enzyme';
+import wait from 'waait';
+import toJSON from 'enzyme-to-json';
+import Router from 'next/router';
+import Pagination, { PAGINATION_QUERY } from '../components/Pagination';
+import { MockedProvider } from 'react-apollo/test-utils';
+
+Router.router = {
+ push() {},
+ prefetch() {},
+};
+
+function makeMocksFor(length) {
+ return [
+ {
+ request: { query: PAGINATION_QUERY },
+ result: {
+ data: {
+ itemsConnection: {
+ __typename: 'aggregate',
+ aggregate: {
+ count: length,
+ __typename: 'count',
+ },
+ },
+ },
+ },
+ },
+ ];
+}
+
+describe('<Pagination/>', () => {
+ it('displays a loading message', () => {
+ const wrapper = mount(
+ <MockedProvider mocks={makeMocksFor(1)}>
+ <Pagination page={1} />
+ </MockedProvider>
+ );
+ const pagination = wrapper.find('[data-test="pagination"]');
+ expect(wrapper.text()).toContain('Loading...');
+ });
+
+ it('renders pagination for 18 items', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={makeMocksFor(18)}>
+ <Pagination page={1} />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ expect(wrapper.find('.totalPages').text()).toEqual('5');
+ const pagination = wrapper.find('div[data-test="pagination"]');
+ expect(toJSON(pagination)).toMatchSnapshot();
+ });
+
+ it('disables prev button on first page', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={makeMocksFor(18)}>
+ <Pagination page={1} />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ expect(wrapper.find('a.prev').prop('aria-disabled')).toEqual(true);
+ expect(wrapper.find('a.next').prop('aria-disabled')).toEqual(false);
+ });
+ it('disables next button on last page', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={makeMocksFor(18)}>
+ <Pagination page={5} />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ expect(wrapper.find('a.prev').prop('aria-disabled')).toEqual(false);
+ expect(wrapper.find('a.next').prop('aria-disabled')).toEqual(true);
+ });
+ it('enables all buttons on a middle page', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={makeMocksFor(18)}>
+ <Pagination page={3} />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ expect(wrapper.find('a.prev').prop('aria-disabled')).toEqual(false);
+ expect(wrapper.find('a.next').prop('aria-disabled')).toEqual(false);
+ });
+});
diff --git a/finished-application/frontend/__tests__/PleaseSignIn.test.js b/finished-application/frontend/__tests__/PleaseSignIn.test.js
new file mode 100644
index 0000000..7d476b4
--- /dev/null
+++ b/finished-application/frontend/__tests__/PleaseSignIn.test.js
@@ -0,0 +1,51 @@
+import { mount } from 'enzyme';
+import wait from 'waait';
+import PleaseSignIn from '../components/PleaseSignIn';
+import { CURRENT_USER_QUERY } from '../components/User';
+import { MockedProvider } from 'react-apollo/test-utils';
+import { fakeUser } from '../lib/testUtils';
+
+const notSignedInMocks = [
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: { data: { me: null } },
+ },
+];
+
+const signedInMocks = [
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: { data: { me: fakeUser() } },
+ },
+];
+
+describe('<PleaseSignIn/>', () => {
+ it('renders the sign in dialog to logged out users', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={notSignedInMocks}>
+ <PleaseSignIn />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ expect(wrapper.text()).toContain('Please Sign In before Continuing');
+ const SignIn = wrapper.find('Signin');
+ expect(SignIn.exists()).toBe(true);
+ });
+
+ it('renders the child component when the user is signed in', async () => {
+ const Hey = () => <p>Hey!</p>;
+ const wrapper = mount(
+ <MockedProvider mocks={signedInMocks}>
+ <PleaseSignIn>
+ <Hey />
+ </PleaseSignIn>
+ </MockedProvider>
+ );
+
+ await wait();
+ wrapper.update();
+ // expect(wrapper.find('Hey').exists()).toBe(true);
+ expect(wrapper.contains(<Hey />)).toBe(true);
+ });
+});
diff --git a/finished-application/frontend/__tests__/RemoveFromCart.test.js b/finished-application/frontend/__tests__/RemoveFromCart.test.js
new file mode 100644
index 0000000..faacc91
--- /dev/null
+++ b/finished-application/frontend/__tests__/RemoveFromCart.test.js
@@ -0,0 +1,67 @@
+import { mount } from 'enzyme';
+import wait from 'waait';
+import toJSON from 'enzyme-to-json';
+import { MockedProvider } from 'react-apollo/test-utils';
+import { ApolloConsumer } from 'react-apollo';
+import RemoveFromCart, { REMOVE_FROM_CART_MUTATION } from '../components/RemoveFromCart';
+import { CURRENT_USER_QUERY } from '../components/User';
+import { fakeUser, fakeCartItem } from '../lib/testUtils';
+
+global.alert = console.log;
+
+const mocks = [
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: {
+ data: {
+ me: {
+ ...fakeUser(),
+ cart: [fakeCartItem({ id: 'abc123' })],
+ },
+ },
+ },
+ },
+ {
+ request: { query: REMOVE_FROM_CART_MUTATION, variables: { id: 'abc123' } },
+ result: {
+ data: {
+ removeFromCart: {
+ __typename: 'CartItem',
+ id: 'abc123',
+ },
+ },
+ },
+ },
+];
+
+describe('<RemoveFromCart/>', () => {
+ it('renders and matches snapshot', async () => {
+ const wrapper = mount(
+ <MockedProvider>
+ <RemoveFromCart id="abc123" />
+ </MockedProvider>
+ );
+ expect(toJSON(wrapper.find('button'))).toMatchSnapshot();
+ });
+
+ it('removes the item from cart', async () => {
+ let apolloClient;
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <ApolloConsumer>
+ {client => {
+ apolloClient = client;
+ return <RemoveFromCart id="abc123" />;
+ }}
+ </ApolloConsumer>
+ </MockedProvider>
+ );
+ const res = await apolloClient.query({ query: CURRENT_USER_QUERY });
+ expect(res.data.me.cart).toHaveLength(1);
+ expect(res.data.me.cart[0].item.price).toBe(5000);
+ wrapper.find('button').simulate('click');
+ await wait();
+ const res2 = await apolloClient.query({ query: CURRENT_USER_QUERY });
+ expect(res2.data.me.cart).toHaveLength(0);
+ });
+});
diff --git a/finished-application/frontend/__tests__/RequestReset.test.js b/finished-application/frontend/__tests__/RequestReset.test.js
new file mode 100644
index 0000000..345b365
--- /dev/null
+++ b/finished-application/frontend/__tests__/RequestReset.test.js
@@ -0,0 +1,46 @@
+import { mount } from 'enzyme';
+import wait from 'waait';
+import toJSON from 'enzyme-to-json';
+import { MockedProvider } from 'react-apollo/test-utils';
+import RequestReset, { REQUEST_RESET_MUTATION } from '../components/RequestReset';
+
+const mocks = [
+ {
+ request: {
+ query: REQUEST_RESET_MUTATION,
+ variables: { email: 'wesbos@gmail.com' },
+ },
+ result: {
+ data: { requestReset: { message: 'success', __typename: 'Message' } },
+ },
+ },
+];
+
+describe('<RequestReset/>', () => {
+ it('renders and matches snapshot', async () => {
+ const wrapper = mount(
+ <MockedProvider>
+ <RequestReset />
+ </MockedProvider>
+ );
+ const form = wrapper.find('form[data-test="form"]');
+ expect(toJSON(form)).toMatchSnapshot();
+ });
+
+ it('calls the mutation', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <RequestReset />
+ </MockedProvider>
+ );
+ // simulate typing an email
+ wrapper
+ .find('input')
+ .simulate('change', { target: { name: 'email', value: 'wesbos@gmail.com' } });
+ // submit the form
+ wrapper.find('form').simulate('submit');
+ await wait();
+ wrapper.update();
+ expect(wrapper.find('p').text()).toContain('Success! Check your email for a reset link!');
+ });
+});
diff --git a/finished-application/frontend/__tests__/Signup.test.js b/finished-application/frontend/__tests__/Signup.test.js
new file mode 100644
index 0000000..e18bdee
--- /dev/null
+++ b/finished-application/frontend/__tests__/Signup.test.js
@@ -0,0 +1,80 @@
+import { mount } from 'enzyme';
+import wait from 'waait';
+import toJSON from 'enzyme-to-json';
+import { MockedProvider } from 'react-apollo/test-utils';
+import { ApolloConsumer } from 'react-apollo';
+import Signup, { SIGNUP_MUTATION } from '../components/Signup';
+import { CURRENT_USER_QUERY } from '../components/User';
+import { fakeUser } from '../lib/testUtils';
+
+function type(wrapper, name, value) {
+ wrapper.find(`input[name="${name}"]`).simulate('change', {
+ target: { name, value },
+ });
+}
+
+const me = fakeUser();
+const mocks = [
+ // signup mock mutation
+ {
+ request: {
+ query: SIGNUP_MUTATION,
+ variables: {
+ name: me.name,
+ email: me.email,
+ password: 'wes',
+ },
+ },
+ result: {
+ data: {
+ signup: {
+ __typename: 'User',
+ id: 'abc123',
+ email: me.email,
+ name: me.name,
+ },
+ },
+ },
+ },
+ // current user query mock
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: { data: { me } },
+ },
+];
+
+describe('<Signup/>', () => {
+ it('renders and matches snapshot', async () => {
+ const wrapper = mount(
+ <MockedProvider>
+ <Signup />
+ </MockedProvider>
+ );
+ expect(toJSON(wrapper.find('form'))).toMatchSnapshot();
+ });
+
+ it('calls the mutation properly', async () => {
+ let apolloClient;
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <ApolloConsumer>
+ {client => {
+ apolloClient = client;
+ return <Signup />;
+ }}
+ </ApolloConsumer>
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ type(wrapper, 'name', me.name);
+ type(wrapper, 'email', me.email);
+ type(wrapper, 'password', 'wes');
+ wrapper.update();
+ wrapper.find('form').simulate('submit');
+ await wait();
+ // query the user out of the apollo client
+ const user = await apolloClient.query({ query: CURRENT_USER_QUERY });
+ expect(user.data.me).toMatchObject(me);
+ });
+});
diff --git a/finished-application/frontend/__tests__/SingleItem.test.js b/finished-application/frontend/__tests__/SingleItem.test.js
new file mode 100644
index 0000000..2963bde
--- /dev/null
+++ b/finished-application/frontend/__tests__/SingleItem.test.js
@@ -0,0 +1,57 @@
+import { mount } from 'enzyme';
+import toJSON from 'enzyme-to-json';
+import wait from 'waait';
+import SingleItem, { SINGLE_ITEM_QUERY } from '../components/SingleItem';
+import { MockedProvider } from 'react-apollo/test-utils';
+import { fakeItem } from '../lib/testUtils';
+
+describe('<SingleItem/>', () => {
+ it('renders with proper data', async () => {
+ const mocks = [
+ {
+ // when someone makes a request with this query and variable combo
+ request: { query: SINGLE_ITEM_QUERY, variables: { id: '123' } },
+ // return this fake data (mocked data)
+ result: {
+ data: {
+ item: fakeItem(),
+ },
+ },
+ },
+ ];
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <SingleItem id="123" />
+ </MockedProvider>
+ );
+ expect(wrapper.text()).toContain('Loading...');
+ await wait();
+ wrapper.update();
+ // console.log(wrapper.debug());
+ expect(toJSON(wrapper.find('h2'))).toMatchSnapshot();
+ expect(toJSON(wrapper.find('img'))).toMatchSnapshot();
+ expect(toJSON(wrapper.find('p'))).toMatchSnapshot();
+ });
+
+ it('Errors with a not found item', async () => {
+ const mocks = [
+ {
+ request: { query: SINGLE_ITEM_QUERY, variables: { id: '123' } },
+ result: {
+ errors: [{ message: 'Items Not Found!' }],
+ },
+ },
+ ];
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <SingleItem id="123" />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ console.log(wrapper.debug());
+ const item = wrapper.find('[data-test="graphql-error"]');
+ expect(item.text()).toContain('Items Not Found!');
+ expect(toJSON(item)).toMatchSnapshot();
+ });
+});
diff --git a/finished-application/frontend/__tests__/TakeMyMoney.test.js b/finished-application/frontend/__tests__/TakeMyMoney.test.js
new file mode 100644
index 0000000..3d68502
--- /dev/null
+++ b/finished-application/frontend/__tests__/TakeMyMoney.test.js
@@ -0,0 +1,98 @@
+import { mount } from 'enzyme';
+import wait from 'waait';
+import toJSON from 'enzyme-to-json';
+import NProgress from 'nprogress';
+import Router from 'next/router';
+import { MockedProvider } from 'react-apollo/test-utils';
+import { ApolloConsumer } from 'react-apollo';
+import TakeMyMoney, { CREATE_ORDER_MUTATION } from '../components/TakeMyMoney';
+import { CURRENT_USER_QUERY } from '../components/User';
+import { fakeUser, fakeCartItem } from '../lib/testUtils';
+
+Router.router = { push() {} };
+
+const mocks = [
+ {
+ request: { query: CURRENT_USER_QUERY },
+ result: {
+ data: {
+ me: {
+ ...fakeUser(),
+ cart: [fakeCartItem()],
+ },
+ },
+ },
+ },
+];
+
+describe('<TakeMyMoney/>', () => {
+ it('renders and matches snapshot', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <TakeMyMoney />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ const checkoutButton = wrapper.find('ReactStripeCheckout');
+ expect(toJSON(checkoutButton)).toMatchSnapshot();
+ });
+ it('creates an order ontoken', async () => {
+ const createOrderMock = jest.fn().mockResolvedValue({
+ data: { createOrder: { id: 'xyz789' } },
+ });
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <TakeMyMoney />
+ </MockedProvider>
+ );
+ const component = wrapper.find('TakeMyMoney').instance();
+ // manully call that onToken method
+ component.onToken({ id: 'abc123' }, createOrderMock);
+ expect(createOrderMock).toHaveBeenCalled();
+ expect(createOrderMock).toHaveBeenCalledWith({ variables: { token: 'abc123' } });
+ });
+
+ it('turns the progress bar on', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <TakeMyMoney />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ NProgress.start = jest.fn();
+ const createOrderMock = jest.fn().mockResolvedValue({
+ data: { createOrder: { id: 'xyz789' } },
+ });
+ const component = wrapper.find('TakeMyMoney').instance();
+ // manully call that onToken method
+ component.onToken({ id: 'abc123' }, createOrderMock);
+ expect(NProgress.start).toHaveBeenCalled();
+ });
+
+ it('routes to the order page when completed', async () => {
+ const wrapper = mount(
+ <MockedProvider mocks={mocks}>
+ <TakeMyMoney />
+ </MockedProvider>
+ );
+ await wait();
+ wrapper.update();
+ const createOrderMock = jest.fn().mockResolvedValue({
+ data: { createOrder: { id: 'xyz789' } },
+ });
+ const component = wrapper.find('TakeMyMoney').instance();
+ Router.router.push = jest.fn();
+ // manully call that onToken method
+ component.onToken({ id: 'abc123' }, createOrderMock);
+ await wait();
+ expect(Router.router.push).toHaveBeenCalled();
+ expect(Router.router.push).toHaveBeenCalledWith({
+ pathname: '/order',
+ query: {
+ id: 'xyz789',
+ },
+ });
+ });
+});
diff --git a/finished-application/frontend/__tests__/__snapshots__/AddToCart.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/AddToCart.test.js.snap
new file mode 100644
index 0000000..2f489d4
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/AddToCart.test.js.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<AddToCart/> renders and matches the snap shot 1`] = `
+<button
+ disabled={false}
+ onClick={[Function]}
+>
+ Add
+ To Cart 🛒
+</button>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/Cart.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/Cart.test.js.snap
new file mode 100644
index 0000000..d5c0d92
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/Cart.test.js.snap
@@ -0,0 +1,32 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<Cart/> renders and matches snappy 1`] = `
+<header>
+ <CloseButton
+ onClick={[Function]}
+ title="close"
+ >
+ <button
+ className="CloseButton-sc-1seb878-0 lbNKfp"
+ onClick={[Function]}
+ title="close"
+ >
+ ×
+ </button>
+ </CloseButton>
+ <Supreme>
+ <h3
+ className="Supreme-xv30qb-0 hpaXsq"
+ >
+ Miss Coleman Berge
+ 's Cart
+ </h3>
+ </Supreme>
+ <p>
+ You Have
+ 1
+ Item
+ in your cart.
+ </p>
+</header>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/CartCount.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/CartCount.test.js.snap
new file mode 100644
index 0000000..92ee89a
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/CartCount.test.js.snap
@@ -0,0 +1,79 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<CartCount/> matches the snapshot 1`] = `
+<CartCount__AnimationStyles>
+ <TransitionGroup
+ childFactory={[Function]}
+ component="div"
+ >
+ <CSSTransition
+ className="count"
+ classNames="count"
+ key="11"
+ timeout={
+ Object {
+ "enter": 400,
+ "exit": 400,
+ }
+ }
+ unmountOnExit={true}
+ >
+ <CartCount__Dot>
+ 11
+ </CartCount__Dot>
+ </CSSTransition>
+ </TransitionGroup>
+</CartCount__AnimationStyles>
+`;
+
+exports[`<CartCount/> updates via props 1`] = `
+<CartCount__AnimationStyles>
+ <TransitionGroup
+ childFactory={[Function]}
+ component="div"
+ >
+ <CSSTransition
+ className="count"
+ classNames="count"
+ key="50"
+ timeout={
+ Object {
+ "enter": 400,
+ "exit": 400,
+ }
+ }
+ unmountOnExit={true}
+ >
+ <CartCount__Dot>
+ 50
+ </CartCount__Dot>
+ </CSSTransition>
+ </TransitionGroup>
+</CartCount__AnimationStyles>
+`;
+
+exports[`<CartCount/> updates via props 2`] = `
+<CartCount__AnimationStyles>
+ <TransitionGroup
+ childFactory={[Function]}
+ component="div"
+ >
+ <CSSTransition
+ className="count"
+ classNames="count"
+ key="10"
+ timeout={
+ Object {
+ "enter": 400,
+ "exit": 400,
+ }
+ }
+ unmountOnExit={true}
+ >
+ <CartCount__Dot>
+ 10
+ </CartCount__Dot>
+ </CSSTransition>
+ </TransitionGroup>
+</CartCount__AnimationStyles>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/CreateItem.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/CreateItem.test.js.snap
new file mode 100644
index 0000000..59d8557
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/CreateItem.test.js.snap
@@ -0,0 +1,77 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<CreateItem/> renders and matches snapshot 1`] = `
+<form
+ className="Form-sc-1xszr8q-0 krRxky"
+ data-test="form"
+ onSubmit={[Function]}
+>
+ <DisplayError
+ error={Object {}}
+ />
+ <fieldset
+ aria-busy={false}
+ disabled={false}
+ >
+ <label
+ htmlFor="file"
+ >
+ Image
+ <input
+ id="file"
+ name="file"
+ onChange={[Function]}
+ placeholder="Upload an image"
+ required={true}
+ type="file"
+ />
+ </label>
+ <label
+ htmlFor="title"
+ >
+ Title
+ <input
+ id="title"
+ name="title"
+ onChange={[Function]}
+ placeholder="Title"
+ required={true}
+ type="text"
+ value=""
+ />
+ </label>
+ <label
+ htmlFor="price"
+ >
+ Price
+ <input
+ id="price"
+ name="price"
+ onChange={[Function]}
+ placeholder="Price"
+ required={true}
+ type="number"
+ value={0}
+ />
+ </label>
+ <label
+ htmlFor="description"
+ >
+ Description
+ <textarea
+ id="description"
+ name="description"
+ onChange={[Function]}
+ placeholder="Enter A Description"
+ required={true}
+ value=""
+ />
+ </label>
+ <button
+ type="submit"
+ >
+ Submit
+ </button>
+ </fieldset>
+</form>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/Item.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/Item.test.js.snap
new file mode 100644
index 0000000..70e4aa8
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/Item.test.js.snap
@@ -0,0 +1,58 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<Item/> renders and matches the snapshot 1`] = `
+<ItemStyles__Item>
+ <img
+ alt="A Cool Item"
+ src="dog.jpg"
+ />
+ <Title>
+ <Link
+ href={
+ Object {
+ "pathname": "/item",
+ "query": Object {
+ "id": "ABC123",
+ },
+ }
+ }
+ >
+ <a>
+ A Cool Item
+ </a>
+ </Link>
+ </Title>
+ <PriceTag>
+ $40
+ </PriceTag>
+ <p>
+ This item is really cool!
+ </p>
+ <div
+ className="buttonList"
+ >
+ <Link
+ href={
+ Object {
+ "pathname": "update",
+ "query": Object {
+ "id": "ABC123",
+ },
+ }
+ }
+ >
+ <a>
+ Edit ✏️
+ </a>
+ </Link>
+ <AddToCart
+ id="ABC123"
+ />
+ <DeleteItem
+ id="ABC123"
+ >
+ Delete This Item
+ </DeleteItem>
+ </div>
+</ItemStyles__Item>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/Nav.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/Nav.test.js.snap
new file mode 100644
index 0000000..c3155a9
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/Nav.test.js.snap
@@ -0,0 +1,37 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<Nav/> renders a minimal nav when signed out 1`] = `
+<ul
+ className="NavStyles-sc-11c0d2g-0 YVEeD"
+ data-test="nav"
+>
+ <Link
+ href="/items"
+ >
+ <a
+ href="/items"
+ onClick={[Function]}
+ >
+ Shop
+ </a>
+ </Link>
+ <Link
+ href="/signup"
+ >
+ <a
+ href="/signup"
+ onClick={[Function]}
+ >
+ Sign In
+ </a>
+ </Link>
+</ul>
+`;
+
+exports[`<Nav/> renders the amount of items in the cart 1`] = `
+<div
+ className="count CartCount__Dot-xxvp4g-1 fJsVOg"
+>
+ 9
+</div>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/Order.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/Order.test.js.snap
new file mode 100644
index 0000000..9dce80b
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/Order.test.js.snap
@@ -0,0 +1,118 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<Order/> renders the order 1`] = `
+<div
+ className="OrderStyles-sc-4oqalm-0 eDzsVm"
+ data-test="order"
+>
+ <SideEffect(Head)>
+ <Head />
+ </SideEffect(Head)>
+ <p>
+ <span>
+ Order ID:
+ </span>
+ <span>
+ ord123
+ </span>
+ </p>
+ <p>
+ <span>
+ Charge
+ </span>
+ <span>
+ ch_123
+ </span>
+ </p>
+ <p>
+ <span>
+ Date
+ </span>
+ <span>
+ March 31, 2018 8:00 PM
+ </span>
+ </p>
+ <p>
+ <span>
+ Order Total
+ </span>
+ <span>
+ $400
+ </span>
+ </p>
+ <p>
+ <span>
+ Item Count
+ </span>
+ <span>
+ 2
+ </span>
+ </p>
+ <div
+ className="items"
+ >
+ <div
+ className="order-item"
+ key="3a430a73-c9e9-4bcc-b46a-41618965ffea"
+ >
+ <img
+ alt="soluta non omnis consequatur enim quia autem"
+ src="reprehenderit.jpg"
+ />
+ <div
+ className="item-details"
+ >
+ <h2>
+ soluta non omnis consequatur enim quia autem
+ </h2>
+ <p>
+ Qty:
+ 1
+ </p>
+ <p>
+ Each:
+ $42.34
+ </p>
+ <p>
+ SubTotal:
+ $42.34
+ </p>
+ <p>
+ et modi tenetur amet modi reprehenderit omnis
+ </p>
+ </div>
+ </div>
+ <div
+ className="order-item"
+ key="2393e090-592f-4d03-b808-c9d81098deec"
+ >
+ <img
+ alt="quia sed exercitationem omnis laborum exercitationem est"
+ src="sint.jpg"
+ />
+ <div
+ className="item-details"
+ >
+ <h2>
+ quia sed exercitationem omnis laborum exercitationem est
+ </h2>
+ <p>
+ Qty:
+ 1
+ </p>
+ <p>
+ Each:
+ $42.34
+ </p>
+ <p>
+ SubTotal:
+ $42.34
+ </p>
+ <p>
+ sapiente laudantium molestias assumenda quasi adipisci mollitia
+ </p>
+ </div>
+ </div>
+ </div>
+</div>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/Pagination.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/Pagination.test.js.snap
new file mode 100644
index 0000000..110f59d
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/Pagination.test.js.snap
@@ -0,0 +1,67 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<Pagination/> renders pagination for 18 items 1`] = `
+<div
+ className="PaginationStyles-aduuar-0 ewJsCc"
+ data-test="pagination"
+>
+ <SideEffect(Head)>
+ <Head />
+ </SideEffect(Head)>
+ <Link
+ href={
+ Object {
+ "pathname": "items",
+ "query": Object {
+ "page": 0,
+ },
+ }
+ }
+ prefetch={true}
+ >
+ <a
+ aria-disabled={true}
+ className="prev"
+ href="items?page=0"
+ onClick={[Function]}
+ >
+ ← Prev
+ </a>
+ </Link>
+ <p>
+ Page
+ 1
+ of
+ <span
+ className="totalPages"
+ >
+ 5
+ </span>
+ !
+ </p>
+ <p>
+ 18
+ Items Total
+ </p>
+ <Link
+ href={
+ Object {
+ "pathname": "items",
+ "query": Object {
+ "page": 2,
+ },
+ }
+ }
+ prefetch={true}
+ >
+ <a
+ aria-disabled={false}
+ className="next"
+ href="items?page=2"
+ onClick={[Function]}
+ >
+ Next →
+ </a>
+ </Link>
+</div>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/RemoveFromCart.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/RemoveFromCart.test.js.snap
new file mode 100644
index 0000000..db8687b
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/RemoveFromCart.test.js.snap
@@ -0,0 +1,12 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<RemoveFromCart/> renders and matches snapshot 1`] = `
+<button
+ className="RemoveFromCart__BigButton-emvtd6-0 gPWNSn"
+ disabled={false}
+ onClick={[Function]}
+ title="Delete Item"
+>
+ ×
+</button>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/RequestReset.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/RequestReset.test.js.snap
new file mode 100644
index 0000000..c0de705
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/RequestReset.test.js.snap
@@ -0,0 +1,39 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<RequestReset/> renders and matches snapshot 1`] = `
+<form
+ className="Form-sc-1xszr8q-0 krRxky"
+ data-test="form"
+ method="post"
+ onSubmit={[Function]}
+>
+ <fieldset
+ aria-busy={false}
+ disabled={false}
+ >
+ <h2>
+ Request a password reset
+ </h2>
+ <DisplayError
+ error={Object {}}
+ />
+ <label
+ htmlFor="email"
+ >
+ Email
+ <input
+ name="email"
+ onChange={[Function]}
+ placeholder="email"
+ type="email"
+ value=""
+ />
+ </label>
+ <button
+ type="submit"
+ >
+ Request Reset!
+ </button>
+ </fieldset>
+</form>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/Signup.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/Signup.test.js.snap
new file mode 100644
index 0000000..bb61ff1
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/Signup.test.js.snap
@@ -0,0 +1,62 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<Signup/> renders and matches snapshot 1`] = `
+<form
+ className="Form-sc-1xszr8q-0 krRxky"
+ method="post"
+ onSubmit={[Function]}
+>
+ <fieldset
+ aria-busy={false}
+ disabled={false}
+ >
+ <h2>
+ Sign Up for An Account
+ </h2>
+ <DisplayError
+ error={Object {}}
+ />
+ <label
+ htmlFor="email"
+ >
+ Email
+ <input
+ name="email"
+ onChange={[Function]}
+ placeholder="email"
+ type="email"
+ value=""
+ />
+ </label>
+ <label
+ htmlFor="name"
+ >
+ Name
+ <input
+ name="name"
+ onChange={[Function]}
+ placeholder="name"
+ type="text"
+ value=""
+ />
+ </label>
+ <label
+ htmlFor="password"
+ >
+ Password
+ <input
+ name="password"
+ onChange={[Function]}
+ placeholder="password"
+ type="password"
+ value=""
+ />
+ </label>
+ <button
+ type="submit"
+ >
+ Sign Up!
+ </button>
+ </fieldset>
+</form>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/SingleItem.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/SingleItem.test.js.snap
new file mode 100644
index 0000000..2f41d4c
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/SingleItem.test.js.snap
@@ -0,0 +1,32 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<SingleItem/> Errors with a not found item 1`] = `
+<p
+ data-test="graphql-error"
+>
+ <strong>
+ Shoot!
+ </strong>
+ Items Not Found!
+</p>
+`;
+
+exports[`<SingleItem/> renders with proper data 1`] = `
+<h2>
+ Viewing
+ dogs are best
+</h2>
+`;
+
+exports[`<SingleItem/> renders with proper data 2`] = `
+<img
+ alt="dogs are best"
+ src="dog.jpg"
+/>
+`;
+
+exports[`<SingleItem/> renders with proper data 3`] = `
+<p>
+ dogs
+</p>
+`;
diff --git a/finished-application/frontend/__tests__/__snapshots__/TakeMyMoney.test.js.snap b/finished-application/frontend/__tests__/__snapshots__/TakeMyMoney.test.js.snap
new file mode 100644
index 0000000..02a112e
--- /dev/null
+++ b/finished-application/frontend/__tests__/__snapshots__/TakeMyMoney.test.js.snap
@@ -0,0 +1,67 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<TakeMyMoney/> renders and matches snapshot 1`] = `
+<ReactStripeCheckout
+ ComponentClass="span"
+ amount={15000}
+ className="StripeCheckout"
+ currency="USD"
+ description="Order of 3 items!"
+ email="Delmer.Smith@yahoo.com"
+ image="dog-small.jpg"
+ label="Pay With Card"
+ locale="auto"
+ name="Sick Fits"
+ reconfigureOnUpdate={false}
+ stripeKey="pk_test_Vtknn6vSdcZWSG2JWvEiWSqC"
+ token={[Function]}
+ triggerEvent="onClick"
+>
+ <button
+ className="StripeCheckout"
+ onBlur={[Function]}
+ onClick={[Function]}
+ onFocus={[Function]}
+ onMouseDown={[Function]}
+ onMouseOut={[Function]}
+ onMouseUp={[Function]}
+ style={
+ Object {
+ "background": "linear-gradient(#28a0e5,#015e94)",
+ "border": 0,
+ "borderRadius": 5,
+ "boxShadow": "0 1px 0 rgba(0,0,0,0.2)",
+ "cursor": "pointer",
+ "display": "inline-block",
+ "overflow": "hidden",
+ "padding": 1,
+ "textDecoration": "none",
+ "userSelect": "none",
+ "visibility": "visible",
+ }
+ }
+ >
+ <span
+ style={
+ Object {
+ "backgroundImage": "linear-gradient(#7dc5ee,#008cdd 85%,#30a2e4)",
+ "borderRadius": 4,
+ "boxShadow": "inset 0 1px 0 rgba(255,255,255,0.25)",
+ "color": "#fff",
+ "display": "block",
+ "fontFamily": "\\"Helvetica Neue\\",Helvetica,Arial,sans-serif",
+ "fontSize": 14,
+ "fontWeight": "bold",
+ "height": 30,
+ "lineHeight": "30px",
+ "padding": "0 12px",
+ "position": "relative",
+ "textShadow": "0 -1px 0 rgba(0,0,0,0.25)",
+ }
+ }
+ >
+ Pay With Card
+ </span>
+ </button>
+</ReactStripeCheckout>
+`;
diff --git a/finished-application/frontend/__tests__/formatMoney.test.js b/finished-application/frontend/__tests__/formatMoney.test.js
new file mode 100644
index 0000000..23d8183
--- /dev/null
+++ b/finished-application/frontend/__tests__/formatMoney.test.js
@@ -0,0 +1,23 @@
+import formatMoney from '../lib/formatMoney';
+
+describe('formatMoney Function', () => {
+ it('works with fractional dollars', () => {
+ expect(formatMoney(1)).toEqual('$0.01');
+ expect(formatMoney(10)).toEqual('$0.10');
+ expect(formatMoney(9)).toEqual('$0.09');
+ expect(formatMoney(40)).toEqual('$0.40');
+ });
+
+ it('leaves cents off for whole dollars', () => {
+ expect(formatMoney(5000)).toEqual('$50');
+ expect(formatMoney(100)).toEqual('$1');
+ expect(formatMoney(50000000)).toEqual('$500,000');
+ });
+
+ it('works with whole and fractional dollars', () => {
+ expect(formatMoney(5012)).toEqual('$50.12');
+ expect(formatMoney(101)).toEqual('$1.01');
+ expect(formatMoney(110)).toEqual('$1.10');
+ expect(formatMoney(20893749823749823749)).toEqual('$208,937,498,237,498,240.00');
+ });
+});
diff --git a/finished-application/frontend/__tests__/mocking.test.js b/finished-application/frontend/__tests__/mocking.test.js
new file mode 100644
index 0000000..d0a05bf
--- /dev/null
+++ b/finished-application/frontend/__tests__/mocking.test.js
@@ -0,0 +1,36 @@
+function Person(name, foods) {
+ this.name = name;
+ this.foods = foods;
+}
+
+Person.prototype.fetchFavFoods = function() {
+ return new Promise((resolve, reject) => {
+ // Simulate an API
+ setTimeout(() => resolve(this.foods), 2000);
+ });
+};
+
+describe('mocking learning', () => {
+ it('mocks a reg function', () => {
+ const fetchDogs = jest.fn();
+ fetchDogs('snickers');
+ expect(fetchDogs).toHaveBeenCalled();
+ expect(fetchDogs).toHaveBeenCalledWith('snickers');
+ fetchDogs('hugo');
+ expect(fetchDogs).toHaveBeenCalledTimes(2);
+ });
+
+ it('can create a person', () => {
+ const me = new Person('Wes', ['pizza', 'burgs']);
+ expect(me.name).toBe('Wes');
+ });
+
+ it('can fetch foods', async () => {
+ const me = new Person('Wes', ['pizza', 'burgs']);
+ // mock the favFoods function
+ me.fetchFavFoods = jest.fn().mockResolvedValue(['sushi', 'ramen']);
+ const favFoods = await me.fetchFavFoods();
+ console.log(favFoods);
+ expect(favFoods).toContain('sushi');
+ });
+});
diff --git a/finished-application/frontend/__tests__/sample.test.js b/finished-application/frontend/__tests__/sample.test.js
new file mode 100644
index 0000000..dbed94f
--- /dev/null
+++ b/finished-application/frontend/__tests__/sample.test.js
@@ -0,0 +1,19 @@
+describe('sample test 101', () => {
+ it('works as expected', () => {
+ const age = 100;
+ expect(1).toEqual(1);
+ expect(age).toEqual(100);
+ });
+
+ it('handles ranges just fine', () => {
+ const age = 200;
+ expect(age).toBeGreaterThan(100);
+ });
+
+ it('makes a list of dog names', () => {
+ const dogs = ['snickers', 'hugo'];
+ expect(dogs).toEqual(dogs);
+ expect(dogs).toContain('snickers');
+ expect(dogs).toContain('snickers');
+ });
+});