@@ -9,6 +9,7 @@ import {shopifyFetch} from '@shopify/cli-kit/node/http'
99import { AbortError } from '@shopify/cli-kit/node/error'
1010import { passwordProtected } from '@shopify/cli-kit/node/themes/api'
1111import { type AdminSession } from '@shopify/cli-kit/node/session'
12+ import { getThemeKitAccessDomain } from '@shopify/cli-kit/node/context/local'
1213
1314vi . mock ( '@shopify/cli-kit/node/http' )
1415vi . mock ( '@shopify/cli-kit/node/themes/api' )
@@ -45,7 +46,11 @@ describe('Storefront API', () => {
4546 )
4647
4748 // When
48- const cookies = await getStorefrontSessionCookies ( 'https://example-store.myshopify.com' , '123456' )
49+ const cookies = await getStorefrontSessionCookies (
50+ 'https://example-store.myshopify.com' ,
51+ 'example-store.myshopify.com' ,
52+ '123456' ,
53+ )
4954
5055 // Then
5156 expect ( cookies ) . toEqual ( { _shopify_essential : ':AABBCCDDEEFFGGHH==123:' } )
@@ -62,13 +67,21 @@ describe('Storefront API', () => {
6267 )
6368 . mockResolvedValueOnce (
6469 response ( {
65- status : 200 ,
66- headers : { 'set-cookie' : 'storefront_digest=digest-value; path=/; HttpOnly' } ,
70+ status : 302 ,
71+ headers : {
72+ 'set-cookie' : 'storefront_digest=digest-value; path=/; HttpOnly' ,
73+ location : 'https://example-store.myshopify.com/' ,
74+ } ,
6775 } ) ,
6876 )
6977
7078 // When
71- const cookies = await getStorefrontSessionCookies ( 'https://example-store.myshopify.com' , '123456' , 'password' )
79+ const cookies = await getStorefrontSessionCookies (
80+ 'https://example-store.myshopify.com' ,
81+ 'example-store.myshopify.com' ,
82+ '123456' ,
83+ 'password' ,
84+ )
7285
7386 // Then
7487 expect ( cookies ) . toEqual ( { _shopify_essential : ':AABBCCDDEEFFGGHH==123:' , storefront_digest : 'digest-value' } )
@@ -135,7 +148,12 @@ describe('Storefront API', () => {
135148 )
136149
137150 // When
138- const cookies = getStorefrontSessionCookies ( 'https://example-store.myshopify.com' , '123456' , 'wrongpassword' )
151+ const cookies = getStorefrontSessionCookies (
152+ 'https://example-store.myshopify.com' ,
153+ 'example-store.myshopify.com' ,
154+ '123456' ,
155+ 'wrongpassword' ,
156+ )
139157
140158 // Then
141159 await expect ( cookies ) . rejects . toThrow (
@@ -171,12 +189,153 @@ describe('Storefront API', () => {
171189 )
172190
173191 // When
174- const cookies = await getStorefrontSessionCookies ( 'https://example-store.myshopify.com' , '123456' )
192+ const cookies = await getStorefrontSessionCookies (
193+ 'https://example-store.myshopify.com' ,
194+ 'example-store.myshopify.com' ,
195+ '123456' ,
196+ )
175197
176198 // Then
177199 expect ( cookies ) . toEqual ( { _shopify_essential : ':AABBCCDDEEFFGGHH==RETRYCOOKIE:' } )
178200 expect ( shopifyFetch ) . toHaveBeenCalledTimes ( 3 )
179201 } )
202+
203+ test ( 'handles storefront_digest migration to _shopify_essential cookie' , async ( ) => {
204+ const originalEssential = ':AABBCCDDEEFFGGHH==123:'
205+ const authenticatedEssential = ':NEWESSENTIAL==456:'
206+
207+ vi . mocked ( shopifyFetch )
208+ . mockResolvedValueOnce (
209+ response ( {
210+ status : 200 ,
211+ headers : { 'set-cookie' : `_shopify_essential=${ originalEssential } ; path=/; HttpOnly` } ,
212+ } ) ,
213+ )
214+ . mockResolvedValueOnce (
215+ response ( {
216+ status : 302 ,
217+ headers : {
218+ 'set-cookie' : `_shopify_essential=${ authenticatedEssential } ; path=/; HttpOnly` ,
219+ location : 'https://example-store.myshopify.com/' ,
220+ } ,
221+ } ) ,
222+ )
223+
224+ // When
225+ const cookies = await getStorefrontSessionCookies (
226+ 'https://example-store.myshopify.com' ,
227+ 'example-store.myshopify.com' ,
228+ '123456' ,
229+ 'password' ,
230+ )
231+
232+ // Then
233+ expect ( cookies ) . toEqual ( {
234+ _shopify_essential : authenticatedEssential ,
235+ } )
236+ } )
237+
238+ test ( 'handles theme kit access with _shopify_essential cookies' , async ( ) => {
239+ const originalEssential = ':AABBCCDDEEFFGGHH==123:'
240+ const authenticatedEssential = ':NEWESSENTIAL==456:'
241+
242+ vi . mocked ( shopifyFetch )
243+ . mockResolvedValueOnce (
244+ response ( {
245+ status : 200 ,
246+ headers : { 'set-cookie' : `_shopify_essential=${ originalEssential } ; path=/; HttpOnly` } ,
247+ } ) ,
248+ )
249+ . mockResolvedValueOnce (
250+ response ( {
251+ status : 302 ,
252+ headers : {
253+ 'set-cookie' : `_shopify_essential=${ authenticatedEssential } ; path=/; HttpOnly` ,
254+ location : 'https://example-store.myshopify.com/' ,
255+ } ,
256+ } ) ,
257+ )
258+
259+ // When
260+ const cookies = await getStorefrontSessionCookies (
261+ `https://${ getThemeKitAccessDomain ( ) } ` ,
262+ 'example-store.myshopify.com' ,
263+ '123456' ,
264+ 'password' ,
265+ )
266+
267+ // Then
268+ expect ( cookies ) . toEqual ( {
269+ _shopify_essential : authenticatedEssential ,
270+ } )
271+ } )
272+
273+ test ( 'handles case when storefront_digest is present (non-migrated case)' , async ( ) => {
274+ // Given: storefront_digest is still being used
275+ vi . mocked ( shopifyFetch )
276+ . mockResolvedValueOnce (
277+ response ( {
278+ status : 200 ,
279+ headers : { 'set-cookie' : '_shopify_essential=:AABBCCDDEEFFGGHH==123:; path=/; HttpOnly' } ,
280+ } ) ,
281+ )
282+ . mockResolvedValueOnce (
283+ response ( {
284+ status : 302 ,
285+ headers : {
286+ 'set-cookie' : 'storefront_digest=digest-value; path=/; HttpOnly' ,
287+ location : 'https://example-store.myshopify.com/' ,
288+ } ,
289+ } ) ,
290+ )
291+
292+ // When
293+ const cookies = await getStorefrontSessionCookies (
294+ 'https://example-store.myshopify.com' ,
295+ 'example-store.myshopify.com' ,
296+ '123456' ,
297+ 'password' ,
298+ )
299+
300+ // Then
301+ expect ( cookies ) . toEqual ( {
302+ _shopify_essential : ':AABBCCDDEEFFGGHH==123:' ,
303+ storefront_digest : 'digest-value' ,
304+ } )
305+ } )
306+
307+ test ( 'throws error when pasword page does not return a 302' , async ( ) => {
308+ // Given: password redirects correctly but _shopify_essential doesn't change (shouldn't happen)
309+ const sameEssential = ':AABBCCDDEEFFGGHH==123:'
310+
311+ vi . mocked ( shopifyFetch )
312+ . mockResolvedValueOnce (
313+ response ( {
314+ status : 200 ,
315+ headers : { 'set-cookie' : `_shopify_essential=${ sameEssential } ; path=/; HttpOnly` } ,
316+ } ) ,
317+ )
318+ . mockResolvedValueOnce (
319+ response ( {
320+ status : 200 ,
321+ } ) ,
322+ )
323+
324+ // When
325+ const cookies = getStorefrontSessionCookies (
326+ 'https://example-store.myshopify.com' ,
327+ 'example-store.myshopify.com' ,
328+ '123456' ,
329+ 'password' ,
330+ )
331+
332+ // Then
333+ await expect ( cookies ) . rejects . toThrow (
334+ new AbortError (
335+ 'Your development session could not be created because the store password is invalid. Please, retry with a different password.' ,
336+ ) ,
337+ )
338+ } )
180339 } )
181340
182341 // Tests rely on this function because the 'packages/theme' package cannot
0 commit comments