fix(nuxt): handle deleted cookies from CookieStore events (#28760)

This commit is contained in:
Eckhardt (Kaizen) Dreyer 2024-08-30 15:37:19 +02:00 committed by GitHub
parent 77e36ee274
commit c8cff9be54
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 80 additions and 3 deletions

View File

@ -103,9 +103,18 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
}
if (store) {
/* event is of type CookieChangeEvent */
const changeHandler = (event: any) => {
const cookie = event.changed.find((c: any) => c.name === name)
if (cookie) { handleChange({ value: cookie.value }) }
const changedCookie = event.changed.find((c: any) => c.name === name)
const removedCookie = event.deleted.find((c: any) => c.name === name)
if (changedCookie) {
handleChange({ value: changedCookie.value })
}
if (removedCookie) {
handleChange({ value: null })
}
}
store.addEventListener('change', changeHandler)
if (hasScope) {

View File

@ -640,7 +640,7 @@ describe('nuxt composables', () => {
},
})
const cookies = res.headers.get('set-cookie')
expect(cookies).toMatchInlineSnapshot('"set-in-plugin=true; Path=/, accessed-with-default-value=default; 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=/"')
expect(cookies).toMatchInlineSnapshot('"set-in-plugin=true; Path=/, accessed-with-default-value=default; 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=/, theCookie=show; Path=/"')
})
it('updates cookies when they are changed', async () => {
const { page } = await renderPage('/cookies')
@ -663,6 +663,26 @@ describe('nuxt composables', () => {
await page.close()
})
it('sets cookies in composable to null in all components', async () => {
const { page } = await renderPage('/cookies')
const parentBannerText = await page.locator('#parent-banner').textContent()
expect(parentBannerText).toContain('parent banner')
const childBannerText = await page.locator('#child-banner').innerText()
expect(childBannerText).toContain('child banner')
// Clear the composable cookie
await page.getByText('Toggle cookie banner').click()
await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 10)))
const parentBannerAfterToggle = await page.locator('#parent-banner').isVisible()
expect(parentBannerAfterToggle).toBe(false)
const childBannerAfterToggle = await page.locator('#child-banner').isVisible()
expect(childBannerAfterToggle).toBe(false)
await page.close()
})
it('supports onPrehydrate', async () => {
const html = await $fetch<string>('/composables/on-prehydrate') as string
/**

View File

@ -0,0 +1,14 @@
<script setup>
import { useCookieManager } from '../composables/cookie-manager'
const { showCookieBanner } = useCookieManager()
</script>
<template>
<div
v-if="showCookieBanner"
id="child-banner"
>
child banner
</div>
</template>

View File

@ -0,0 +1,18 @@
export function useCookieManager () {
const theCookie = useCookie<null | string>('theCookie', {
default: () => 'show',
})
const showCookieBanner = computed(() => {
return theCookie.value === 'show'
})
function toggle () {
theCookie.value = theCookie.value === 'show' ? null : 'show'
}
return {
showCookieBanner,
toggle,
}
}

View File

@ -1,4 +1,7 @@
<script setup lang="ts">
import CookieComponent from '../components/ComponentUsingCookie.vue'
import { useCookieManager } from '../composables/cookie-manager'
useCookie('accessed-but-not-used')
useCookie('accessed-with-default-value', { default: () => 'default' })
useCookie('set').value = 'set'
@ -25,6 +28,8 @@ function changeCookie () {
objectCookie.value!.foo = 'baz'
}
}
const { showCookieBanner, toggle } = useCookieManager()
</script>
<template>
@ -38,5 +43,16 @@ function changeCookie () {
<button @click="refreshCookie('browser-object-default')">
Refresh cookie
</button>
<CookieComponent />
<div
v-if="showCookieBanner"
id="parent-banner"
>
parent banner
</div>
<button @click="toggle">
Toggle cookie banner
</button>
</div>
</template>