@shopbite-de/storefront 1.18.1 → 1.18.3

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.
Files changed (31) hide show
  1. package/app/app.vue +3 -9
  2. package/app/components/Cart/Item.vue +5 -5
  3. package/app/components/Category/Listing.vue +141 -92
  4. package/app/components/Checkout/DeliveryTimeSelect.vue +8 -6
  5. package/app/components/Checkout/PaymentAndDelivery.vue +31 -33
  6. package/app/components/Checkout/PaymentMethod.vue +1 -1
  7. package/app/components/Checkout/ShippingMethod.vue +1 -1
  8. package/app/components/Checkout/Summary.vue +37 -48
  9. package/app/components/Header/Right.vue +3 -3
  10. package/app/components/Header/Title.vue +7 -14
  11. package/app/components/Header.vue +2 -2
  12. package/app/components/ImageGallery.vue +26 -13
  13. package/app/components/Product/Card.vue +13 -11
  14. package/app/components/Product/CardSkeleton.vue +26 -0
  15. package/app/components/Product/{Detail2.vue → Detail.vue} +1 -1
  16. package/app/components/User/Detail.vue +2 -2
  17. package/app/composables/useShopBiteConfig.ts +5 -20
  18. package/app/pages/bestellung/bestaetigen.vue +14 -0
  19. package/app/pages/bestellung/warenkorb.vue +49 -0
  20. package/app/pages/bestellung/zahlung-versand.vue +23 -0
  21. package/app/pages/bestellung.vue +36 -84
  22. package/app/pages/index.vue +1 -1
  23. package/app/pages/kontakt.vue +1 -1
  24. package/app/pages/speisekarte/[...all].vue +1 -0
  25. package/app/stores/checkout.ts +22 -0
  26. package/nuxt.config.ts +5 -0
  27. package/package.json +3 -1
  28. package/test/e2e/simple-checkout-as-recurring-customer.test.ts +8 -8
  29. package/test/nuxt/useShopBiteConfig.test.ts +16 -20
  30. package/test/nuxt/HeaderTitle.test.ts +0 -42
  31. /package/app/components/Product/{Configurator2.vue → Configurator.vue} +0 -0
