fix(nuxt): clone cookie to detect changes within object (#25007)

This commit is contained in:
Daniel Roe 2024-01-02 15:37:19 +00:00 committed by GitHub
parent 2bda817eaf
commit 7087a06c6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 24 additions and 3 deletions

View File

@ -6,6 +6,7 @@ import { deleteCookie, getCookie, getRequestHeader, setCookie } from 'h3'
import type { H3Event } from 'h3' import type { H3Event } from 'h3'
import destr from 'destr' import destr from 'destr'
import { isEqual } from 'ohash' import { isEqual } from 'ohash'
import { klona } from 'klona'
import { useNuxtApp } from '../nuxt' import { useNuxtApp } from '../nuxt'
import { useRequestEvent } from './ssr' import { useRequestEvent } from './ssr'
@ -44,7 +45,7 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
} }
const hasExpired = delay !== undefined && delay <= 0 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 // use a custom ref to expire the cookie on client side otherwise use basic ref
const cookie = import.meta.client && delay && !hasExpired const cookie = import.meta.client && delay && !hasExpired

View File

@ -489,7 +489,19 @@ describe('nuxt composables', () => {
} }
}) })
const cookies = res.headers.get('set-cookie') 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()
}) })
}) })

View File

@ -10,10 +10,18 @@ useCookie('browser-accessed-with-default-value', () => 'default')
useCookie('browser-set').value = 'set' useCookie('browser-set').value = 'set'
useCookie('browser-set-to-null').value = null useCookie('browser-set-to-null').value = null
useCookie('browser-set-to-null-with-default', () => 'default').value = null useCookie('browser-set-to-null-with-default', () => 'default').value = null
const objectCookie = useCookie('browser-object-default', {
default: () => ({ foo: 'bar' })
})
</script> </script>
<template> <template>
<div> <div>
<div>cookies testing page</div> <div>cookies testing page</div>
<pre>{{ objectCookie }}</pre>
<button @click="objectCookie.foo = 'baz'">
Change cookie
</button>
</div> </div>
</template> </template>