From 7087a06c6d02f974a89d5505308e8577dcb71dc2 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Tue, 2 Jan 2024 15:37:19 +0000 Subject: [PATCH] fix(nuxt): clone cookie to detect changes within object (#25007) --- packages/nuxt/src/app/composables/cookie.ts | 3 ++- test/basic.test.ts | 16 ++++++++++++++-- test/fixtures/basic/pages/cookies.vue | 8 ++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/nuxt/src/app/composables/cookie.ts b/packages/nuxt/src/app/composables/cookie.ts index 15c96c6f40..b030bfcf6f 100644 --- a/packages/nuxt/src/app/composables/cookie.ts +++ b/packages/nuxt/src/app/composables/cookie.ts @@ -6,6 +6,7 @@ import { deleteCookie, getCookie, getRequestHeader, setCookie } from 'h3' import type { H3Event } from 'h3' import destr from 'destr' import { isEqual } from 'ohash' +import { klona } from 'klona' import { useNuxtApp } from '../nuxt' import { useRequestEvent } from './ssr' @@ -44,7 +45,7 @@ export function useCookie (name: string, _opts?: } const hasExpired = delay !== undefined && delay <= 0 - const cookieValue = hasExpired ? undefined : (cookies[name] as any) ?? opts.default?.() + const cookieValue = klona(hasExpired ? undefined : (cookies[name] as any) ?? opts.default?.()) // use a custom ref to expire the cookie on client side otherwise use basic ref const cookie = import.meta.client && delay && !hasExpired diff --git a/test/basic.test.ts b/test/basic.test.ts index 6c45e2750c..d0d1d88645 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -489,7 +489,19 @@ describe('nuxt composables', () => { } }) const cookies = res.headers.get('set-cookie') - expect(cookies).toMatchInlineSnapshot('"set-in-plugin=true; Path=/, set=set; Path=/, browser-set=set; Path=/, browser-set-to-null=; Max-Age=0; Path=/, browser-set-to-null-with-default=; Max-Age=0; Path=/"') + expect(cookies).toMatchInlineSnapshot('"set-in-plugin=true; Path=/, set=set; Path=/, browser-set=set; Path=/, browser-set-to-null=; Max-Age=0; Path=/, browser-set-to-null-with-default=; Max-Age=0; Path=/, browser-object-default=%7B%22foo%22%3A%22bar%22%7D; Path=/"') + }) + it('updates cookies when they are changed', async () => { + const { page } = await renderPage('/cookies') + async function extractCookie () { + const cookie = await page.evaluate(() => document.cookie) + const raw = cookie.match(/browser-object-default=([^;]*)/)![1] ?? 'null' + return JSON.parse(decodeURIComponent(raw)) + } + expect(await extractCookie()).toEqual({ foo: 'bar' }) + await page.getByRole('button').click() + expect(await extractCookie()).toEqual({ foo: 'baz' }) + await page.close() }) }) @@ -1462,7 +1474,7 @@ describe('server components/islands', () => { const islandRequest = page.waitForResponse(response => response.url().includes('/__nuxt_island/') && response.status() === 200) await page.locator('#increase-pure-component').click() await islandRequest - + await page.locator('#slot-in-server').getByText('Slot with in .server component').waitFor() await page.locator('#test-slot').getByText('Slot with name test').waitFor() diff --git a/test/fixtures/basic/pages/cookies.vue b/test/fixtures/basic/pages/cookies.vue index 45c67460df..7c14eed8ba 100644 --- a/test/fixtures/basic/pages/cookies.vue +++ b/test/fixtures/basic/pages/cookies.vue @@ -10,10 +10,18 @@ useCookie('browser-accessed-with-default-value', () => 'default') useCookie('browser-set').value = 'set' useCookie('browser-set-to-null').value = null useCookie('browser-set-to-null-with-default', () => 'default').value = null + +const objectCookie = useCookie('browser-object-default', { + default: () => ({ foo: 'bar' }) +})