-
Notifications
You must be signed in to change notification settings - Fork 36
/
CartView.test.tsx
193 lines (160 loc) · 5.89 KB
/
CartView.test.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import React from 'react';
import { rest } from 'msw';
import { Route, Routes } from 'react-router-dom';
import { MOCK_API_URL } from '../../../mocks/constants';
import { server } from '../../../mocks/server';
import { CartUtils } from '../../../models';
import {
render,
screen,
userEvent,
waitFor,
waitForElementToBeRemoved,
} from '../../../test/test-utils';
import { CartView } from './CartView';
const START_ORDER = 'Please click on a product to start your order.';
const cart = {
items: [
{
productId: 'apple-imac',
productName: 'iMac',
price: 1299,
quantity: 1,
},
{
productId: 'apple-macbook-pro',
productName: 'MacBook Pro',
price: 699,
quantity: 1,
},
],
};
const MockCheckoutPage = () => {
return <h1>Checkout Page</h1>;
};
describe('<CartView />', () => {
test('renders correctly with no order items', async () => {
render(<CartView />);
// start order message should exist
const startOrderMessage = await screen.findByText(START_ORDER);
expect(startOrderMessage).toBeInTheDocument();
// checkout button should not exist
const checkoutButton = screen.queryByText('Checkout');
expect(checkoutButton).toBeNull();
});
test('renders correctly with one or more order items', async () => {
// simulate 2 items in the cart
server.use(
rest.get(`${MOCK_API_URL}/cart`, (req, res, ctx) => {
return res(ctx.status(200), ctx.json(cart));
})
);
render(<CartView />);
// checkout button should exist
const checkoutButton = await screen.findByText('Checkout');
expect(checkoutButton).not.toBeNull();
// start order message should not exist
const startOrderMessage = screen.queryByText(START_ORDER);
expect(startOrderMessage).toBeNull();
// 2 order items should exist
const orderItemTable = await screen.findByTestId('order-items');
const orderItems = orderItemTable.querySelectorAll('tbody tr');
expect(orderItems.length).toBe(2);
});
test('renders an error if fetching of the cart fails', async () => {
// simulate an error when fetching the cart
server.use(
rest.get(`${MOCK_API_URL}/cart`, (req, res, ctx) => {
return res(ctx.status(404));
})
);
// Suppress console errors
jest.spyOn(console, 'error').mockImplementation(() => {});
render(<CartView />);
const errorMessage = await screen.findByText(/404/);
expect(errorMessage).toBeInTheDocument();
jest.restoreAllMocks();
});
test('clicking on delete button deletes the item from the order', async () => {
// simulate 2 items in the cart
server.use(
rest.get(`${MOCK_API_URL}/cart`, (req, res, ctx) => {
return res(ctx.status(200), ctx.json(cart));
})
);
// simulate delete from 2 items in the cart
server.use(
rest.delete(`${MOCK_API_URL}/cart/items/:productId`, (req, res, ctx) => {
const { productId } = req.params;
const newCart = CartUtils.deleteItem(cart, productId);
return res(ctx.status(200), ctx.json(newCart));
})
);
render(<CartView />);
// wait for Checkout button to render
await screen.findByText('Checkout');
// delete the first item from the order
const deleteButtons = await screen.findAllByTestId('delete-button');
expect(deleteButtons.length).toBe(2);
userEvent.click(deleteButtons[0]);
// wait for 'iMac' to disappear
await waitForElementToBeRemoved(() => screen.getByText('iMac'));
// only 1 item should remain
const orderItemTable = await screen.findByTestId('order-items');
expect(orderItemTable.querySelectorAll('tbody tr').length).toBe(1);
// the remaining item should be 'MacBook Pro'
const macbookPro = screen.getByText('MacBook Pro');
expect(macbookPro).toBeInTheDocument();
});
test('item quantity can be changed by typing into the quantity field', async () => {
// simulate 2 items in the cart
server.use(
rest.get(`${MOCK_API_URL}/cart`, (req, res, ctx) => {
return res(ctx.status(200), ctx.json(cart));
})
);
// simulate set item quantity
server.use(
rest.patch(`${MOCK_API_URL}/cart/items/:productId`, (req, res, ctx) => {
const { productId } = req.params;
const { quantity } = req.body as any;
const newCart = CartUtils.setItemQuantity(cart, productId, quantity);
return res(ctx.status(200), ctx.json(newCart));
})
);
render(<CartView />);
// wait for 2 items to render
const quantityInputs = await screen.findAllByTestId('quantity-input');
expect(quantityInputs).toHaveLength(2);
// change iMac quantity to 2
// Note the use of {selectall} - without this 2 will be simply
// appended to the existing quantity, resulting in 12.
userEvent.type(quantityInputs[0], '{selectall}2');
// wait for price of iMac line item to change
const priceCells = screen.getAllByTestId('price-cell');
await waitFor(() => expect(priceCells[0].textContent).toBe('2,598.00'));
});
// Note: Applications should probably not check that navigation works,
// because React Router has lots of tests to assure us that it works!
// However, if you must, here's how to.
test('clicking on checkout button navigates to Checkout page', async () => {
// simulate 2 items in the cart
server.use(
rest.get(`${MOCK_API_URL}/cart`, (req, res, ctx) => {
return res(ctx.status(200), ctx.json(cart));
})
);
render(
<Routes>
<Route path="/" element={<CartView />} />
<Route path="/checkout" element={<MockCheckoutPage />} />
</Routes>
);
// click on Checkout button
const checkoutButton = await screen.findByText('Checkout');
userEvent.click(checkoutButton);
// expect checkout page to be rendered
const checkoutPageTitle = await screen.findByText('Checkout Page');
expect(checkoutPageTitle).toBeInTheDocument();
});
});