fix(orders): mark a demo order in the history rather than leaving it to read as real (#205) #209
@@ -38,7 +38,16 @@ const COLUMNS = [
|
|||||||
dataIndex: 'status',
|
dataIndex: 'status',
|
||||||
render: (v: string) => <Tag color={STATUS_COLORS[v]}>{v}</Tag>
|
render: (v: string) => <Tag color={STATUS_COLORS[v]}>{v}</Tag>
|
||||||
},
|
},
|
||||||
{ title: 'Processor', dataIndex: 'processor' },
|
{
|
||||||
|
title: 'Processor',
|
||||||
|
dataIndex: 'processor',
|
||||||
|
// `demo` used to render as a raw column value, which is not an explanation:
|
||||||
|
// a customer has no reason to read it as "this did not happen", and the row
|
||||||
|
// was otherwise identical to a real one — real price, `completed` status,
|
||||||
|
// same neutral tag. The cart says it is a demo (#195, #203) for about three
|
||||||
|
// seconds; this is the record they come back to. See #205.
|
||||||
|
render: (v: string) => (v === 'demo' ? <Tag color="warning">Demo (not charged)</Tag> : v)
|
||||||
|
},
|
||||||
{ title: 'Date', dataIndex: 'created_at', render: (v: string) => new Date(v).toLocaleDateString() }
|
{ title: 'Date', dataIndex: 'created_at', render: (v: string) => new Date(v).toLocaleDateString() }
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -69,6 +78,12 @@ function OrdersBody({ loading, error, orders, onRetry }: BodyProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shown only when there is one to explain. The per-row tag says which order,
|
||||||
|
// this says what it means — a tag reading "Demo" still assumes the reader
|
||||||
|
// knows what a demo order is, and the thing they actually want to know is
|
||||||
|
// whether to expect a parcel.
|
||||||
|
const hasDemoOrder = orders.some(o => o.processor === 'demo');
|
||||||
|
|
||||||
if (orders.length === 0) {
|
if (orders.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Space direction="vertical" align="center" style={{ width: '100%', marginTop: 24 }}>
|
<Space direction="vertical" align="center" style={{ width: '100%', marginTop: 24 }}>
|
||||||
@@ -79,6 +94,16 @@ function OrdersBody({ loading, error, orders, onRetry }: BodyProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{hasDemoOrder && (
|
||||||
|
<Alert
|
||||||
|
type="warning"
|
||||||
|
showIcon
|
||||||
|
style={{ marginBottom: 16 }}
|
||||||
|
message="Some of these are demo orders"
|
||||||
|
description="A demo order is a pretend one: nothing was charged, and nothing will be shipped."
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Table
|
<Table
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
dataSource={orders}
|
dataSource={orders}
|
||||||
@@ -88,6 +113,7 @@ function OrdersBody({ loading, error, orders, onRetry }: BodyProps) {
|
|||||||
scroll={{ x: 'max-content' }}
|
scroll={{ x: 'max-content' }}
|
||||||
columns={COLUMNS}
|
columns={COLUMNS}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,32 @@ test.describe('Demo mode says so to the customer', () => {
|
|||||||
await expect(cart.demoNotice).toBeVisible({ timeout: 20000 });
|
await expect(cart.demoNotice).toBeVisible({ timeout: 20000 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// The toast is three seconds; this is the record the customer comes back to
|
||||||
|
// when they wonder where their item is. It showed `demo` as a raw value under
|
||||||
|
// a "Processor" heading, beside a real price and a neutral `completed` tag —
|
||||||
|
// nothing a customer would read as "this did not happen". See #205.
|
||||||
|
test('order history marks the demo order rather than showing it as a real one', async ({
|
||||||
|
page,
|
||||||
|
customer,
|
||||||
|
cart,
|
||||||
|
orders
|
||||||
|
}) => {
|
||||||
|
const name = `Demo h${uniqueSuffix()}`;
|
||||||
|
const item = await createItem(page.request, { name, price: '80' });
|
||||||
|
expect((await page.request.post(`/api/cart/items/${item.id}`)).status()).toBe(201);
|
||||||
|
expect((await page.request.post('/api/customers/me/addresses', { data: ADDRESS })).ok()).toBe(true);
|
||||||
|
|
||||||
|
await cart.goto();
|
||||||
|
await expect(cart.checkoutButton).toBeVisible({ timeout: 20000 });
|
||||||
|
await cart.checkoutButton.click();
|
||||||
|
await expect(page.getByText(/nothing was charged/i)).toBeVisible({ timeout: 20000 });
|
||||||
|
|
||||||
|
await orders.goto();
|
||||||
|
|
||||||
|
await expect(orders.demoOrderMarker).toBeVisible({ timeout: 20000 });
|
||||||
|
await expect(orders.demoNotice).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
test('the confirmation says nothing was charged', async ({ page, customer, cart }) => {
|
test('the confirmation says nothing was charged', async ({ page, customer, cart }) => {
|
||||||
const name = `Demo p${uniqueSuffix()}`;
|
const name = `Demo p${uniqueSuffix()}`;
|
||||||
const item = await createItem(page.request, { name, price: '80' });
|
const item = await createItem(page.request, { name, price: '80' });
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export class OrdersPage {
|
|||||||
readonly continueShoppingButton: Locator;
|
readonly continueShoppingButton: Locator;
|
||||||
readonly backToShopButton: Locator;
|
readonly backToShopButton: Locator;
|
||||||
readonly anyDialog: Locator;
|
readonly anyDialog: Locator;
|
||||||
|
readonly demoNotice: Locator;
|
||||||
|
readonly demoOrderMarker: Locator;
|
||||||
|
|
||||||
constructor(private readonly page: Page) {
|
constructor(private readonly page: Page) {
|
||||||
this.heading = page.getByRole('heading', { name: 'Order History' });
|
this.heading = page.getByRole('heading', { name: 'Order History' });
|
||||||
@@ -21,6 +23,8 @@ export class OrdersPage {
|
|||||||
this.continueShoppingButton = page.getByRole('button', { name: 'Continue Shopping' });
|
this.continueShoppingButton = page.getByRole('button', { name: 'Continue Shopping' });
|
||||||
this.backToShopButton = page.getByRole('button', { name: 'Back to Shop' });
|
this.backToShopButton = page.getByRole('button', { name: 'Back to Shop' });
|
||||||
this.anyDialog = page.getByRole('dialog');
|
this.anyDialog = page.getByRole('dialog');
|
||||||
|
this.demoNotice = page.getByText('Some of these are demo orders');
|
||||||
|
this.demoOrderMarker = page.getByText('Demo (not charged)');
|
||||||
}
|
}
|
||||||
|
|
||||||
async goto(): Promise<void> {
|
async goto(): Promise<void> {
|
||||||
|
|||||||
Reference in New Issue
Block a user