-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheckout.spec.ts
More file actions
164 lines (132 loc) · 6.88 KB
/
checkout.spec.ts
File metadata and controls
164 lines (132 loc) · 6.88 KB
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
import { test, expect } from '@playwright/test';
test.describe('Checkout @destructive', () => {
// Cart is shared DB state — run serially to avoid race conditions
test.describe.configure({ mode: 'serial' });
const BASE = process.env.ENVIRONMENT_URL || '';
test.beforeEach(async ({ request }) => {
await request.delete(`${BASE}/api/cart`);
});
test('POST /api/checkout creates an order and decrements stock', async ({ request }) => {
// Get initial stock for record 1
const before = await (await request.get(`${BASE}/api/records/1`)).json();
// Add to cart and checkout
await request.post(`${BASE}/api/cart`, { data: { recordId: 1, quantity: 1 } });
const checkoutRes = await request.post(`${BASE}/api/checkout`, {
data: { name: 'Jane Doe', email: 'jane@example.com', address: '123 Vinyl Lane, Brooklyn, NY 11201' },
});
expect(checkoutRes.status()).toBe(201);
const order = await checkoutRes.json();
expect(order).toHaveProperty('orderId');
expect(order.items).toHaveLength(1);
expect(order.items[0].recordId).toBe(1);
expect(order.total).toBe(before.price);
// Verify stock decremented
const after = await (await request.get(`${BASE}/api/records/1`)).json();
expect(after.stock).toBe(before.stock - 1);
});
test('POST /api/checkout with empty cart returns 400', async ({ request }) => {
const res = await request.post(`${BASE}/api/checkout`, {
data: { name: 'Jane Doe', email: 'jane@example.com', address: '123 Vinyl Lane' },
});
expect(res.status()).toBe(400);
const body = await res.json();
expect(body.error).toBe('Cart is empty');
});
test('GET /api/orders/:id returns the created order', async ({ request }) => {
await request.post(`${BASE}/api/cart`, { data: { recordId: 3, quantity: 2 } });
const checkoutRes = await request.post(`${BASE}/api/checkout`, {
data: { name: 'Jane Doe', email: 'jane@example.com', address: '123 Vinyl Lane' },
});
const { orderId } = await checkoutRes.json();
const orderRes = await request.get(`${BASE}/api/orders/${orderId}`);
expect(orderRes.status()).toBe(200);
const order = await orderRes.json();
expect(order.id).toBe(orderId);
expect(order.status).toBe('confirmed');
expect(order.items).toHaveLength(1);
expect(order.items[0].quantity).toBe(2);
});
test('POST /api/checkout without customer details returns 400', async ({ request }) => {
await request.post(`${BASE}/api/cart`, { data: { recordId: 1, quantity: 1 } });
const res = await request.post(`${BASE}/api/checkout`, {
data: { name: 'Jane Doe' }, // missing email and address
});
expect(res.status()).toBe(400);
const body = await res.json();
expect(body.error).toContain('required');
});
test('POST /api/checkout with multiple items totals correctly', async ({ request }) => {
const rec1 = await (await request.get(`${BASE}/api/records/1`)).json();
const rec2 = await (await request.get(`${BASE}/api/records/2`)).json();
await request.post(`${BASE}/api/cart`, { data: { recordId: 1, quantity: 1 } });
await request.post(`${BASE}/api/cart`, { data: { recordId: 2, quantity: 3 } });
const checkoutRes = await request.post(`${BASE}/api/checkout`, {
data: { name: 'Jane Doe', email: 'jane@example.com', address: '123 Vinyl Lane' },
});
expect(checkoutRes.status()).toBe(201);
const order = await checkoutRes.json();
expect(order.items).toHaveLength(2);
const expectedTotal = Math.round((rec1.price + rec2.price * 3) * 100) / 100;
expect(order.total).toBe(expectedTotal);
});
test('order stores customer details', async ({ request }) => {
await request.post(`${BASE}/api/cart`, { data: { recordId: 1, quantity: 1 } });
const checkoutRes = await request.post(`${BASE}/api/checkout`, {
data: { name: 'Alex Rivera', email: 'alex@raccoonrecords.dev', address: '742 Evergreen Terrace' },
});
const { orderId } = await checkoutRes.json();
const orderRes = await request.get(`${BASE}/api/orders/${orderId}`);
const order = await orderRes.json();
expect(order.customer.name).toBe('Alex Rivera');
expect(order.customer.email).toBe('alex@raccoonrecords.dev');
expect(order.customer.address).toBe('742 Evergreen Terrace');
});
test('full checkout flow via UI', async ({ page }) => {
await page.goto(`${BASE}/`);
await expect(page.getByTestId('record-card').first()).toBeVisible();
// Add item to cart
await page.getByTestId('add-to-cart-1').click();
await expect(page.getByTestId('cart-badge')).toContainText('1');
// Open cart and click checkout
await page.getByTestId('cart-button').click();
await expect(page.getByTestId('cart-drawer')).toBeVisible();
await page.getByTestId('checkout-btn').click();
// Fill in customer details
await expect(page.getByTestId('checkout-form')).toBeVisible();
await page.getByTestId('checkout-name').fill('Jane Doe');
await page.getByTestId('checkout-email').fill('jane@example.com');
await page.getByTestId('checkout-address').fill('123 Vinyl Lane, Brooklyn, NY 11201');
await page.getByTestId('place-order-btn').click();
// Verify confirmation appears
await expect(page.getByTestId('checkout-confirmation')).toBeVisible({ timeout: 5000 });
await expect(page.getByTestId('checkout-confirmation')).toContainText('Order');
});
test('checkout form shows total and back button returns to cart', async ({ page }) => {
await page.goto(`${BASE}/`);
await expect(page.getByTestId('record-card').first()).toBeVisible();
await page.getByTestId('add-to-cart-1').click();
await expect(page.getByTestId('cart-badge')).toContainText('1');
await page.getByTestId('cart-button').click();
await page.getByTestId('checkout-btn').click();
// Form shows total
await expect(page.getByTestId('checkout-form')).toBeVisible();
await expect(page.getByTestId('checkout-form-total')).toContainText('$');
// Back button returns to cart items
await page.getByTestId('checkout-back-btn').click();
await expect(page.getByTestId('checkout-form')).not.toBeVisible();
await expect(page.getByTestId('cart-items')).toBeVisible();
});
test('submitting checkout form with empty fields shows validation toast', async ({ page }) => {
await page.goto(`${BASE}/`);
await expect(page.getByTestId('record-card').first()).toBeVisible();
await page.getByTestId('add-to-cart-1').click();
await page.getByTestId('cart-button').click();
await page.getByTestId('checkout-btn').click();
// Try to place order without filling fields
await expect(page.getByTestId('checkout-form')).toBeVisible();
await page.getByTestId('place-order-btn').click();
// Should show validation toast, not confirmation
await expect(page.getByTestId('toast')).toContainText('fill in all fields');
await expect(page.getByTestId('checkout-confirmation')).not.toBeVisible();
});
});