@faststore/core 4.3.0-dev.6 → 4.3.0-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.
@@ -1,9 +1,9 @@
1
1
 
2
- > @faststore/core@4.3.0-dev.5 generate /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@4.3.0-dev.6 generate /home/runner/work/faststore/faststore/packages/core
3
3
  > pnpm run gen-types && pnpm run cache-graphql
4
4
 
5
5
 
6
- > @faststore/core@4.3.0-dev.5 gen-types /home/runner/work/faststore/faststore/packages/core
6
+ > @faststore/core@4.3.0-dev.6 gen-types /home/runner/work/faststore/faststore/packages/core
7
7
  > node ../cli/bin/run generate-types .
8
8
 
9
9
  [STARTED] Parse Configuration
@@ -19,7 +19,7 @@
19
19
  [COMPLETED] Generate to /home/runner/work/faststore/faststore/packages/core/@generated/
20
20
  [COMPLETED] Generate outputs
21
21
 
22
- > @faststore/core@4.3.0-dev.5 cache-graphql /home/runner/work/faststore/faststore/packages/core
22
+ > @faststore/core@4.3.0-dev.6 cache-graphql /home/runner/work/faststore/faststore/packages/core
23
23
  > node ../cli/bin/run cache-graphql --config=./discovery.config.default.js --queries=./@generated/persisted-documents.json
24
24
 
25
25
  [Info] - Config file location: /home/runner/work/faststore/faststore/packages/core/discovery.config.default.js
@@ -1,12 +1,12 @@
1
1
 
2
- > @faststore/core@4.3.0-dev.5 test /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@4.3.0-dev.6 test /home/runner/work/faststore/faststore/packages/core
3
3
  > vitest run
4
4
 
5
5
 
6
6
   RUN  v4.0.7 /home/runner/work/faststore/faststore/packages/core
7
7
 
8
- ✓  browser  test/sdk/session/installLocaleCorrector.browser.test.ts (7 tests) 48ms
9
- ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 29ms
8
+ ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 36ms
9
+ ✓  browser  test/sdk/session/installLocaleCorrector.browser.test.ts (7 tests) 54ms
10
10
  stderr | test/sdk/localization/store-url.browser.test.ts
11
11
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
12
12
  at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:119:27)
@@ -14,15 +14,14 @@
14
14
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:353:23)
15
15
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
16
16
 
17
- ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 78ms
18
- ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 18ms
19
- ✓  node  test/utils/match-url.test.ts (10 tests) 33ms
20
- ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 12ms
21
- ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 39ms
17
+ ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 11ms
18
+ ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 123ms
19
+ ✓  node  test/utils/match-url.test.ts (10 tests) 21ms
20
+ ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 15ms
21
+ ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 20ms
22
22
  stderr | test/components/search/SearchInputComponent.test.tsx
23
23
  Warning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
24
24
 
25
- ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 55ms
26
25
  stderr | test/components/search/SearchInputComponent.test.tsx > SearchInput (OES integration) > renders without crashing
27
26
  Warning: React does not recognize the `visibleDropdown` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `visibledropdown` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
28
27
  at div
@@ -83,12 +82,17 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
83
82
  at Suspense
84
83
  at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
85
84
 
86
- ✓  node  test/components/search/SearchInputComponent.test.tsx (6 tests) 407ms
87
- ✓  node  test/sdk/search/useSearchHistory.test.ts (13 tests) 200ms
88
- ✓  node  test/sdk/localization/useBindingSelector.test.tsx (12 tests) 53ms
89
- ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 30ms
85
+ ✓  node  test/components/search/SearchInputComponent.test.tsx (6 tests) 372ms
86
+ ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 50ms
87
+ ✓  node  test/sdk/search/useSearchHistory.test.ts (13 tests) 244ms
88
+ ✓  node  test/sdk/localization/useBindingSelector.test.tsx (12 tests) 71ms
90
89
  ✓  node  test/utils/clearCookies.test.ts (20 tests) 98ms