@@ -26,19 +26,32 @@ defineProps<{
26
26
  :links="links"
27
27
  >
28
28
  <template #body>
29
- <UCarousel
30
- v-slot="{ item, index }"
31
- arrows
32
- :items="images"
33
- class="w-full max-w-2xl mx-auto"
34
- >
35
- <img
36
- :src="item.image"
37
- :alt="item.alt"
38
- :fetchpriority="index === 0 ? 'high' : 'auto'"
39
- class="rounded-lg"
40
- />
41
- </UCarousel>
29
+ <ClientOnly>
30
+ <UCarousel
31
+ v-slot="{ item, index }"
32
+ arrows
33
+ :items="images"
34
+ class="w-full max-w-2xl mx-auto"
35
+ >
36
+ <img
37
+ :src="item.image"
38
+ :alt="item.alt"
39
+ :fetchpriority="index === 0 ? 'high' : 'auto'"
40
+ class="rounded-lg"
41
+ />
42
+ </UCarousel>
43
+ <template #fallback>
44
+ <div class="w-full max-w-2xl mx-auto">
45
+ <img
46
+ v-if="images?.[0]"
47
+ :src="images[0].image"
48
+ :alt="images[0].alt"
49
+ fetchpriority="high"
50
+ class="rounded-lg"
51
+ />
52
+ </div>
53
+ </template>
54
+ </ClientOnly>
42
55
  </template>
43
56
  </UPageSection>
44
57
  </template>
@@ -81,7 +81,7 @@ function onVariantSelected(variant: Schemas["Product"]) {
81
81
  :ui="{ footer: 'w-full', root: 'shadow-lg' }"
82
82
  >
83
83
  <template #header>
84
- <UBadge
84
+ <LazyUBadge
85
85
  v-if="isVegi"
86
86
  icon="i-lucide-leaf"
87
87
  color="success"
@@ -92,7 +92,7 @@ function onVariantSelected(variant: Schemas["Product"]) {
92
92
  </template>
93
93
 
94
94
  <div v-if="product.cover?.media?.url">
95
- <NuxtImg
95
+ <LazyNuxtImg
96
96
  :src="product.cover.media.url"
97
97
  class="rounded-md h-auto max-w-full object-contain ransition-opacity duration-700"
98
98
  sizes="(min-width: 1024px) 50vw, 100vw"
@@ -138,15 +138,17 @@ function onVariantSelected(variant: Schemas["Product"]) {
138
138
  />
139
139
  </div>
140
140
  </div>
141
- <UCollapsible v-model:open="openDetails" class="flex flex-col gap-2">
142
- <template #content>
143
- <ProductDetail2
144
- :product-id="product.id"
145
- @product-added="toggleDetails"
146
- @variant-selected="onVariantSelected"
147
- />
148
- </template>
149
- </UCollapsible>
141
+ <ClientOnly>
142
+ <UCollapsible v-model:open="openDetails" class="flex flex-col gap-2">
143
+ <template #content>
144
+ <LazyProductDetail
145
+ :product-id="product.id"
146
+ @product-added="toggleDetails"
147
+ @variant-selected="onVariantSelected"
148
+ />
149
+ </template>
150
+ </UCollapsible>
151
+ </ClientOnly>
150
152
  </template>
151
153
  </UPageCard>
152
154
  </AnimatedSection>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <div
3
+ class="ring-1 ring-accented rounded-xl shadow-lg p-4 flex flex-row gap-4"
4
+ >
5
+ <div class="flex flex-col gap-3 flex-1 min-w-0">
6
+ <USkeleton class="h-5 w-20 rounded-full" />
7
+ <div class="flex items-baseline gap-2">
8
+ <USkeleton class="h-3.5 w-7" />
9
+ <USkeleton class="h-3.5 w-36" />
10
+ </div>
11
+ <div class="flex flex-col gap-2">
12
+ <USkeleton class="h-3 w-full" />
13
+ <USkeleton class="h-3 w-5/6" />
14
+ <USkeleton class="h-3 w-1/2" />
15
+ </div>
16
+ <div class="flex justify-between items-center mt-auto pt-2">
17
+ <USkeleton class="h-4 w-14" />
18
+ <div class="flex gap-2">
19
+ <USkeleton class="h-8 w-8 rounded-md" />
20
+ <USkeleton class="h-8 w-8 rounded-md" />
21
+ </div>
22
+ </div>
23
+ </div>
24
+ <USkeleton class="size-28 rounded-md shrink-0" />
25
+ </div>
26
+ </template>
@@ -142,7 +142,7 @@ watch(productDetails, () => {
142
142
  <template>
143
143
  <div v-if="!pending">
144
144
  <div v-if="productDetails?.configurator">
145
- <ProductConfigurator2
145
+ <ProductConfigurator
146
146
  v-if="productDetails?.configurator"
147
147
  :p="productDetails.product"
148
148
  :c="productDetails.configurator"
@@ -47,7 +47,7 @@ onMounted(() => {
47
47
  </script>
48
48
 
49
49
  <template>
50
- <div class="shadow-md rounded-md mb-4 p-6 bg-elevated">
50
+ <UCard class="mb-4">
51
51
  <div>{{ fullName }}</div>
52
52
  <div>{{ user?.email }}</div>
53
53
  <USeparator
@@ -76,5 +76,5 @@ onMounted(() => {
76
76
  :with-edit-button="withEditButton"
77
77
  @update:address="handleAddressUpdate"
78
78
  />
79
- </div>
79
+ </UCard>
80
80
  </template>
@@ -1,31 +1,16 @@
1
- import { useContext, useShopwareContext } from "#imports";
2
- import type { Schemas } from "#shopware";
3
-
4
- type useShopBiteConfigReturn = {
5
- deliveryTime: ComputedRef<number>;
6
- isCheckoutEnabled: ComputedRef<boolean>;
7
- refresh(): Promise<Schemas["ShopBiteConfig"]>;
8
- };
9
-
10
- export function useShopBiteConfig(): useShopBiteConfigReturn {
1
+ export function useShopBiteConfig() {
11
2
  const { apiClient } = useShopwareContext();
12
3
 
13
- const _deliveryTime = useContext<number>("deliveryTime");
14
- const _isCheckoutEnabled = useContext<boolean>("isCheckoutActive");
15
-
16
- async function refresh(): Promise<Schemas["ShopBiteConfig"]> {
4
+ const { data, refresh } = useAsyncData("shopbite-config", async () => {
17
5
  const { data } = await apiClient.invoke(
18
6
  "shopbite.config.get get /shopbite/config",
19
7
  );
20
- _deliveryTime.value = data.deliveryTime;
21
- _isCheckoutEnabled.value = data.isCheckoutEnabled;
22
-
23
8
  return data;
24
- }
9
+ });
25
10
 
26
11
  return {
27
- deliveryTime: computed(() => _deliveryTime.value),
28
- isCheckoutEnabled: computed(() => _isCheckoutEnabled.value),
12
+ deliveryTime: computed(() => data.value?.deliveryTime ?? 30),
13
+ isCheckoutEnabled: computed(() => data.value?.isCheckoutEnabled ?? false),
29
14
  refresh,
30
15
  };
31
16
  }
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ const { isLoggedIn, isGuestSession } = useUser();
3
+ const { setStep } = useCheckoutStore();
4
+
5
+ if (!isLoggedIn.value && !isGuestSession.value) {
6
+ await navigateTo("/bestellung/warenkorb");
7
+ }
8
+
9
+ setStep(2);
10
+ </script>
11
+
12
+ <template>
13
+ <CheckoutSummary />
14
+ </template>
@@ -0,0 +1,49 @@
1
+ <script setup lang="ts">
2
+ import LoginOrRegister from "~/components/Checkout/LoginOrRegister.vue";
3
+
4
+ const { isLoggedIn, isGuestSession } = useUser();
5
+ const { isEmpty } = useCart();
6
+ const { setStep } = useCheckoutStore();
7
+
8
+ setStep(0);
9
+
10
+ const isCustomerAvailable = computed<boolean>(() => {
11
+ return isLoggedIn.value || isGuestSession.value;
12
+ });
13
+ </script>
14
+
15
+ <template>
16
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-8 py-8">
17
+ <div class="flex flex-col gap-4">
18
+ <h2 class="text-lg font-semibold">
19
+ {{ isCustomerAvailable ? "Deine Daten" : "Anmelden oder registrieren" }}
20
+ </h2>
21
+ <LoginOrRegister v-if="!isLoggedIn && !isGuestSession" />
22
+ <UserDetail v-else :with-edit-button="true" />
23
+ </div>
24
+
25
+ <div class="flex flex-col gap-4">
26
+ <h2 class="text-lg font-semibold">Warenkorb</h2>
27
+ <UCard>
28
+ <CartQuickView />
29
+ </UCard>
30
+ <UButton
31
+ v-if="!isEmpty && isCustomerAvailable"
32
+ label="Zahlungs- und Versandart auswählen"
33
+ size="xl"
34
+ block
35
+ trailing-icon="i-lucide-arrow-right"
36
+ to="/bestellung/zahlung-versand"
37
+ />
38
+ <UButton
39
+ v-if="isEmpty"
40
+ label="Zur Speisekarte"
41
+ size="xl"
42
+ block
43
+ variant="outline"
44
+ icon="i-lucide-arrow-left"
45
+ to="/speisekarte"
46
+ />
47
+ </div>
48
+ </div>
49
+ </template>
@@ -0,0 +1,23 @@
1
+ <script setup lang="ts">
2
+ const { isLoggedIn, isGuestSession } = useUser();
3
+ const { setStep } = useCheckoutStore();
4
+
5
+ if (!isLoggedIn.value && !isGuestSession.value) {
6
+ await navigateTo("/bestellung/warenkorb");
7
+ }
8
+
9
+ setStep(1);
10
+ </script>
11
+
12
+ <template>
13
+ <div class="flex flex-col gap-8 py-8">
14
+ <CheckoutPaymentAndDelivery />
15
+ <UButton
16
+ label="Weiter zu Prüfen & Bestellen"
17
+ trailing-icon="i-lucide-arrow-right"
18
+ size="xl"
19
+ block
20
+ to="/bestellung/bestaetigen"
21
+ />
22
+ </div>
23
+ </template>
@@ -1,95 +1,47 @@
1
1
  <script setup lang="ts">
2
- import LoginOrRegister from "~/components/Checkout/LoginOrRegister.vue";
3
2
  import type { StepperItem } from "@nuxt/ui";
4
3
 
5
- const { isLoggedIn, isGuestSession } = useUser();
6
- const { isEmpty } = useCart();
4
+ const checkoutStore = useCheckoutStore();
5
+ const { step } = storeToRefs(checkoutStore);
7
6
 
8
- const items = [
9
- {
10
- slot: "user" as const,
11
- title: "Deine Daten",
12
- icon: "i-lucide-user",
13
- },
14
- {
15
- slot: "shipping" as const,
16
- title: "Zahlung & Versand",
17
- icon: "i-lucide-truck",
18
- },
19
- {
20
- slot: "checkout" as const,
21
- title: "Prüfen & Bestellen",
22
- icon: "i-lucide-check",
23
- },
24
- ] satisfies StepperItem[];
7
+ const stepRoutes = [
8
+ "/bestellung/warenkorb",
9
+ "/bestellung/zahlung-versand",
10
+ "/bestellung/bestaetigen",
11
+ ] as const;
25
12
 
26
- const activeStep = ref(0);
13
+ const items = computed(
14
+ () =>
15
+ [
16
+ {
17
+ title: "Warenkorb",
18
+ icon: "i-lucide-shopping-cart",
19
+ disabled: false,
20
+ },
21
+ {
22
+ title: "Zahlung & Versand",
23
+ icon: "i-lucide-truck",
24
+ disabled: step.value < 1,
25
+ },
26
+ {
27
+ title: "Prüfen & Bestellen",
28
+ icon: "i-lucide-check",
29
+ disabled: step.value < 2,
30
+ },
31
+ ] satisfies StepperItem[],
32
+ );
27
33
 
28
- const isCustomerAvailable = computed<boolean>(() => {
29
- return isLoggedIn.value || isGuestSession.value;
34
+ watch(step, (newStep) => {
35
+ navigateTo(stepRoutes[newStep]);
30
36
  });
31
37
  </script>
32
38
 
33
39
  <template>
34
- <UContainer>
35
- <UPageHeader title="Bestellung aufgeben" />
36
- <UPageBody>
37
- <UStepper v-model="activeStep" :items="items">
38
- <template #user>
39
- <div class="flex flex-col md:flex-row w-full gap-18 my-16">
40
- <LoginOrRegister
41
- v-if="!isLoggedIn && !isGuestSession"
42
- class="basis-1/2"
43
- />
44
- <div v-else class="basis-1/2">
45
- <UserDetail :with-edit-button="true" />
46
- </div>
47
- <div class="basis-1/2">
48
- <h3 class="text-2xl mb-6 font-semibold">Warenkorb</h3>
49
- <CartQuickView />
50
- <UButton
51
- v-if="!isEmpty && isCustomerAvailable"
52
- :disabled="!isLoggedIn && !isGuestSession"
53
- label="Zahlungs- und Versandart auswählen"
54
- size="xl"
55
- block
56
- trailing-icon="i-lucide-arrow-right"
57
- class="my-4"
58
- @click="activeStep = 1"
59
- />
60
- <UButton
61
- v-if="isEmpty"
62
- label="Zur Speisekarte"
63
- size="xl"
64
- block
65
- icon="i-lucide-arrow-left"
66
- class="my-4"
67
- to="/speisekarte"
68
- />
69
- </div>
70
- </div>
71
- </template>
72
-
73
- <template #shipping>
74
- <div class="my-14">
75
- <CheckoutPaymentAndDelivery />
76
- <div class="w-full flex justify-end">
77
- <UButton
78
- label="Weiter zu Prüfen & Bestellen"
79
- trailing-icon="i-lucide-arrow-right"
80
- class="m-8 md:max-w-96"
81
- size="xl"
82
- block
83
- @click="activeStep = 2"
84
- />
85
- </div>
86
- </div>
87
- </template>
88
-
89
- <template #checkout>
90
- <CheckoutSummary />
91
- </template>
92
- </UStepper>
93
- </UPageBody>
94
- </UContainer>
40
+ <UPageSection>
41
+ <UStepper ref="stepper" v-model="step" :items="items" size="lg">
42
+ <template #content>
43
+ <NuxtPage />
44
+ </template>
45
+ </UStepper>
46
+ </UPageSection>
95
47
  </template>
@@ -47,7 +47,7 @@ useSeoMeta({
47
47
 
48
48
  <USeparator :ui="{ border: 'border-primary/30' }" />
49
49
 
50
- <FoodMarquee
50
+ <LazyFoodMarquee
51
51
  v-if="page.marquee.items?.length > 0"
52
52
  :title="page.marquee.title"
53
53
  :description="page.marquee.description"
@@ -13,7 +13,7 @@ if (config.public.shopBite.feature.contactForm !== true) {
13
13
 
14
14
  <template>
15
15
  <UPageSection
16
- title="Sie haben eine Frage oder Anregung?Wir freuen uns auf Ihre Nachricht."
16
+ title="Sie haben eine Frage oder Anregung? Wir freuen uns auf Ihre Nachricht."
17
17
  description="Bitte beachten Sie, dass wir Tischreservierung oder Tischstornierung nur telefonisch entgegennehmen können."
18
18
  icon="i-lucide-mail"
19
19
  orientation="horizontal"
@@ -1,3 +1,4 @@
1
+ H
1
2
  <script setup lang="ts">
2
3
  import type { Schemas } from "#shopware";
3
4
 
@@ -0,0 +1,22 @@
1
+ const stepRoutes = [
2
+ "/bestellung/warenkorb",
3
+ "/bestellung/zahlung-versand",
4
+ "/bestellung/bestaetigen",
5
+ ] as const;
6
+
7
+ export const useCheckoutStore = defineStore("checkout", () => {
8
+ const step = ref(0);
9
+
10
+ function setStep(index: number) {
11
+ step.value = index;
12
+ }
13
+
14
+ async function navigateToStep(index: number) {
15
+ if (index < 0 || index >= stepRoutes.length) return;
16
+ if (index <= step.value) {
17
+ await navigateTo(stepRoutes[index]);
18
+ }
19
+ }
20
+
21
+ return { step, setStep, navigateToStep };
22
+ });
package/nuxt.config.ts CHANGED
@@ -78,6 +78,9 @@ export default defineNuxtConfig({
78
78
  "/registrierung/bestaetigen": {
79
79
  ssr: false,
80
80
  },
81
+ "/bestellung": {
82
+ redirect: "/bestellung/warenkorb",
83
+ },
81
84
  },
82
85
 
83
86
  css: ["~/assets/css/main.css"],
@@ -100,6 +103,7 @@ export default defineNuxtConfig({
100
103
  "@nuxt/scripts",
101
104
  "nuxt-vitalizer",
102
105
  "@nuxt/eslint",
106
+ "@pinia/nuxt",
103
107
  ],
104
108
 
105
109
  content: {
@@ -197,6 +201,7 @@ export default defineNuxtConfig({
197
201
  "@nuxt/scripts",
198
202
  "@nuxt/test-utils/module",
199
203
  "@nuxt/eslint",
204
+ "@nuxt/hints",
200
205
  ],
201
206
  },
202
207
  $production: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopbite-de/storefront",
3
- "version": "1.18.1",
3
+ "version": "1.18.3",
4
4
  "main": "nuxt.config.ts",
5
5
  "description": "Shopware storefront for food delivery shops",
6
6
  "keywords": [
@@ -27,6 +27,7 @@
27
27
  "@nuxt/scripts": "0.13.2",
28
28
  "@nuxt/ui": "^4.5.1",
29
29
  "@nuxtjs/robots": "^6.0.0",
30
+ "@pinia/nuxt": "0.11.3",
30
31
  "@sentry/nuxt": "^10.43.0",
31
32
  "@shopware/api-client": "^1.4.0",
32
33
  "@shopware/api-gen": "^1.4.0",
@@ -43,6 +44,7 @@
43
44
  "uuid": "^13.0.0"
44
45
  },
45
46
  "devDependencies": {
47
+ "@nuxt/hints": "1.0.2",
46
48
  "@iconify-json/heroicons": "^1.2.3",
47
49
  "@iconify-json/hugeicons": "^1.2.23",
48
50
  "@nuxt/devtools-kit": "^3.2.3",
@@ -39,7 +39,7 @@ async function clearCart(page: Page) {
39
39
  await expect(page.getByRole("heading", { name: /warenkorb/i })).toBeVisible();
40
40
 
41
41
  const deleteButtons = page.getByRole("button", {
42
- name: "Remove item from cart",
42
+ name: "Artikel entfernen",
43
43
  });
44
44
  const itemCount = await deleteButtons.count();
45
45
 
@@ -92,7 +92,7 @@ async function selectProductAndAddToCart(
92
92
  }
93
93
 
94
94
  async function proceedToCheckoutAndLogin(page: Page) {
95
- await page.goto("/bestellung", { waitUntil: "load" });
95
+ await page.goto("/bestellung/warenkorb", { waitUntil: "load" });
96
96
 
97
97
  const loginTab = page.getByRole("tab", { name: "Einloggen" });
98
98
  await expect(loginTab).toBeVisible();
@@ -129,7 +129,7 @@ async function proceedToCheckoutAndLogin(page: Page) {
129
129
 
130
130
  // Wait for login to complete and navigate back to checkout
131
131
  await page.waitForTimeout(2000);
132
- await page.goto("/bestellung", { waitUntil: "load" });
132
+ await page.goto("/bestellung/zahlung-versand", { waitUntil: "load" });
133
133
  await page.waitForTimeout(1000);
134
134
 
135
135
  // Skip the rest of this function since we already logged in
@@ -159,15 +159,15 @@ async function proceedToCheckoutAndLogin(page: Page) {
159
159
 
160
160
  async function verifyCheckoutQuantity(page: Page) {
161
161
  // Ensure we're on the checkout page
162
- if (!page.url().includes("/bestellung")) {
163
- await page.goto("/bestellung", { waitUntil: "load" });
162
+ if (!page.url().includes("/bestellung/warenkorb")) {
163
+ await page.goto("/bestellung/warenkorb", { waitUntil: "load" });
164
164
  await page.waitForTimeout(1000);
165
165
  }
166
166
 
167
167
  // Try to find the quantity input with multiple strategies
168
168
  const checkoutQuantityInput = page
169
169
  .getByRole("spinbutton", {
170
- name: /item quantity/i,
170
+ name: /menge/i,
171
171
  })
172
172
  .or(page.getByRole("spinbutton"))
173
173
  .or(page.locator("input[type='number']"));
@@ -178,7 +178,7 @@ async function verifyCheckoutQuantity(page: Page) {
178
178
  }
179
179
 
180
180
  async function selectPaymentAndShipping(page: Page) {
181
- const nextStepButton = page.getByRole("button", {
181
+ const nextStepButton = page.getByRole("link", {
182
182
  name: "Zahlungs- und Versandart auswählen",
183
183
  });
184
184
  await expect(nextStepButton).toBeVisible({ timeout: 10000 });
@@ -197,7 +197,7 @@ async function selectPaymentAndShipping(page: Page) {
197
197
  }
198
198
 
199
199
  async function proceedToOrderReview(page: Page) {
200
- const lastStepButton = page.getByRole("button", {
200
+ const lastStepButton = page.getByRole("link", {
201
201
  name: "Weiter zu Prüfen & Bestellen",
202
202
  });
203
203
  await expect(lastStepButton).toBeVisible({ timeout: 10000 });
@@ -1,14 +1,11 @@
1
1
  import { describe, it, expect, vi, beforeEach } from "vitest";
2
2
  import { mockNuxtImport } from "@nuxt/test-utils/runtime";
3
+ import { ref } from "vue";
3
4
  import { useShopBiteConfig } from "~/composables/useShopBiteConfig";
4
5
 
5
- const { mockInvoke, mockDeliveryTime, mockIsCheckoutEnabled } = vi.hoisted(
6
- () => ({
7
- mockInvoke: vi.fn(),
8
- mockDeliveryTime: { value: 0 },
9
- mockIsCheckoutEnabled: { value: false },
10
- }),
11
- );
6
+ const { mockInvoke } = vi.hoisted(() => ({
7
+ mockInvoke: vi.fn(),
8
+ }));
12
9
 
13
10
  mockNuxtImport("useShopwareContext", () => () => ({
14
11
  apiClient: {
@@ -16,25 +13,26 @@ mockNuxtImport("useShopwareContext", () => () => ({
16
13
  },
17
14
  }));
18
15
 
19
- mockNuxtImport("useContext", () => (key: string) => {
20
- if (key === "deliveryTime") return mockDeliveryTime;
21
- if (key === "isCheckoutActive") return mockIsCheckoutEnabled;
22
- return { value: null };
23
- });
16
+ mockNuxtImport(
17
+ "useAsyncData",
18
+ () => (_key: string, fetcher: () => Promise<unknown>) => {
19
+ const data = ref<unknown>(null);
20
+ const refresh = async () => {
21
+ data.value = await fetcher();
22
+ };
23
+ return { data, refresh };
24
+ },
25
+ );
24
26
 
25
27
  describe("useShopBiteConfig", () => {
26
28
  beforeEach(() => {
27
29
  vi.clearAllMocks();
28
- mockDeliveryTime.value = 0;
29
- mockIsCheckoutEnabled.value = false;
30
30
  });
31
31
 
32
- it("should initialize with values from context", () => {
33
- mockDeliveryTime.value = 30;
34
- mockIsCheckoutEnabled.value = true;
32
+ it("should return default values when no data is loaded", () => {
35
33
  const { deliveryTime, isCheckoutEnabled } = useShopBiteConfig();
36
34
  expect(deliveryTime.value).toBe(30);
37
- expect(isCheckoutEnabled.value).toBe(true);
35
+ expect(isCheckoutEnabled.value).toBe(false);
38
36
  });
39
37
 
40
38
  it("should refresh values from API", async () => {
@@ -53,7 +51,5 @@ describe("useShopBiteConfig", () => {
53
51
  );
54
52
  expect(deliveryTime.value).toBe(45);
55
53
  expect(isCheckoutEnabled.value).toBe(true);
56
- expect(mockDeliveryTime.value).toBe(45);
57
- expect(mockIsCheckoutEnabled.value).toBe(true);
58
54
  });
59
55
  });