@faststore/core 4.10.1-dev.6 → 4.10.1-dev.7
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 +176 -167
- package/@generated/graphql.ts +1 -0
- package/@generated/schema.graphql +1 -1
- package/CHANGELOG.md +29 -0
- package/package.json +6 -6
- package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawer.tsx +3 -3
- package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawerBody.tsx +5 -7
- package/src/components/account/Drawer/OrganizationSignInButton/OrganizationSignInButton.tsx +4 -1
- package/src/components/account/Layout/Layout.tsx +5 -7
- package/src/components/account/Menu/Menu.tsx +1 -1
- package/src/components/navigation/Navbar/Navbar.tsx +3 -3
- package/src/components/navigation/Navbar/NavbarAccountArea.tsx +5 -5
- package/src/components/navigation/NavbarSlider/NavbarSlider.tsx +3 -3
- package/src/experimental/myAccountCmsServerSideProps.ts +3 -3
- package/src/experimental/myAccountServerSideProps.ts +4 -4
- package/src/pages/[slug]/p.tsx +11 -2
- package/src/pages/api/fs/logout.ts +18 -10
- package/src/pages/api/fs/switch-contract.ts +170 -21
- package/src/pages/api/graphql.ts +4 -3
- package/src/pages/pvt/account/cards/index.tsx +5 -5
- package/src/pages/pvt/account/orders/[id].tsx +5 -5
- package/src/pages/pvt/account/orders/index.tsx +5 -5
- package/src/pages/pvt/account/profile.tsx +5 -5
- package/src/pages/pvt/account/quotes/index.tsx +5 -5
- package/src/pages/pvt/account/security.tsx +5 -5
- package/src/pages/pvt/account/user-details.tsx +6 -6
- package/src/sdk/account/getB2BSessionClaims.ts +1 -1
- package/src/sdk/account/getIsB2BBuyer.ts +28 -0
- package/src/sdk/account/refreshToken.ts +89 -11
- package/src/sdk/account/refreshTokenPaths.ts +25 -0
- package/src/sdk/account/useRefreshToken.ts +10 -5
- package/src/sdk/product/isProductNotFound.ts +13 -0
- package/src/sdk/product/useProductNotFoundRedirect.ts +43 -0
- package/src/sdk/product/useProductQuery.ts +29 -0
- package/src/sdk/session/index.ts +4 -4
- package/src/utils/getCheckoutParentDomain.ts +53 -0
- package/src/utils/trustedForwardedHost.ts +18 -0
- package/test/components/account/Layout.test.tsx +1 -1
- package/test/components/account/Menu.browser.test.tsx +7 -5
- package/test/components/account/OrganizationDrawer.browser.test.tsx +13 -13
- package/test/components/account/OrganizationDrawerBody.test.tsx +3 -3
- package/test/components/account/OrganizationSignInButton.browser.test.tsx +19 -4
- package/test/components/navigation/Navbar.browser.test.tsx +3 -3
- package/test/components/navigation/NavbarAccountArea.browser.test.tsx +5 -5
- package/test/components/navigation/NavbarSlider.browser.test.tsx +3 -3
- package/test/experimental/myAccountCmsServerSideProps.test.ts +5 -5
- package/test/pages/api/logout.test.ts +106 -0
- package/test/pages/api/switch-contract.test.ts +443 -15
- package/test/pages/pvt/account/cards/index.test.ts +3 -3
- package/test/sdk/account/getIsB2BBuyer.test.ts +52 -0
- package/test/sdk/account/refreshToken.browser.test.ts +10 -1
- package/test/sdk/account/refreshToken.test.ts +150 -18
- package/test/sdk/account/useRefreshToken.browser.test.ts +4 -1
- package/test/sdk/product/useProductNotFoundRedirect.browser.test.ts +83 -0
- package/test/sdk/product/useProductQuery.browser.test.ts +154 -0
- package/test/sdk/session/refreshTokenRoute.browser.test.ts +106 -0
- package/test/sdk/session/validateSession.browser.test.ts +4 -1
- package/test/utils/trustedForwardedHost.test.ts +21 -0
- package/src/sdk/account/getIsRepresentative.ts +0 -20
|
@@ -11,17 +11,17 @@ vi.mock(
|
|
|
11
11
|
() => ({
|
|
12
12
|
OrganizationSignInButton: ({
|
|
13
13
|
icon,
|
|
14
|
-
|
|
14
|
+
isB2BBuyer,
|
|
15
15
|
}: {
|
|
16
16
|
icon: { alt: string; icon: string }
|
|
17
|
-
|
|
17
|
+
isB2BBuyer?: boolean
|
|
18
18
|
}) => (
|
|
19
19
|
<button
|
|
20
20
|
type="button"
|
|
21
21
|
data-testid="organization-signin"
|
|
22
22
|
data-icon={icon.alt}
|
|
23
23
|
>
|
|
24
|
-
{
|
|
24
|
+
{isB2BBuyer ? 'B2B buyer' : 'Not a B2B buyer'}
|
|
25
25
|
</button>
|
|
26
26
|
),
|
|
27
27
|
})
|
|
@@ -85,7 +85,7 @@ describe('NavbarAccountArea', () => {
|
|
|
85
85
|
<NavbarAccountArea
|
|
86
86
|
isSignInResolved
|
|
87
87
|
isOrganizationEnabled
|
|
88
|
-
|
|
88
|
+
isB2BBuyer
|
|
89
89
|
signInButton={signInButton}
|
|
90
90
|
ButtonSignIn={ButtonSignInStub}
|
|
91
91
|
skeletonAttr="data-fs-navbar-signin-skeleton"
|
|
@@ -93,7 +93,7 @@ describe('NavbarAccountArea', () => {
|
|
|
93
93
|
)
|
|
94
94
|
|
|
95
95
|
expect(screen.getByTestId('organization-signin')).toHaveTextContent(
|
|
96
|
-
'
|
|
96
|
+
'B2B buyer'
|
|
97
97
|
)
|
|
98
98
|
expect(screen.queryByTestId('storefront-signin')).toBeNull()
|
|
99
99
|
})
|
|
@@ -120,10 +120,10 @@ describe('NavbarSlider', () => {
|
|
|
120
120
|
)
|
|
121
121
|
})
|
|
122
122
|
|
|
123
|
-
it('forwards isSignInResolved=true and isOrganizationEnabled once the B2B
|
|
123
|
+
it('forwards isSignInResolved=true and isOrganizationEnabled once the B2B session resolves', () => {
|
|
124
124
|
mockStoreConfig.experimental.enableFaststoreMyAccount = true
|
|
125
125
|
mockUseSession.mockReturnValue({
|
|
126
|
-
b2b: {
|
|
126
|
+
b2b: { unitId: 'unit-1', customerId: 'contract-1' },
|
|
127
127
|
isSessionReady: true,
|
|
128
128
|
hasValidated: true,
|
|
129
129
|
})
|
|
@@ -134,7 +134,7 @@ describe('NavbarSlider', () => {
|
|
|
134
134
|
expect.objectContaining({
|
|
135
135
|
isSignInResolved: true,
|
|
136
136
|
isOrganizationEnabled: true,
|
|
137
|
-
|
|
137
|
+
isB2BBuyer: true,
|
|
138
138
|
})
|
|
139
139
|
)
|
|
140
140
|
|
|
@@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
2
2
|
|
|
3
3
|
const mockValidateUser = vi.fn()
|
|
4
4
|
const mockGetMyAccountRedirect = vi.fn()
|
|
5
|
-
const
|
|
5
|
+
const mockGetIsB2BBuyer = vi.fn()
|
|
6
6
|
const mockFetchMyAccountPageContent = vi.fn()
|
|
7
7
|
const mockGetGlobalSectionsData = vi.fn()
|
|
8
8
|
const mockExecute = vi.fn()
|
|
@@ -20,8 +20,8 @@ vi.mock('src/utils/myAccountRedirect', () => ({
|
|
|
20
20
|
mockGetMyAccountRedirect(...args),
|
|
21
21
|
}))
|
|
22
22
|
|
|
23
|
-
vi.mock('src/sdk/account/
|
|
24
|
-
|
|
23
|
+
vi.mock('src/sdk/account/getIsB2BBuyer', () => ({
|
|
24
|
+
getIsB2BBuyer: (...args: unknown[]) => mockGetIsB2BBuyer(...args),
|
|
25
25
|
}))
|
|
26
26
|
|
|
27
27
|
vi.mock('src/server/cms/fetchMyAccountPageContent', () => ({
|
|
@@ -78,7 +78,7 @@ function buildContext(overrides: Record<string, unknown> = {}) {
|
|
|
78
78
|
describe('myAccountCmsServerSideProps', () => {
|
|
79
79
|
beforeEach(() => {
|
|
80
80
|
vi.clearAllMocks()
|
|
81
|
-
|
|
81
|
+
mockGetIsB2BBuyer.mockReturnValue(false)
|
|
82
82
|
mockGetGlobalSectionsData.mockReturnValue([
|
|
83
83
|
Promise.resolve({ sections: [], settings: {} }),
|
|
84
84
|
Promise.resolve({ sections: [] }),
|
|
@@ -176,7 +176,7 @@ describe('myAccountCmsServerSideProps', () => {
|
|
|
176
176
|
expect(result).toMatchObject({
|
|
177
177
|
props: {
|
|
178
178
|
accountName: 'Ada',
|
|
179
|
-
|
|
179
|
+
isB2BBuyer: false,
|
|
180
180
|
navigationLabels: { profileLabel: 'Profile' },
|
|
181
181
|
pageSections: [
|
|
182
182
|
{
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { NextApiRequest, NextApiResponse } from 'next'
|
|
2
|
+
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest'
|
|
3
|
+
|
|
4
|
+
const mockConfig = vi.hoisted(() => ({
|
|
5
|
+
default: {
|
|
6
|
+
experimental: { refreshToken: true } as Record<string, unknown>,
|
|
7
|
+
} as { experimental: Record<string, unknown>; secureSubdomain?: string },
|
|
8
|
+
}))
|
|
9
|
+
|
|
10
|
+
vi.mock('discovery.config', () => ({ __esModule: true, ...mockConfig }))
|
|
11
|
+
|
|
12
|
+
function createReqRes(cookie = 'VtexIdclientAutCookie_test-store=token') {
|
|
13
|
+
const res = {
|
|
14
|
+
status: vi.fn().mockReturnThis(),
|
|
15
|
+
json: vi.fn(),
|
|
16
|
+
end: vi.fn(),
|
|
17
|
+
setHeader: vi.fn(),
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
req: {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: { host: 'store.example.com', cookie },
|
|
24
|
+
} as unknown as NextApiRequest,
|
|
25
|
+
res: res as unknown as NextApiResponse & { setHeader: Mock },
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const setCookiesFrom = (res: { setHeader: Mock }): string[] =>
|
|
30
|
+
(res.setHeader.mock.calls.find(
|
|
31
|
+
([name]) => String(name).toLowerCase() === 'set-cookie'
|
|
32
|
+
)?.[1] as string[] | undefined) ?? []
|
|
33
|
+
|
|
34
|
+
async function getHandler() {
|
|
35
|
+
const mod = await import('../../../src/pages/api/fs/logout')
|
|
36
|
+
return mod.default
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe('/api/fs/logout', () => {
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
vi.resetModules()
|
|
42
|
+
mockConfig.default.experimental = { refreshToken: true }
|
|
43
|
+
mockConfig.default.secureSubdomain = undefined
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('expires vid_rt on every path it can be scoped to, even though the request never carries it', async () => {
|
|
47
|
+
const handler = await getHandler()
|
|
48
|
+
const { req, res } = createReqRes()
|
|
49
|
+
|
|
50
|
+
await handler(req, res)
|
|
51
|
+
|
|
52
|
+
const vidRt = setCookiesFrom(res).filter((cookie) =>
|
|
53
|
+
cookie.startsWith('vid_rt=;')
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
for (const path of [
|
|
57
|
+
'/api/vtexid/refreshtoken/webstore',
|
|
58
|
+
'/api/authenticator/refreshtoken/webstore',
|
|
59
|
+
'/api/authenticator/v1/refreshtoken/webstore',
|
|
60
|
+
]) {
|
|
61
|
+
expect(vidRt.some((cookie) => cookie.includes(`path=${path}`))).toBe(true)
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('does not touch vid_rt when refresh token is disabled', async () => {
|
|
66
|
+
mockConfig.default.experimental = {}
|
|
67
|
+
const handler = await getHandler()
|
|
68
|
+
const { req, res } = createReqRes()
|
|
69
|
+
|
|
70
|
+
await handler(req, res)
|
|
71
|
+
|
|
72
|
+
expect(
|
|
73
|
+
setCookiesFrom(res).some((cookie) => cookie.startsWith('vid_rt='))
|
|
74
|
+
).toBe(false)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('expires the auth cookie on the parent shared with a sibling checkout host', async () => {
|
|
78
|
+
mockConfig.default.secureSubdomain = 'https://secure.example.com'
|
|
79
|
+
const handler = await getHandler()
|
|
80
|
+
const { req, res } = createReqRes()
|
|
81
|
+
|
|
82
|
+
await handler(req, res)
|
|
83
|
+
|
|
84
|
+
expect(
|
|
85
|
+
setCookiesFrom(res).filter((cookie) =>
|
|
86
|
+
cookie.startsWith('VtexIdclientAutCookie_test-store=;')
|
|
87
|
+
)
|
|
88
|
+
).toEqual(
|
|
89
|
+
expect.arrayContaining([expect.stringContaining('; domain=example.com;')])
|
|
90
|
+
)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('does not touch the parent domain when checkout runs on the store host', async () => {
|
|
94
|
+
mockConfig.default.secureSubdomain = 'https://store.example.com'
|
|
95
|
+
const handler = await getHandler()
|
|
96
|
+
const { req, res } = createReqRes()
|
|
97
|
+
|
|
98
|
+
await handler(req, res)
|
|
99
|
+
|
|
100
|
+
expect(
|
|
101
|
+
setCookiesFrom(res).some((cookie) =>
|
|
102
|
+
cookie.includes('; domain=example.com;')
|
|
103
|
+
)
|
|
104
|
+
).toBe(false)
|
|
105
|
+
})
|
|
106
|
+
})
|