91
- ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 118ms
90
+ ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 37ms
91
+ stderr | test/sdk/account/useSetPassword.test.ts > useSetPassword > maps wrongcredentials error responses to the existing message
92
+ Set password request failed: Bad Request
93
+
94
+ ✓  node  test/sdk/account/useSetPassword.test.ts (6 tests) 247ms
95
+ ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 89ms
92
96
  stderr | test/pages/api/graphql.test.ts > /api/graphql error status propagation > propagates the upstream 400 from a wrapped BadRequestError instead of 500
93
97
  Graphql execution returned with error: [
94
98
  {
@@ -135,26 +139,27 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
135
139
  { message: 'bad', status: 400, type: 'BadRequestError' }
136
140
  ]
137
141
 
138
- ✓  node  test/pages/api/graphql.test.ts (10 tests) 58ms
139
- ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 48ms
140
- ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 33ms
141
- ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 49ms
142
- ✓  node  test/server/cms/global.test.ts (3 tests) 4ms
143
- ✓  node  test/server/content/service.test.ts (5 tests) 4ms
144
- ✓  node  test/sdk/localization/store-url.test.ts (1 test) 4ms
145
- ✓  node  test/server/index.test.ts (7 tests) 990ms
146
- ✓ should handle options and execute  520ms
147
- ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 6ms
148
- ✓  node  test/pages/api/preview.test.ts (2 tests) 7ms
149
- ✓  node  test/sdk/auth/useAuth.test.ts (5 tests) 32ms
142
+ ✓  node  test/pages/api/graphql.test.ts (10 tests) 59ms
143
+ ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 81ms
144
+ ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 62ms
145
+ ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 41ms
146
+ ✓  node  test/server/cms/global.test.ts (3 tests) 5ms
147
+ ✓  node  test/server/index.test.ts (7 tests) 862ms
148
+ ✓ should exist with its plugins  303ms
149
+ ✓ should handle options and execute  311ms
150
+ ✓  node  test/server/content/service.test.ts (5 tests) 6ms
151
+ ✓  node  test/sdk/localization/store-url.test.ts (1 test) 5ms
152
+ ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 7ms
153
+ ✓  node  test/pages/api/preview.test.ts (2 tests) 10ms
154
+ ✓  node  test/sdk/auth/useAuth.test.ts (5 tests) 33ms
150
155
  ✓  node  test/utils/validateSessionRefreshToken.test.ts (6 tests) 5ms
151
156
  ✓  node  test/components/search/SearchInput.test.ts (6 tests) 8ms
152
- ✓  node  test/server/cms/index.test.ts (2 tests) 4ms
153
- ✓  node  test/utils/isLocalHost.test.ts (7 tests) 7ms
154
- ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 26ms
155
-
156
-  Test Files  30 passed (30)
157
-  Tests  287 passed (287)
158
-  Start at  15:21:20
159
-  Duration  21.59s (transform 6.15s, setup 0ms, collect 18.64s, tests 2.50s, environment 28.13s, prepare 992ms)
157
+ ✓  node  test/utils/isLocalHost.test.ts (7 tests) 6ms
158
+ ✓  node  test/server/cms/index.test.ts (2 tests) 6ms
159
+ ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 27ms
160
+
161
+  Test Files  31 passed (31)
162
+  Tests  293 passed (293)
163
+  Start at  16:58:10
164
+  Duration  24.02s (transform 5.83s, setup 0ms, collect 19.89s, tests 2.71s, environment 32.71s, prepare 998ms)
160
165
 
package/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [4.3.0-dev.7](https://github.com/vtex/faststore/compare/v4.3.0-dev.6...v4.3.0-dev.7) (2026-06-17)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **core:** use authenticator route for setpassword ([#3380](https://github.com/vtex/faststore/issues/3380)) ([a155269](https://github.com/vtex/faststore/commit/a155269678d8a0584a98008b1384bf146f6da1cb))
11
+
6
12
  # [4.3.0-dev.6](https://github.com/vtex/faststore/compare/v4.3.0-dev.5...v4.3.0-dev.6) (2026-06-17)
7
13
 
8
14
  ### Bug Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "4.3.0-dev.6",
3
+ "version": "4.3.0-dev.7",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -70,11 +70,11 @@
70
70
  "style-loader": "^3.3.1",
71
71
  "swr": "^2.2.5",
72
72
  "use-sync-external-store": "^1.6.0",
73
- "@faststore/api": "4.3.0-dev.6",
74
- "@faststore/lighthouse": "4.3.0-dev.6",
75
- "@faststore/sdk": "4.3.0-dev.6",
76
- "@faststore/ui": "4.3.0-dev.6",
77
- "@faststore/diagnostics": "4.3.0-dev.6"
73
+ "@faststore/api": "4.3.0-dev.7",
74
+ "@faststore/diagnostics": "4.3.0-dev.7",
75
+ "@faststore/lighthouse": "4.3.0-dev.7",
76
+ "@faststore/ui": "4.3.0-dev.7",
77
+ "@faststore/sdk": "4.3.0-dev.7"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@cypress/code-coverage": "^3.12.1",
@@ -39,84 +39,89 @@ const authMessage = {
39
39
  export const useSetPassword = (accountName?: string) => {
40
40
  const [loading, setLoading] = useState<boolean>(false)
41
41
 
42
- const setPassword = useCallback(async (input: SetPasswordInput) => {
43
- setLoading(true)
44
-
45
- try {
46
- await startLogin({ email: input.userEmail, accountName })
47
-
48
- const body = {
49
- login: input.userEmail,
50
- currentPassword: input.currentPassword,
51
- newPassword: input.newPassword,
52
- accesskey: !input.accesskey ? null : input.accesskey,
53
- recaptcha: !input.recaptcha ? null : input.recaptcha,
54
- }
42
+ const setPassword = useCallback(
43
+ async (input: SetPasswordInput) => {
44
+ setLoading(true)
45
+
46
+ try {
47
+ const an = encodeURIComponent(accountName ?? config.api.storeId)
55
48
 
56
- const response = await fetch(
57
- `/api/vtexid/pub/authentication/classic/setpassword?expireSessions=true`,
58
- {
59
- method: 'POST',
60
- body: buildFormData(body),
61
- credentials: 'include',
49
+ await startLogin({ email: input.userEmail, accountName, an })
50
+
51
+ const body = {
52
+ login: input.userEmail,
53
+ currentPassword: input.currentPassword,
54
+ newPassword: input.newPassword,
55
+ accesskey: !input.accesskey ? null : input.accesskey,
56
+ recaptcha: !input.recaptcha ? null : input.recaptcha,
62
57
  }
63
- )
64
58
 
65
- if (!response.ok) {
66
- setLoading(false)
59
+ const response = await fetch(
60
+ `/api/authenticator/pub/authentication/classic/setpassword?expireSessions=true&an=${an}`,
61
+ {
62
+ method: 'POST',
63
+ body: buildFormData(body),
64
+ credentials: 'include',
65
+ }
66
+ )
67
+
68
+ if (!response.ok) {
69
+ setLoading(false)
67
70
 
68
- console.error('Set password request failed:', response.statusText)
71
+ console.error('Set password request failed:', response.statusText)
69
72
 
70
- let errorStatus = AUTH_STATUS.UNEXPECTED_ERROR
73
+ let errorStatus = AUTH_STATUS.UNEXPECTED_ERROR
71
74
 
72
- try {
73
- const errorBody = await response.json()
74
- if (errorBody?.authStatus) {
75
- errorStatus = String(errorBody.authStatus).toLowerCase().trim()
75
+ try {
76
+ const errorBody = await response.json()
77
+ if (errorBody?.authStatus) {
78
+ errorStatus = String(errorBody.authStatus).toLowerCase().trim()
79
+ }
80
+ } catch {
81
+ // Keep the default error
76
82
  }
77
- } catch {
78
- // Keep the default error
79
- }
80
83
 
81
- return {
82
- success: false,
83
- message: authMessage[errorStatus],
84
+ return {
85
+ success: false,
86
+ message: authMessage[errorStatus],
87
+ }
84
88
  }
85
- }
86
89
 
87
- const result: SetPasswordResultType = await response.json()
90
+ const result: SetPasswordResultType = await response.json()
88
91
 
89
- if (!result) {
90
- setLoading(false)
92
+ if (!result) {
93
+ setLoading(false)
91
94
 
92
- return {
93
- success: false,
94
- message: authMessage[AUTH_STATUS.NO_RESPONSE],
95
+ return {
96
+ success: false,
97
+ message: authMessage[AUTH_STATUS.NO_RESPONSE],
98
+ }
95
99
  }
96
- }
97
100
 
98
- const authStatus = result?.authStatus?.toLowerCase().trim() ?? ''
101
+ const authStatus = result?.authStatus?.toLowerCase().trim() ?? ''
99
102
 
100
- return {
101
- success: authStatus === AUTH_STATUS.SUCCESS,
102
- message: authMessage[authStatus] || 'Unexpected error occurred',
103
- }
104
- } catch (err) {
105
- console.error('Error setting password:', err)
103
+ return {
104
+ success: authStatus === AUTH_STATUS.SUCCESS,
105
+ message: authMessage[authStatus] || 'Unexpected error occurred',
106
+ }
107
+ } catch (err) {
108
+ console.error('Error setting password:', err)
106
109
 
107
- const authStatus =
108
- typeof err === 'object' && err !== null && 'authStatus' in err
109
- ? String(err.authStatus).toLowerCase().trim()
110
- : AUTH_STATUS.UNEXPECTED_ERROR
110
+ const authStatus =
111
+ typeof err === 'object' && err !== null && 'authStatus' in err
112
+ ? String(err.authStatus).toLowerCase().trim()
113
+ : AUTH_STATUS.UNEXPECTED_ERROR
111
114
 
112
- return {
113
- success: false,
114
- message: authMessage[authStatus] || 'Unexpected error occurred',
115
+ return {
116
+ success: false,
117
+ message: authMessage[authStatus] || 'Unexpected error occurred',
118
+ }
119
+ } finally {
120
+ setLoading(false)
115
121
  }
116
- } finally {
117
- setLoading(false)
118
- }
119
- }, [])
122
+ },
123
+ [accountName]
124
+ )
120
125
 
121
126
  return { setPassword, loading }
122
127
  }
@@ -124,23 +129,28 @@ export const useSetPassword = (accountName?: string) => {
124
129
  const startLogin = async ({
125
130
  email,
126
131
  accountName,
132
+ an,
127
133
  }: {
128
134
  email: string
129
135
  accountName?: string
136
+ an: string
130
137
  }) => {
131
138
  try {
132
- const response = await fetch(`/api/vtexid/pub/authentication/startlogin`, {
133
- method: 'POST',
134
- credentials: 'include',
135
- body: buildFormData({
136
- user: email,
137
- scope: accountName ?? config.api.storeId,
138
- accountName: accountName ?? config.api.storeId,
139
- returnUrl: '/',
140
- callbackUrl: '/',
141
- fingerprint: null,
142
- }),
143
- })
139
+ const scope = accountName ?? config.api.storeId
140
+
141
+ const response = await fetch(
142
+ `/api/authenticator/pub/authentication/start?an=${an}`,
143
+ {
144
+ method: 'POST',
145
+ credentials: 'include',
146
+ body: buildFormData({
147
+ user: email,
148
+ scope,
149
+ accountName: scope,
150
+ returnUrl: '/',
151
+ }),
152
+ }
153
+ )
144
154
 
145
155
  if (!response.ok) {
146
156
  throw {
@@ -0,0 +1,192 @@
1
+ /**
2
+ * @vitest-environment jsdom
3
+ */
4
+
5
+ import { act, renderHook } from '@testing-library/react'
6
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
7
+
8
+ vi.mock('discovery.config', () => ({
9
+ __esModule: true,
10
+ default: {
11
+ api: { storeId: 'storeframework' },
12
+ },
13
+ }))
14
+
15
+ const mockFetch = vi.hoisted(() => vi.fn())
16
+ vi.mock('isomorphic-unfetch', () => ({ __esModule: true, default: mockFetch }))
17
+
18
+ import { useSetPassword } from '../../../src/sdk/account/useSetPassword'
19
+
20
+ const okResponse = (body: unknown) => ({
21
+ ok: true,
22
+ statusText: 'OK',
23
+ json: async () => body,
24
+ })
25
+
26
+ const errorResponse = (body: unknown) => ({
27
+ ok: false,
28
+ statusText: 'Bad Request',
29
+ json: async () => body,
30
+ })
31
+
32
+ const validInput = {
33
+ userEmail: 'shopper@example.com',
34
+ currentPassword: 'OldPass123',
35
+ newPassword: 'NewPass123',
36
+ }
37
+
38
+ function getSetPasswordCall() {
39
+ return mockFetch.mock.calls.find((call) =>
40
+ String(call[0]).includes('setpassword')
41
+ )
42
+ }
43
+
44
+ function getStartLoginCall() {
45
+ return mockFetch.mock.calls.find((call) =>
46
+ String(call[0]).includes('/pub/authentication/start')
47
+ )
48
+ }
49
+
50
+ describe('useSetPassword', () => {
51
+ beforeEach(() => {
52
+ mockFetch.mockReset()
53
+ })
54
+
55
+ afterEach(() => {
56
+ vi.clearAllMocks()
57
+ })
58
+
59
+ it('posts to the new authenticator setpassword route with expireSessions and an', async () => {
60
+ mockFetch
61
+ .mockResolvedValueOnce(okResponse({})) // startLogin
62
+ .mockResolvedValueOnce(okResponse({ authStatus: 'success' }))
63
+
64
+ const { result } = renderHook(() => useSetPassword('myaccount'))
65
+
66
+ await act(async () => {
67
+ await result.current.setPassword(validInput)
68
+ })
69
+
70
+ const call = getSetPasswordCall()
71
+ expect(call).toBeDefined()
72
+
73
+ const url = String(call?.[0])
74
+ expect(url).toContain(
75
+ '/api/authenticator/pub/authentication/classic/setpassword'
76
+ )
77
+ expect(url).not.toContain('/api/vtexid/')
78
+ expect(url).toContain('expireSessions=true')
79
+ expect(url).toContain('an=myaccount')
80
+ })
81
+
82
+ it('posts to the new authenticator start route with an and credentials', async () => {
83
+ mockFetch
84
+ .mockResolvedValueOnce(okResponse({})) // startLogin
85
+ .mockResolvedValueOnce(okResponse({ authStatus: 'success' }))
86
+
87
+ const { result } = renderHook(() => useSetPassword('myaccount'))
88
+
89
+ await act(async () => {
90
+ await result.current.setPassword(validInput)
91
+ })
92
+
93
+ const call = getStartLoginCall()
94
+ expect(call).toBeDefined()
95
+
96
+ const url = String(call?.[0])
97
+ expect(url).toContain('/api/authenticator/pub/authentication/start')
98
+ expect(url).not.toContain('/api/vtexid/')
99
+ expect(url).toContain('an=myaccount')
100
+
101
+ const init = call?.[1] as RequestInit
102
+ expect(init?.method).toBe('POST')
103
+ expect(init?.credentials).toBe('include')
104
+
105
+ const body = init?.body as FormData
106
+ expect(body).toBeInstanceOf(FormData)
107
+ expect(body.get('user')).toBe(validInput.userEmail)
108
+ expect(body.get('scope')).toBe('myaccount')
109
+ expect(body.get('accountName')).toBe('myaccount')
110
+ expect(body.get('returnUrl')).toBe('/')
111
+ })
112
+
113
+ it('sends a POST with credentials and the expected form-data body', async () => {
114
+ mockFetch
115
+ .mockResolvedValueOnce(okResponse({}))
116
+ .mockResolvedValueOnce(okResponse({ authStatus: 'success' }))
117
+
118
+ const { result } = renderHook(() => useSetPassword('myaccount'))
119
+
120
+ await act(async () => {
121
+ await result.current.setPassword(validInput)
122
+ })
123
+
124
+ const call = getSetPasswordCall()
125
+ const init = call?.[1] as RequestInit
126
+
127
+ expect(init?.method).toBe('POST')
128
+ expect(init?.credentials).toBe('include')
129
+
130
+ const body = init?.body as FormData
131
+ expect(body).toBeInstanceOf(FormData)
132
+ expect(body.get('login')).toBe(validInput.userEmail)
133
+ expect(body.get('currentPassword')).toBe(validInput.currentPassword)
134
+ expect(body.get('newPassword')).toBe(validInput.newPassword)
135
+ })
136
+
137
+ it('returns success when the endpoint reports authStatus success', async () => {
138
+ mockFetch
139
+ .mockResolvedValueOnce(okResponse({}))
140
+ .mockResolvedValueOnce(okResponse({ authStatus: 'success' }))
141
+
142
+ const { result } = renderHook(() => useSetPassword('myaccount'))
143
+
144
+ let outcome: { success: boolean; message: string } | undefined
145
+ await act(async () => {
146
+ outcome = await result.current.setPassword(validInput)
147
+ })
148
+
149
+ expect(outcome).toEqual({
150
+ success: true,
151
+ message: 'Password set successfully',
152
+ })
153
+ })
154
+
155
+ it('maps wrongcredentials error responses to the existing message', async () => {
156
+ mockFetch
157
+ .mockResolvedValueOnce(okResponse({}))
158
+ .mockResolvedValueOnce(errorResponse({ authStatus: 'wrongcredentials' }))
159
+
160
+ const { result } = renderHook(() => useSetPassword('myaccount'))
161
+
162
+ let outcome: { success: boolean; message: string } | undefined
163
+ await act(async () => {
164
+ outcome = await result.current.setPassword(validInput)
165
+ })
166
+
167
+ expect(outcome).toEqual({ success: false, message: 'Wrong credentials' })
168
+ })
169
+
170
+ it('falls back to config.api.storeId when accountName is missing', async () => {
171
+ mockFetch
172
+ .mockResolvedValueOnce(okResponse({}))
173
+ .mockResolvedValueOnce(okResponse({ authStatus: 'success' }))
174
+
175
+ const { result } = renderHook(() => useSetPassword())
176
+
177
+ await act(async () => {
178
+ await result.current.setPassword(validInput)
179
+ })
180
+
181
+ const setPasswordUrl = String(getSetPasswordCall()?.[0])
182
+ expect(setPasswordUrl).toContain('an=storeframework')
183
+
184
+ const startLoginCall = getStartLoginCall()
185
+ const startLoginUrl = String(startLoginCall?.[0])
186
+ expect(startLoginUrl).toContain('an=storeframework')
187
+
188
+ const startBody = (startLoginCall?.[1] as RequestInit)?.body as FormData
189
+ expect(startBody.get('scope')).toBe('storeframework')
190
+ expect(startBody.get('accountName')).toBe('storeframework')
191
+ })
192
+ })