@faststore/core 4.8.1-dev.0 → 4.8.1-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-generate.log +3 -3
- package/.turbo/turbo-test.log +152 -114
- package/CHANGELOG.md +10 -0
- package/cms/faststore/my-account/components/cms_component__accountnavigation.jsonc +10 -0
- package/cms/faststore/my-account/components/cms_component__accountorderdelivery.jsonc +80 -0
- package/cms/faststore/my-account/components/cms_component__accountorderdetails.jsonc +25 -0
- package/cms/faststore/my-account/components/cms_component__accountorderslist.jsonc +10 -0
- package/cms/faststore/my-account/components/cms_component__accountorderstatus.jsonc +90 -0
- package/cms/faststore/my-account/components/cms_component__accountordersummary.jsonc +25 -0
- package/package.json +6 -6
- package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawerFooter.tsx +13 -2
- package/src/components/account/orders/ListOrders/FilterSlider/FilterFacetPendingApproval/FilterFacetPendingApproval.tsx +8 -3
- package/src/components/account/orders/ListOrders/FilterSlider/FilterSlider.tsx +1 -0
- package/src/components/account/orders/ListOrders/ListOrders.tsx +2 -2
- package/src/components/account/orders/ListOrders/listOrdersLabels.ts +4 -0
- package/src/components/account/orders/OrderDetails/BuyingPolicyAlert/BuyingPolicyAlert.tsx +45 -9
- package/src/components/account/orders/OrderDetails/DeliveryCard/DeliveryCard.tsx +14 -3
- package/src/components/account/orders/OrderDetails/DeliveryOptionAccordion/DeliveryOptionAccordion.tsx +4 -1
- package/src/components/account/orders/OrderDetails/DeliveryOptionAccordion/DeliveryOptionAccordionDeliveryInfo.tsx +14 -7
- package/src/components/account/orders/OrderDetails/DeliveryOptionAccordion/DeliveryOptionAccordionProducts.tsx +8 -5
- package/src/components/account/orders/OrderDetails/OrderDetailsHeader.tsx +5 -0
- package/src/components/account/orders/OrderDetails/StatusCard/StatusCard.tsx +26 -89
- package/src/components/account/orders/OrderDetails/StatusCard/statusCardLocalization.ts +114 -0
- package/src/components/account/orders/OrderDetails/SummaryCard/SummaryCard.tsx +2 -1
- package/src/components/account/orders/OrderDetails/SummaryCard/getOrderTotalLabel.ts +19 -0
- package/src/components/account/orders/OrderDetails/getDeliveryOptionLabel.ts +135 -0
- package/src/components/account/orders/OrderDetails/orderDetailsLabels.ts +73 -0
- package/src/components/sections/Account/AccountOrderDelivery.tsx +3 -1
- package/src/components/sections/Account/AccountOrderDetails.tsx +16 -0
- package/src/components/sections/Account/AccountOrderStatus.tsx +27 -3
- package/src/components/sections/Account/AccountOrdersList.tsx +4 -0
- package/src/pages/api/graphql.ts +108 -69
- package/src/sdk/account/accountPageContext.ts +14 -3
- package/src/sdk/account/getMyAccountRoutes.ts +2 -0
- package/src/sdk/overrides/PageProvider.tsx +1 -1
- package/test/components/account/OrganizationDrawerFooter.browser.test.tsx +95 -1
- package/test/components/account/orders/BuyingPolicyAlert.browser.test.tsx +342 -0
- package/test/components/account/orders/DeliveryCard.browser.test.tsx +36 -0
- package/test/components/account/orders/DeliveryOptionAccordion.browser.test.tsx +76 -0
- package/test/components/account/orders/DeliveryOptionAccordionDeliveryInfo.browser.test.tsx +41 -0
- package/test/components/account/orders/DeliveryOptionAccordionProducts.browser.test.tsx +35 -0
- package/test/components/account/orders/FilterFacetPendingApproval.browser.test.tsx +25 -0
- package/test/components/account/orders/StatusCard.browser.test.tsx +37 -0
- package/test/components/account/orders/StatusCard.test.ts +101 -0
- package/test/components/account/orders/SummaryCard.browser.test.tsx +59 -0
- package/test/components/account/orders/getDeliveryOptionLabel.test.ts +129 -0
- package/test/components/account/orders/getOrderTotalLabel.test.ts +35 -0
- package/test/components/account/orders/listOrdersLabels.test.ts +23 -0
- package/test/components/account/orders/orderDetailsLabels.test.ts +13 -0
- package/test/components/sections/Account/AccountOrderDelivery.browser.test.tsx +72 -0
- package/test/components/sections/Account/AccountOrderDetails.browser.test.tsx +151 -0
- package/test/components/sections/Account/AccountOrderStatus.browser.test.tsx +59 -0
- package/test/components/sections/Account/AccountOrdersList.browser.test.tsx +67 -0
- package/test/pages/api/graphql.test.ts +27 -1
- package/test/sdk/account/getMyAccountRoutes.test.ts +11 -1
- package/test/utils/userOrderStatus.test.ts +22 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { render, screen } from '@testing-library/react'
|
|
6
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
7
|
+
|
|
8
|
+
import SummaryCard from '../../../../src/components/account/orders/OrderDetails/SummaryCard'
|
|
9
|
+
|
|
10
|
+
vi.mock('next/router', () => ({
|
|
11
|
+
useRouter: () => ({ locale: 'en-US' }),
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
describe('SummaryCard', () => {
|
|
15
|
+
it('renders localized totals, interest, and the final total', () => {
|
|
16
|
+
render(
|
|
17
|
+
<SummaryCard
|
|
18
|
+
totals={[
|
|
19
|
+
{ id: 'Items', name: 'Items from OMS', value: 1_000 },
|
|
20
|
+
{ id: 'FutureTotal', name: 'Future total from OMS', value: 100 },
|
|
21
|
+
]}
|
|
22
|
+
currencyCode="USD"
|
|
23
|
+
transactions={[
|
|
24
|
+
{
|
|
25
|
+
isActive: true,
|
|
26
|
+
payments: [{ value: 1_200, referenceValue: 1_100 }],
|
|
27
|
+
},
|
|
28
|
+
]}
|
|
29
|
+
labels={{
|
|
30
|
+
itemsTotalLabel: 'Products',
|
|
31
|
+
interestLabel: 'Financing',
|
|
32
|
+
totalLabel: 'Grand total',
|
|
33
|
+
}}
|
|
34
|
+
/>
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
expect(screen.getByText('Products')).toBeTruthy()
|
|
38
|
+
expect(screen.getByText('Future total from OMS')).toBeTruthy()
|
|
39
|
+
expect(screen.getByText('Financing')).toBeTruthy()
|
|
40
|
+
expect(screen.getByText('Grand total')).toBeTruthy()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('does not add interest for inactive transactions', () => {
|
|
44
|
+
render(
|
|
45
|
+
<SummaryCard
|
|
46
|
+
totals={[{ id: 'Items', name: 'Items from OMS', value: 1_000 }]}
|
|
47
|
+
currencyCode="USD"
|
|
48
|
+
transactions={[
|
|
49
|
+
{
|
|
50
|
+
isActive: false,
|
|
51
|
+
payments: [{ value: 1_200, referenceValue: 1_000 }],
|
|
52
|
+
},
|
|
53
|
+
]}
|
|
54
|
+
/>
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
expect(screen.queryByText('Interest')).toBeNull()
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getDeliveryOptionKey,
|
|
5
|
+
getDeliveryOptionLabel,
|
|
6
|
+
} from '../../../../src/components/account/orders/OrderDetails/getDeliveryOptionLabel'
|
|
7
|
+
import { resolveOrderDeliveryLabels } from '../../../../src/components/account/orders/OrderDetails/orderDetailsLabels'
|
|
8
|
+
|
|
9
|
+
const labels = resolveOrderDeliveryLabels({
|
|
10
|
+
deliveryChannelLabel: 'Entrega',
|
|
11
|
+
pickupChannelLabel: 'Retirada',
|
|
12
|
+
takeAwayChannelLabel: 'Levar',
|
|
13
|
+
businessDaysZeroTemplate: 'bd-0',
|
|
14
|
+
businessDaysOneTemplate: 'bd-1',
|
|
15
|
+
businessDaysOtherTemplate: 'bd-{count}',
|
|
16
|
+
daysZeroTemplate: 'd-0',
|
|
17
|
+
daysOneTemplate: 'd-1',
|
|
18
|
+
daysOtherTemplate: 'd-{count}',
|
|
19
|
+
hoursZeroTemplate: 'h-0',
|
|
20
|
+
hoursOneTemplate: 'h-1',
|
|
21
|
+
hoursOtherTemplate: 'h-{count}',
|
|
22
|
+
minutesZeroTemplate: 'm-0',
|
|
23
|
+
minutesOneTemplate: 'm-1',
|
|
24
|
+
minutesOtherTemplate: 'm-{count}',
|
|
25
|
+
toNeighborhoodTemplate: 'para {neighborhood}',
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('getDeliveryOptionLabel', () => {
|
|
29
|
+
it.each([
|
|
30
|
+
['0bd', 'bd-0'],
|
|
31
|
+
['1bd', 'bd-1'],
|
|
32
|
+
['5bd', 'bd-5'],
|
|
33
|
+
['0d', 'd-0'],
|
|
34
|
+
['1d', 'd-1'],
|
|
35
|
+
['5d', 'd-5'],
|
|
36
|
+
['0h', 'h-0'],
|
|
37
|
+
['1h', 'h-1'],
|
|
38
|
+
['5h', 'h-5'],
|
|
39
|
+
['0m', 'm-0'],
|
|
40
|
+
['1m', 'm-1'],
|
|
41
|
+
['5m', 'm-5'],
|
|
42
|
+
])('localizes shipping estimate %s', (shippingEstimate, expected) => {
|
|
43
|
+
expect(
|
|
44
|
+
getDeliveryOptionLabel({ deliveryChannel: '', shippingEstimate }, labels)
|
|
45
|
+
).toBe(expected)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it.each([
|
|
49
|
+
['delivery', 'Entrega'],
|
|
50
|
+
['pickup', 'Retirada'],
|
|
51
|
+
['pickup-in-point', 'Retirada'],
|
|
52
|
+
['take-away', 'Levar'],
|
|
53
|
+
])('localizes the %s channel', (deliveryChannel, expected) => {
|
|
54
|
+
expect(
|
|
55
|
+
getDeliveryOptionLabel(
|
|
56
|
+
{ deliveryChannel, shippingEstimate: '1d' },
|
|
57
|
+
labels
|
|
58
|
+
)
|
|
59
|
+
).toBe(`${expected} d-1`)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('localizes the neighborhood connector while preserving its value', () => {
|
|
63
|
+
expect(
|
|
64
|
+
getDeliveryOptionLabel(
|
|
65
|
+
{
|
|
66
|
+
deliveryChannel: 'delivery',
|
|
67
|
+
shippingEstimate: '5bd',
|
|
68
|
+
address: { neighborhood: 'Botafogo' },
|
|
69
|
+
},
|
|
70
|
+
labels
|
|
71
|
+
)
|
|
72
|
+
).toBe('Entrega bd-5 para Botafogo')
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('treats padded one-unit estimates the same way as the API parser', () => {
|
|
76
|
+
expect(
|
|
77
|
+
getDeliveryOptionLabel(
|
|
78
|
+
{ deliveryChannel: '', shippingEstimate: '01bd' },
|
|
79
|
+
labels
|
|
80
|
+
)
|
|
81
|
+
).toBe('bd-1')
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('builds a stable key from the same grouping fields as the API', () => {
|
|
85
|
+
expect(
|
|
86
|
+
getDeliveryOptionKey({
|
|
87
|
+
selectedSla: 'Normal',
|
|
88
|
+
deliveryChannel: 'delivery',
|
|
89
|
+
deliveryCompany: 'Correios',
|
|
90
|
+
seller: '1',
|
|
91
|
+
shippingEstimate: '5bd',
|
|
92
|
+
shippingEstimateDate: '2026-08-05T00:00:00Z',
|
|
93
|
+
address: { addressId: 'addr-1' },
|
|
94
|
+
deliveryWindow: {
|
|
95
|
+
startDateUtc: '2026-08-05T10:00:00Z',
|
|
96
|
+
endDateUtc: '2026-08-05T18:00:00Z',
|
|
97
|
+
},
|
|
98
|
+
})
|
|
99
|
+
).toBe(
|
|
100
|
+
'Normal|delivery|Correios|1|5bd|2026-08-05T00:00:00Z|addr-1|2026-08-05T10:00:00Z|2026-08-05T18:00:00Z'
|
|
101
|
+
)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('keeps a recognized channel localized when the estimate is unavailable', () => {
|
|
105
|
+
expect(
|
|
106
|
+
getDeliveryOptionLabel(
|
|
107
|
+
{
|
|
108
|
+
deliveryChannel: 'delivery',
|
|
109
|
+
shippingEstimate: 'someday',
|
|
110
|
+
friendlyDeliveryOptionName: 'Delivery someday',
|
|
111
|
+
},
|
|
112
|
+
labels
|
|
113
|
+
)
|
|
114
|
+
).toBe('Entrega')
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('preserves the API fallback for unsupported raw values', () => {
|
|
118
|
+
expect(
|
|
119
|
+
getDeliveryOptionLabel(
|
|
120
|
+
{
|
|
121
|
+
deliveryChannel: 'future-channel',
|
|
122
|
+
shippingEstimate: 'someday',
|
|
123
|
+
friendlyDeliveryOptionName: 'Existing API label',
|
|
124
|
+
},
|
|
125
|
+
labels
|
|
126
|
+
)
|
|
127
|
+
).toBe('Existing API label')
|
|
128
|
+
})
|
|
129
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { getOrderTotalLabel } from '../../../../src/components/account/orders/OrderDetails/SummaryCard/getOrderTotalLabel'
|
|
4
|
+
import { resolveOrderSummaryLabels } from '../../../../src/components/account/orders/OrderDetails/orderDetailsLabels'
|
|
5
|
+
|
|
6
|
+
const labels = resolveOrderSummaryLabels({
|
|
7
|
+
itemsTotalLabel: 'Produtos',
|
|
8
|
+
discountsTotalLabel: 'Descontos',
|
|
9
|
+
shippingTotalLabel: 'Frete',
|
|
10
|
+
taxTotalLabel: 'Impostos',
|
|
11
|
+
changeTotalLabel: 'Alterações',
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
describe('getOrderTotalLabel', () => {
|
|
15
|
+
it.each([
|
|
16
|
+
['Items', 'Produtos'],
|
|
17
|
+
['Discounts', 'Descontos'],
|
|
18
|
+
['Shipping', 'Frete'],
|
|
19
|
+
['Tax', 'Impostos'],
|
|
20
|
+
['Change', 'Alterações'],
|
|
21
|
+
])('localizes the documented OMS %s total', (id, expected) => {
|
|
22
|
+
expect(getOrderTotalLabel({ id, name: `${id} from OMS` }, labels)).toBe(
|
|
23
|
+
expected
|
|
24
|
+
)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('falls back to the OMS name for an unknown total id', () => {
|
|
28
|
+
expect(
|
|
29
|
+
getOrderTotalLabel(
|
|
30
|
+
{ id: 'FutureTotal', name: 'Future total from OMS' },
|
|
31
|
+
labels
|
|
32
|
+
)
|
|
33
|
+
).toBe('Future total from OMS')
|
|
34
|
+
})
|
|
35
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
defaultListOrdersLabels,
|
|
5
|
+
resolveListOrdersLabels,
|
|
6
|
+
} from '../../../../src/components/account/orders/ListOrders/listOrdersLabels'
|
|
7
|
+
|
|
8
|
+
describe('list orders labels', () => {
|
|
9
|
+
it('provides English defaults for filter group labels', () => {
|
|
10
|
+
expect(defaultListOrdersLabels.statusFilterLabel).toBe('Status')
|
|
11
|
+
expect(defaultListOrdersLabels.orderDateFilterLabel).toBe('Order Date')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('resolves localized filter group labels', () => {
|
|
15
|
+
const labels = resolveListOrdersLabels({
|
|
16
|
+
statusFilterLabel: 'Situação',
|
|
17
|
+
orderDateFilterLabel: 'Data do pedido',
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
expect(labels.statusFilterLabel).toBe('Situação')
|
|
21
|
+
expect(labels.orderDateFilterLabel).toBe('Data do pedido')
|
|
22
|
+
})
|
|
23
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
defaultOrderDeliveryLabels,
|
|
5
|
+
resolveOrderDeliveryLabels,
|
|
6
|
+
} from '../../../../src/components/account/orders/OrderDetails/orderDetailsLabels'
|
|
7
|
+
|
|
8
|
+
describe('order details labels', () => {
|
|
9
|
+
it('uses English delivery labels by default', () => {
|
|
10
|
+
expect(resolveOrderDeliveryLabels()).toEqual(defaultOrderDeliveryLabels)
|
|
11
|
+
expect(defaultOrderDeliveryLabels.eachLabel).toBe('Each')
|
|
12
|
+
})
|
|
13
|
+
})
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest'
|
|
2
|
+
import { cleanup, render, screen } from '@testing-library/react'
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
+
|
|
5
|
+
const mockUseAccountPageData = vi.hoisted(() => vi.fn())
|
|
6
|
+
|
|
7
|
+
vi.mock('next/router', () => ({ useRouter: () => ({ locale: 'pt-BR' }) }))
|
|
8
|
+
vi.mock('src/sdk/account/accountPageContext', () => ({
|
|
9
|
+
useAccountPageData: mockUseAccountPageData,
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
import AccountOrderDelivery from 'src/components/sections/Account/AccountOrderDelivery'
|
|
13
|
+
|
|
14
|
+
const order = {
|
|
15
|
+
storePreferencesData: { currencyCode: 'BRL' },
|
|
16
|
+
customFields: [],
|
|
17
|
+
deliveryOptionsData: {
|
|
18
|
+
contact: { name: 'Maria' },
|
|
19
|
+
deliveryOptions: [
|
|
20
|
+
{
|
|
21
|
+
selectedSla: 'Normal',
|
|
22
|
+
deliveryChannel: 'delivery',
|
|
23
|
+
shippingEstimate: '2bd',
|
|
24
|
+
friendlyDeliveryOptionName: 'Delivery Up to 2 business days',
|
|
25
|
+
quantityOfDifferentItems: 1,
|
|
26
|
+
total: 1100,
|
|
27
|
+
items: [],
|
|
28
|
+
address: {
|
|
29
|
+
city: 'Rio de Janeiro',
|
|
30
|
+
street: 'Rua Um',
|
|
31
|
+
postalCode: '20000-000',
|
|
32
|
+
state: 'RJ',
|
|
33
|
+
country: 'BRA',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
afterEach(() => {
|
|
41
|
+
cleanup()
|
|
42
|
+
mockUseAccountPageData.mockReset()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('AccountOrderDelivery', () => {
|
|
46
|
+
it('forwards the CMS labels to the delivery card and accordions', () => {
|
|
47
|
+
mockUseAccountPageData.mockReturnValue({ order })
|
|
48
|
+
|
|
49
|
+
render(
|
|
50
|
+
<AccountOrderDelivery
|
|
51
|
+
deliveryTitle="Entrega do pedido"
|
|
52
|
+
deliveryChannelLabel="Entrega"
|
|
53
|
+
businessDaysOtherTemplate="Em até {count} dias úteis"
|
|
54
|
+
recipientLabel="Destinatário"
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
expect(screen.getByText('Entrega do pedido')).toBeInTheDocument()
|
|
59
|
+
expect(screen.getAllByText('Entrega Em até 2 dias úteis')).toHaveLength(2)
|
|
60
|
+
expect(screen.getByText('Destinatário')).toBeInTheDocument()
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('renders nothing when the order has no delivery data', () => {
|
|
64
|
+
mockUseAccountPageData.mockReturnValue({
|
|
65
|
+
order: { ...order, deliveryOptionsData: null },
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const { container } = render(<AccountOrderDelivery />)
|
|
69
|
+
|
|
70
|
+
expect(container).toBeEmptyDOMElement()
|
|
71
|
+
})
|
|
72
|
+
})
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import '@testing-library/jest-dom/vitest'
|
|
6
|
+
import { cleanup, render, screen } from '@testing-library/react'
|
|
7
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
8
|
+
|
|
9
|
+
const mockUseAccountPageData = vi.hoisted(() => vi.fn())
|
|
10
|
+
|
|
11
|
+
vi.mock('src/sdk/account/accountPageContext', () => ({
|
|
12
|
+
useAccountPageData: mockUseAccountPageData,
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
vi.mock(
|
|
16
|
+
'src/components/account/orders/OrderDetails/OrderDetailsHeader',
|
|
17
|
+
() => ({
|
|
18
|
+
OrderDetailsHeader: ({
|
|
19
|
+
labels,
|
|
20
|
+
}: {
|
|
21
|
+
labels: Record<string, string | undefined>
|
|
22
|
+
}) => (
|
|
23
|
+
<div data-testid="order-details-header">
|
|
24
|
+
<span data-testid="reject-modal-title">{labels.rejectModalTitle}</span>
|
|
25
|
+
<span data-testid="reject-modal-message">
|
|
26
|
+
{labels.rejectModalMessage}
|
|
27
|
+
</span>
|
|
28
|
+
<span data-testid="reject-modal-confirm">
|
|
29
|
+
{labels.rejectModalConfirmText}
|
|
30
|
+
</span>
|
|
31
|
+
<span data-testid="approve-success-toast">
|
|
32
|
+
{labels.approveSuccessToast}
|
|
33
|
+
</span>
|
|
34
|
+
<span data-testid="approve-error-toast">
|
|
35
|
+
{labels.approveErrorToast}
|
|
36
|
+
</span>
|
|
37
|
+
<span data-testid="reject-success-toast">
|
|
38
|
+
{labels.rejectSuccessToast}
|
|
39
|
+
</span>
|
|
40
|
+
<span data-testid="reject-error-toast">{labels.rejectErrorToast}</span>
|
|
41
|
+
<span data-testid="pending-further-approvals-alert">
|
|
42
|
+
{labels.pendingFurtherApprovalsAlert}
|
|
43
|
+
</span>
|
|
44
|
+
</div>
|
|
45
|
+
),
|
|
46
|
+
})
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
import AccountOrderDetails from 'src/components/sections/Account/AccountOrderDetails'
|
|
50
|
+
import { defaultOrderDetailsHeaderLabels } from 'src/components/account/orders/OrderDetails/orderDetailsLabels'
|
|
51
|
+
|
|
52
|
+
const order = { orderId: '123' }
|
|
53
|
+
|
|
54
|
+
afterEach(cleanup)
|
|
55
|
+
|
|
56
|
+
describe('AccountOrderDetails', () => {
|
|
57
|
+
it('forwards the default English reject modal labels when the CMS has no override', () => {
|
|
58
|
+
mockUseAccountPageData.mockReturnValueOnce({ order })
|
|
59
|
+
|
|
60
|
+
render(<AccountOrderDetails />)
|
|
61
|
+
|
|
62
|
+
expect(screen.getByTestId('reject-modal-title')).toHaveTextContent(
|
|
63
|
+
defaultOrderDetailsHeaderLabels.rejectModalTitle
|
|
64
|
+
)
|
|
65
|
+
expect(screen.getByTestId('reject-modal-message').textContent).toBe(
|
|
66
|
+
defaultOrderDetailsHeaderLabels.rejectModalMessage
|
|
67
|
+
)
|
|
68
|
+
expect(screen.getByTestId('reject-modal-confirm')).toHaveTextContent(
|
|
69
|
+
defaultOrderDetailsHeaderLabels.rejectModalConfirmText
|
|
70
|
+
)
|
|
71
|
+
expect(screen.getByTestId('approve-success-toast')).toHaveTextContent(
|
|
72
|
+
defaultOrderDetailsHeaderLabels.approveSuccessToast
|
|
73
|
+
)
|
|
74
|
+
expect(screen.getByTestId('approve-error-toast')).toHaveTextContent(
|
|
75
|
+
defaultOrderDetailsHeaderLabels.approveErrorToast
|
|
76
|
+
)
|
|
77
|
+
expect(screen.getByTestId('reject-success-toast')).toHaveTextContent(
|
|
78
|
+
defaultOrderDetailsHeaderLabels.rejectSuccessToast
|
|
79
|
+
)
|
|
80
|
+
expect(screen.getByTestId('reject-error-toast')).toHaveTextContent(
|
|
81
|
+
defaultOrderDetailsHeaderLabels.rejectErrorToast
|
|
82
|
+
)
|
|
83
|
+
expect(
|
|
84
|
+
screen.getByTestId('pending-further-approvals-alert')
|
|
85
|
+
).toHaveTextContent(
|
|
86
|
+
defaultOrderDetailsHeaderLabels.pendingFurtherApprovalsAlert
|
|
87
|
+
)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('forwards CMS-provided reject modal labels to the order details header', () => {
|
|
91
|
+
mockUseAccountPageData.mockReturnValueOnce({ order })
|
|
92
|
+
|
|
93
|
+
render(
|
|
94
|
+
<AccountOrderDetails
|
|
95
|
+
rejectModalTitle="Rejeitar solicitação de aprovação"
|
|
96
|
+
rejectModalMessage="Você está rejeitando a política {policy}."
|
|
97
|
+
rejectModalConfirmText="Confirmar rejeição"
|
|
98
|
+
/>
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
expect(screen.getByTestId('reject-modal-title')).toHaveTextContent(
|
|
102
|
+
'Rejeitar solicitação de aprovação'
|
|
103
|
+
)
|
|
104
|
+
expect(screen.getByTestId('reject-modal-message')).toHaveTextContent(
|
|
105
|
+
'Você está rejeitando a política {policy}.'
|
|
106
|
+
)
|
|
107
|
+
expect(screen.getByTestId('reject-modal-confirm')).toHaveTextContent(
|
|
108
|
+
'Confirmar rejeição'
|
|
109
|
+
)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('forwards CMS-provided buying policy toast labels to the order details header', () => {
|
|
113
|
+
mockUseAccountPageData.mockReturnValueOnce({ order })
|
|
114
|
+
|
|
115
|
+
render(
|
|
116
|
+
<AccountOrderDetails
|
|
117
|
+
approveSuccessToast="Política {policy} aprovada com sucesso."
|
|
118
|
+
approveErrorToast="Não foi possível aprovar a política."
|
|
119
|
+
rejectSuccessToast="Política {policy} rejeitada. Pedido negado."
|
|
120
|
+
rejectErrorToast="Não foi possível rejeitar a política."
|
|
121
|
+
pendingFurtherApprovalsAlert="Sua aprovação foi registrada. O pedido ainda aguarda outras aprovações."
|
|
122
|
+
/>
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
expect(screen.getByTestId('approve-success-toast')).toHaveTextContent(
|
|
126
|
+
'Política {policy} aprovada com sucesso.'
|
|
127
|
+
)
|
|
128
|
+
expect(screen.getByTestId('approve-error-toast')).toHaveTextContent(
|
|
129
|
+
'Não foi possível aprovar a política.'
|
|
130
|
+
)
|
|
131
|
+
expect(screen.getByTestId('reject-success-toast')).toHaveTextContent(
|
|
132
|
+
'Política {policy} rejeitada. Pedido negado.'
|
|
133
|
+
)
|
|
134
|
+
expect(screen.getByTestId('reject-error-toast')).toHaveTextContent(
|
|
135
|
+
'Não foi possível rejeitar a política.'
|
|
136
|
+
)
|
|
137
|
+
expect(
|
|
138
|
+
screen.getByTestId('pending-further-approvals-alert')
|
|
139
|
+
).toHaveTextContent(
|
|
140
|
+
'Sua aprovação foi registrada. O pedido ainda aguarda outras aprovações.'
|
|
141
|
+
)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('renders nothing when the page data has no order', () => {
|
|
145
|
+
mockUseAccountPageData.mockReturnValueOnce({ order: null })
|
|
146
|
+
|
|
147
|
+
const { container } = render(<AccountOrderDetails />)
|
|
148
|
+
|
|
149
|
+
expect(container).toBeEmptyDOMElement()
|
|
150
|
+
})
|
|
151
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest'
|
|
2
|
+
import { cleanup, render, screen } from '@testing-library/react'
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
+
|
|
5
|
+
const mockUseAccountPageData = vi.hoisted(() => vi.fn())
|
|
6
|
+
|
|
7
|
+
vi.mock('next/router', () => ({ useRouter: () => ({ locale: 'pt-BR' }) }))
|
|
8
|
+
vi.mock('src/sdk/account/accountPageContext', () => ({
|
|
9
|
+
useAccountPageData: mockUseAccountPageData,
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
import AccountOrderStatus from 'src/components/sections/Account/AccountOrderStatus'
|
|
13
|
+
|
|
14
|
+
const order = {
|
|
15
|
+
status: 'payment-approved',
|
|
16
|
+
creationDate: '2026-08-05T18:30:00.000Z',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
afterEach(cleanup)
|
|
20
|
+
|
|
21
|
+
describe('AccountOrderStatus', () => {
|
|
22
|
+
it('renders the timeline with the default labels', () => {
|
|
23
|
+
mockUseAccountPageData.mockReturnValueOnce({ order })
|
|
24
|
+
|
|
25
|
+
render(<AccountOrderStatus />)
|
|
26
|
+
|
|
27
|
+
expect(screen.getByText('Status')).toBeInTheDocument()
|
|
28
|
+
expect(screen.getByText('Order placed')).toBeInTheDocument()
|
|
29
|
+
expect(screen.getByText('Handling order')).toBeInTheDocument()
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('forwards the CMS labels to the status card', () => {
|
|
33
|
+
mockUseAccountPageData.mockReturnValueOnce({ order })
|
|
34
|
+
|
|
35
|
+
render(
|
|
36
|
+
<AccountOrderStatus
|
|
37
|
+
statusTitle="Status do pedido"
|
|
38
|
+
orderPlacedStep="Pedido realizado"
|
|
39
|
+
approvedStep="Aprovado"
|
|
40
|
+
handlingStep="Em separação"
|
|
41
|
+
shipOrderStep="Enviar pedido"
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
expect(screen.getByText('Status do pedido')).toBeInTheDocument()
|
|
46
|
+
expect(screen.getByText('Pedido realizado')).toBeInTheDocument()
|
|
47
|
+
expect(screen.getByText('Aprovado')).toBeInTheDocument()
|
|
48
|
+
expect(screen.getByText('Em separação')).toBeInTheDocument()
|
|
49
|
+
expect(screen.getByText('Enviar pedido')).toBeInTheDocument()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('renders nothing when the page data has no order', () => {
|
|
53
|
+
mockUseAccountPageData.mockReturnValueOnce({ order: null })
|
|
54
|
+
|
|
55
|
+
const { container } = render(<AccountOrderStatus />)
|
|
56
|
+
|
|
57
|
+
expect(container).toBeEmptyDOMElement()
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest'
|
|
2
|
+
import { cleanup, render } from '@testing-library/react'
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
+
|
|
5
|
+
import type { ListOrdersProps } from 'src/components/account/orders/ListOrders/ListOrders'
|
|
6
|
+
|
|
7
|
+
const mockUseAccountPageData = vi.hoisted(() => vi.fn())
|
|
8
|
+
const mockListOrders = vi.hoisted(() =>
|
|
9
|
+
vi.fn((_props: ListOrdersProps) => null)
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
vi.mock('src/sdk/account/accountPageContext', () => ({
|
|
13
|
+
useAccountPageData: mockUseAccountPageData,
|
|
14
|
+
}))
|
|
15
|
+
vi.mock('src/components/account/orders/ListOrders', () => ({
|
|
16
|
+
ListOrders: mockListOrders,
|
|
17
|
+
}))
|
|
18
|
+
|
|
19
|
+
import AccountOrdersList from 'src/components/sections/Account/AccountOrdersList'
|
|
20
|
+
|
|
21
|
+
const pageData = {
|
|
22
|
+
listOrders: { list: [] },
|
|
23
|
+
total: 0,
|
|
24
|
+
perPage: 10,
|
|
25
|
+
filters: {
|
|
26
|
+
page: 1,
|
|
27
|
+
status: [],
|
|
28
|
+
dateInitial: '',
|
|
29
|
+
dateFinal: '',
|
|
30
|
+
text: '',
|
|
31
|
+
clientEmail: '',
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
cleanup()
|
|
37
|
+
mockListOrders.mockClear()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('AccountOrdersList', () => {
|
|
41
|
+
it('forwards the default filter group labels', () => {
|
|
42
|
+
mockUseAccountPageData.mockReturnValueOnce(pageData)
|
|
43
|
+
|
|
44
|
+
render(<AccountOrdersList />)
|
|
45
|
+
|
|
46
|
+
expect(mockListOrders.mock.calls[0][0].labels).toMatchObject({
|
|
47
|
+
statusFilterLabel: 'Status',
|
|
48
|
+
orderDateFilterLabel: 'Order Date',
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('forwards the CMS filter group labels', () => {
|
|
53
|
+
mockUseAccountPageData.mockReturnValueOnce(pageData)
|
|
54
|
+
|
|
55
|
+
render(
|
|
56
|
+
<AccountOrdersList
|
|
57
|
+
statusFilterLabel="Situação"
|
|
58
|
+
orderDateFilterLabel="Data do pedido"
|
|
59
|
+
/>
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
expect(mockListOrders.mock.calls[0][0].labels).toMatchObject({
|
|
63
|
+
statusFilterLabel: 'Situação',
|
|
64
|
+
orderDateFilterLabel: 'Data do pedido',
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
})
|
|
@@ -18,12 +18,13 @@ vi.mock('../../../src/server', () => ({
|
|
|
18
18
|
|
|
19
19
|
const mockedExecute = vi.mocked(execute)
|
|
20
20
|
|
|
21
|
-
const createResponse = () => {
|
|
21
|
+
const createResponse = ({ headersSent = false } = {}) => {
|
|
22
22
|
const res = {
|
|
23
23
|
status: vi.fn().mockReturnThis(),
|
|
24
24
|
setHeader: vi.fn().mockReturnThis(),
|
|
25
25
|
send: vi.fn().mockReturnThis(),
|
|
26
26
|
end: vi.fn().mockReturnThis(),
|
|
27
|
+
headersSent,
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
return res as unknown as NextApiResponse & typeof res
|
|
@@ -122,6 +123,7 @@ describe('/api/graphql error status propagation', () => {
|
|
|
122
123
|
expect(res.status).toHaveBeenCalledWith(500)
|
|
123
124
|
expect(res.end).toHaveBeenCalled()
|
|
124
125
|
expect(res.send).not.toHaveBeenCalled()
|
|
126
|
+
expect(res.setHeader).toHaveBeenCalledWith('cache-control', 'no-store')
|
|
125
127
|
})
|
|
126
128
|
|
|
127
129
|
it('exposes type, status and message in the body outside production', async () => {
|
|
@@ -168,6 +170,15 @@ describe('/api/graphql error status propagation', () => {
|
|
|
168
170
|
|
|
169
171
|
expect(res.status).toHaveBeenCalledWith(404)
|
|
170
172
|
})
|
|
173
|
+
|
|
174
|
+
it('sets cache-control: no-store on error responses so a bare 404/410 is not cached by intermediaries', async () => {
|
|
175
|
+
mockExecuteWithErrors([maskedError(new NotFoundError('missing'))])
|
|
176
|
+
|
|
177
|
+
const res = createResponse()
|
|
178
|
+
await handler(createRequest(), res)
|
|
179
|
+
|
|
180
|
+
expect(res.setHeader).toHaveBeenCalledWith('cache-control', 'no-store')
|
|
181
|
+
})
|
|
171
182
|
})
|
|
172
183
|
|
|
173
184
|
describe('/api/graphql request handling', () => {
|
|
@@ -200,6 +211,21 @@ describe('/api/graphql request handling', () => {
|
|
|
200
211
|
|
|
201
212
|
expect(res.status).toHaveBeenCalledWith(status)
|
|
202
213
|
expect(res.end).toHaveBeenCalled()
|
|
214
|
+
expect(res.setHeader).toHaveBeenCalledWith('cache-control', 'no-store')
|
|
203
215
|
}
|
|
204
216
|
)
|
|
217
|
+
|
|
218
|
+
it('skips the cache-control header when headers were already sent', async () => {
|
|
219
|
+
mockedExecute.mockRejectedValue(new Error('boom after flush'))
|
|
220
|
+
|
|
221
|
+
const res = createResponse({ headersSent: true })
|
|
222
|
+
await handler(createRequest(), res)
|
|
223
|
+
|
|
224
|
+
expect(res.setHeader).not.toHaveBeenCalledWith(
|
|
225
|
+
'cache-control',
|
|
226
|
+
expect.anything()
|
|
227
|
+
)
|
|
228
|
+
expect(res.status).toHaveBeenCalledWith(500)
|
|
229
|
+
expect(res.end).toHaveBeenCalled()
|
|
230
|
+
})
|
|
205
231
|
})
|