@shopbite-de/storefront 1.2.8 → 1.3.0

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.
@@ -0,0 +1,162 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { mockNuxtImport } from "@nuxt/test-utils/runtime";
3
+
4
+ import { useAddToCart } from "../../app/composables/useAddToCart";
5
+ import { nextTick } from "vue";
6
+
7
+ // Use vi.hoisted for variables used in mocks
8
+ const {
9
+ mockAddProducts,
10
+ mockRefreshCart,
11
+ mockToastAdd,
12
+ mockTriggerProductAdded,
13
+ mockTrackEvent
14
+ } = vi.hoisted(() => ({
15
+ mockAddProducts: vi.fn(),
16
+ mockRefreshCart: vi.fn(),
17
+ mockToastAdd: vi.fn(),
18
+ mockTriggerProductAdded: vi.fn(),
19
+ mockTrackEvent: vi.fn(),
20
+ }));
21
+
22
+ mockNuxtImport("useCart", () => {
23
+ return () => ({
24
+ addProducts: mockAddProducts,
25
+ refreshCart: mockRefreshCart,
26
+ });
27
+ });
28
+
29
+ mockNuxtImport("useToast", () => {
30
+ return () => ({
31
+ add: mockToastAdd,
32
+ });
33
+ });
34
+
35
+ mockNuxtImport("useProductEvents", () => {
36
+ return () => ({
37
+ triggerProductAdded: mockTriggerProductAdded,
38
+ });
39
+ });
40
+
41
+ mockNuxtImport("useTrackEvent", () => {
42
+ return mockTrackEvent;
43
+ });
44
+
45
+ // Provide the mocks globally or in a way that they are picked up
46
+ vi.stubGlobal('useCart', () => ({
47
+ addProducts: mockAddProducts,
48
+ refreshCart: mockRefreshCart,
49
+ }));
50
+ vi.stubGlobal('useToast', () => ({
51
+ add: mockToastAdd,
52
+ }));
53
+ vi.stubGlobal('useProductEvents', () => ({
54
+ triggerProductAdded: mockTriggerProductAdded,
55
+ }));
56
+ vi.stubGlobal('useTrackEvent', mockTrackEvent);
57
+
58
+ describe("useAddToCart", () => {
59
+ const mockProduct = {
60
+ id: "product-123",
61
+ productNumber: "SW10123",
62
+ translated: {
63
+ name: "Test Pizza",
64
+ },
65
+ } as any;
66
+
67
+ beforeEach(() => {
68
+ vi.clearAllMocks();
69
+ });
70
+
71
+ it("should initialize with default values", () => {
72
+ const {
73
+ selectedProduct,
74
+ selectedExtras,
75
+ deselectedIngredients,
76
+ selectedQuantity,
77
+ isLoading,
78
+ } = useAddToCart();
79
+
80
+ expect(selectedProduct.value).toBeNull();
81
+ expect(selectedExtras.value).toEqual([]);
82
+ expect(deselectedIngredients.value).toEqual([]);
83
+ expect(selectedQuantity.value).toBe(1);
84
+ expect(isLoading.value).toBe(false);
85
+ });
86
+
87
+ it("should set selected product", () => {
88
+ const { setSelectedProduct, selectedProduct } = useAddToCart();
89
+ setSelectedProduct(mockProduct);
90
+ expect(selectedProduct.value).toEqual(mockProduct);
91
+ });
92
+
93
+ it("should generate correct cartItemLabel for simple product", async () => {
94
+ const { setSelectedProduct, cartItemLabel } = useAddToCart();
95
+ setSelectedProduct(mockProduct);
96
+ await nextTick();
97
+ expect(cartItemLabel.value).toBe("Test Pizza");
98
+ });
99
+
100
+ it("should generate correct cartItemLabel with extras and deselected ingredients", async () => {
101
+ const {
102
+ setSelectedProduct,
103
+ setSelectedExtras,
104
+ setDeselectedIngredients,
105
+ cartItemLabel,
106
+ } = useAddToCart();
107
+ setSelectedProduct(mockProduct);
108
+ setSelectedExtras([{ label: "Extra Cheese", value: "cheese" }] as any);
109
+ setDeselectedIngredients(["Onions"]);
110
+ await nextTick();
111
+ expect(cartItemLabel.value).toBe("Test Pizza +Extra Cheese -Onions");
112
+ });
113
+
114
+ it("should add simple product to cart", async () => {
115
+ const { setSelectedProduct, addToCart, isLoading } = useAddToCart();
116
+ setSelectedProduct(mockProduct);
117
+
118
+ mockAddProducts.mockResolvedValue({ id: "cart-123" });
119
+ mockRefreshCart.mockResolvedValue({});
120
+
121
+ await addToCart();
122
+
123
+ expect(isLoading.value).toBe(false);
124
+ expect(mockAddProducts).toHaveBeenCalledWith([
125
+ {
126
+ id: "product-123",
127
+ quantity: 1,
128
+ type: "product",
129
+ },
130
+ ]);
131
+ expect(mockRefreshCart).toHaveBeenCalled();
132
+ expect(mockToastAdd).toHaveBeenCalled();
133
+ expect(mockTriggerProductAdded).toHaveBeenCalled();
134
+ expect(mockTrackEvent).toHaveBeenCalledWith("add_to_cart", expect.any(Object));
135
+ });
136
+
137
+ it("should add product with extras to cart as container", async () => {
138
+ const { setSelectedProduct, setSelectedExtras, addToCart } = useAddToCart();
139
+ setSelectedProduct(mockProduct);
140
+ setSelectedExtras([{ label: "Extra Cheese", value: "cheese" }] as any);
141
+
142
+ mockAddProducts.mockResolvedValue({ id: "cart-123" });
143
+
144
+ await addToCart();
145
+
146
+ expect(mockAddProducts).toHaveBeenCalledWith([
147
+ expect.objectContaining({
148
+ type: "container",
149
+ children: expect.arrayContaining([
150
+ expect.objectContaining({
151
+ type: "product",
152
+ referencedId: "product-123",
153
+ }),
154
+ expect.objectContaining({
155
+ type: "product",
156
+ id: "cheese",
157
+ }),
158
+ ]),
159
+ }),
160
+ ]);
161
+ });
162
+ });
@@ -0,0 +1,61 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { mockNuxtImport } from "@nuxt/test-utils/runtime";
3
+ import { ref } from "vue";
4
+ import { useDeliveryTime } from "../../app/composables/useDeliveryTime";
5
+
6
+ const { mockDeliveryTime } = vi.hoisted(() => ({
7
+ mockDeliveryTime: { value: 45 }, // Use object to keep reference
8
+ }));
9
+
10
+ mockNuxtImport("usePizzaToppings", () => () => ({
11
+ deliveryTime: mockDeliveryTime,
12
+ }));
13
+
14
+ describe("useDeliveryTime", () => {
15
+ const now = ref(new Date("2023-10-27T12:00:00")); // A Friday
16
+
17
+ beforeEach(() => {
18
+ vi.clearAllMocks();
19
+ });
20
+
21
+ it("should calculate earliest selectable time", () => {
22
+ mockDeliveryTime.value = 30;
23
+ const { earliest } = useDeliveryTime(now);
24
+ // 12:00 + 30 mins = 12:30
25
+ expect(earliest.value.getHours()).toBe(12);
26
+ expect(earliest.value.getMinutes()).toBe(30);
27
+ });
28
+
29
+ it("should identify if closed today (e.g., Tuesday)", () => {
30
+ const tuesday = ref(new Date("2023-10-24T12:00:00"));
31
+ const { isClosedToday, helperText } = useDeliveryTime(tuesday);
32
+ expect(isClosedToday.value).toBe(true);
33
+ expect(helperText.value).toContain("Dienstag");
34
+ });
35
+
36
+ it("should validate valid time", () => {
37
+ const { validate, minTime, maxTime } = useDeliveryTime(now);
38
+ if (minTime.value && maxTime.value) {
39
+ expect(validate(minTime.value)).toBeNull();
40
+ }
41
+ });
42
+
43
+ it("should return error for invalid format", () => {
44
+ const { validate } = useDeliveryTime(now);
45
+ expect(validate("invalid")).toBe("Bitte eine gültige Uhrzeit im Format HH:MM eingeben.");
46
+ });
47
+
48
+ it("should return error for time before minTime", () => {
49
+ const { validate, minTime } = useDeliveryTime(now);
50
+ if (minTime.value) {
51
+ // Assuming minTime is something like "12:30"
52
+ const [hours, mins] = minTime.value.split(":").map(Number);
53
+ const earlyTime = new Date(now.value);
54
+ earlyTime.setHours(hours as number);
55
+ earlyTime.setMinutes(mins as number - 5);
56
+ const earlyTimeStr = earlyTime.getHours().toString().padStart(2, '0') + ":" + earlyTime.getMinutes().toString().padStart(2, '0');
57
+
58
+ expect(validate(earlyTimeStr)).toContain("vor dem frühestmöglichen Zeitpunkt");
59
+ }
60
+ });
61
+ });
@@ -0,0 +1,59 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { useInterval } from "../../app/composables/useInterval";
3
+ import { mount } from "@vue/test-utils";
4
+ import { defineComponent } from "vue";
5
+
6
+ describe("useInterval", () => {
7
+ beforeEach(() => {
8
+ vi.useFakeTimers();
9
+ });
10
+
11
+ afterEach(() => {
12
+ vi.restoreAllMocks();
13
+ vi.useRealTimers();
14
+ });
15
+
16
+ it("should start interval on mount and call callback", async () => {
17
+ const callback = vi.fn();
18
+ const TestComponent = defineComponent({
19
+ setup() {
20
+ useInterval(callback, 1000);
21
+ return {};
22
+ },
23
+ template: "<div></div>",
24
+ });
25
+
26
+ const wrapper = mount(TestComponent);
27
+
28
+ expect(callback).not.toHaveBeenCalled();
29
+
30
+ vi.advanceTimersByTime(1000);
31
+ expect(callback).toHaveBeenCalledTimes(1);
32
+
33
+ vi.advanceTimersByTime(1000);
34
+ expect(callback).toHaveBeenCalledTimes(2);
35
+
36
+ wrapper.unmount();
37
+ });
38
+
39
+ it("should clear interval on unmount", () => {
40
+ const callback = vi.fn();
41
+ const TestComponent = defineComponent({
42
+ setup() {
43
+ useInterval(callback, 1000);
44
+ return {};
45
+ },
46
+ template: "<div></div>",
47
+ });
48
+
49
+ const wrapper = mount(TestComponent);
50
+
51
+ vi.advanceTimersByTime(1000);
52
+ expect(callback).toHaveBeenCalledTimes(1);
53
+
54
+ wrapper.unmount();
55
+
56
+ vi.advanceTimersByTime(1000);
57
+ expect(callback).toHaveBeenCalledTimes(1); // Should not have increased
58
+ });
59
+ });
@@ -0,0 +1,59 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { mockNuxtImport } from "@nuxt/test-utils/runtime";
3
+ import { usePizzaToppings } from "../../app/composables/usePizzaToppings";
4
+
5
+ const {
6
+ mockInvoke,
7
+ mockDeliveryTime,
8
+ mockIsCheckoutEnabled,
9
+ } = vi.hoisted(() => ({
10
+ mockInvoke: vi.fn(),
11
+ mockDeliveryTime: { value: 0 },
12
+ mockIsCheckoutEnabled: { value: false },
13
+ }));
14
+
15
+ mockNuxtImport("useShopwareContext", () => () => ({
16
+ apiClient: {
17
+ invoke: mockInvoke,
18
+ },
19
+ }));
20
+
21
+ mockNuxtImport("useContext", () => (key: string) => {
22
+ if (key === "deliveryTime") return mockDeliveryTime;
23
+ if (key === "isCheckoutActive") return mockIsCheckoutEnabled;
24
+ return { value: null };
25
+ });
26
+
27
+ describe("usePizzaToppings", () => {
28
+ beforeEach(() => {
29
+ vi.clearAllMocks();
30
+ mockDeliveryTime.value = 0;
31
+ mockIsCheckoutEnabled.value = false;
32
+ });
33
+
34
+ it("should initialize with values from context", () => {
35
+ mockDeliveryTime.value = 30;
36
+ mockIsCheckoutEnabled.value = true;
37
+ const { deliveryTime, isCheckoutEnabled } = usePizzaToppings();
38
+ expect(deliveryTime.value).toBe(30);
39
+ expect(isCheckoutEnabled.value).toBe(true);
40
+ });
41
+
42
+ it("should refresh values from API", async () => {
43
+ mockInvoke.mockResolvedValue({
44
+ data: {
45
+ deliveryTime: 45,
46
+ isCheckoutEnabled: true
47
+ }
48
+ });
49
+
50
+ const { refresh, deliveryTime, isCheckoutEnabled } = usePizzaToppings();
51
+ await refresh();
52
+
53
+ expect(mockInvoke).toHaveBeenCalledWith("pizza-toppings.get get /pizza-toppings");
54
+ expect(deliveryTime.value).toBe(45);
55
+ expect(isCheckoutEnabled.value).toBe(true);
56
+ expect(mockDeliveryTime.value).toBe(45);
57
+ expect(mockIsCheckoutEnabled.value).toBe(true);
58
+ });
59
+ });
@@ -0,0 +1,87 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { useProductConfigurator } from "../../app/composables/useProductConfigurator";
3
+
4
+
5
+ const {
6
+ mockInvoke,
7
+ mockConfigurator,
8
+ mockProduct,
9
+ } = vi.hoisted(() => ({
10
+ mockInvoke: vi.fn(),
11
+ mockConfigurator: { value: [] },
12
+ mockProduct: { value: { id: "p1", optionIds: [], options: [] } },
13
+ }));
14
+
15
+ // Use vi.mock for explicit imports
16
+ vi.mock("@shopware/composables", () => ({
17
+ useShopwareContext: () => ({
18
+ apiClient: {
19
+ invoke: mockInvoke,
20
+ },
21
+ }),
22
+ useProductConfigurator: () => ({
23
+ handleChange: vi.fn(),
24
+ }),
25
+ useProduct: () => ({
26
+ configurator: mockConfigurator,
27
+ product: mockProduct,
28
+ }),
29
+ }));
30
+
31
+ describe("useProductConfigurator", () => {
32
+ beforeEach(() => {
33
+ vi.clearAllMocks();
34
+ mockConfigurator.value = [];
35
+ mockProduct.value = {
36
+ id: "p1",
37
+ optionIds: [],
38
+ options: []
39
+ } as any;
40
+ });
41
+
42
+ it("should initialize with selected options from product", () => {
43
+ mockConfigurator.value = [
44
+ {
45
+ id: "g1",
46
+ name: "Size",
47
+ options: [{ id: "o1", name: "Small" }]
48
+ }
49
+ ] as any;
50
+ mockProduct.value = {
51
+ id: "p1-v1",
52
+ parentId: "p1",
53
+ optionIds: ["o1"],
54
+ options: [{ id: "o1" }]
55
+ } as any;
56
+
57
+ const { isLoadingOptions } = useProductConfigurator();
58
+ expect(isLoadingOptions.value).toBe(true);
59
+ });
60
+
61
+ it("should find variant for selected options", async () => {
62
+ mockProduct.value = { parentId: "parent-1" } as any;
63
+ mockInvoke.mockResolvedValue({
64
+ data: {
65
+ elements: [{ id: "variant-1" }]
66
+ }
67
+ });
68
+
69
+ const { findVariantForSelectedOptions } = useProductConfigurator();
70
+ const result = await findVariantForSelectedOptions({ "Size": "o1" });
71
+
72
+ expect(mockInvoke).toHaveBeenCalledWith("readProduct post /product", expect.any(Object));
73
+ expect(result).toEqual({ id: "variant-1" });
74
+ });
75
+
76
+ it("should return undefined on error in findVariantForSelectedOptions", async () => {
77
+ mockInvoke.mockRejectedValue(new Error("API Error"));
78
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
79
+
80
+ const { findVariantForSelectedOptions } = useProductConfigurator();
81
+ const result = await findVariantForSelectedOptions({ "Size": "o1" });
82
+
83
+ expect(result).toBeUndefined();
84
+ expect(consoleSpy).toHaveBeenCalled();
85
+ consoleSpy.mockRestore();
86
+ });
87
+ });
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, vi } from "vitest";
2
- import { useProductEvents } from "./useProductEvents";
2
+ import { useProductEvents } from "../../app/composables/useProductEvents";
3
3
  import { nextTick } from "vue";
4
4
 
5
5
  /**
@@ -0,0 +1,89 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { useProductVariants } from "../../app/composables/useProductVariants";
3
+ import { ref } from "vue";
4
+
5
+ describe("useProductVariants", () => {
6
+ it("should return empty object when no settings provided", () => {
7
+ const settings = ref([]);
8
+ const { variants } = useProductVariants(settings as any);
9
+ expect(variants.value).toEqual({});
10
+ });
11
+
12
+ it("should group options by group id", () => {
13
+ const settings = ref([
14
+ {
15
+ option: {
16
+ id: "opt-1",
17
+ name: "Small",
18
+ group: {
19
+ id: "group-size",
20
+ name: "Size",
21
+ translated: { name: "Größe" }
22
+ },
23
+ translated: { name: "Klein" }
24
+ }
25
+ },
26
+ {
27
+ option: {
28
+ id: "opt-2",
29
+ name: "Large",
30
+ group: {
31
+ id: "group-size",
32
+ name: "Size",
33
+ translated: { name: "Größe" }
34
+ },
35
+ translated: { name: "Groß" }
36
+ }
37
+ },
38
+ {
39
+ option: {
40
+ id: "opt-3",
41
+ name: "Red",
42
+ group: {
43
+ id: "group-color",
44
+ name: "Color",
45
+ translated: { name: "Farbe" }
46
+ },
47
+ translated: { name: "Rot" }
48
+ }
49
+ }
50
+ ]);
51
+
52
+ const { variants } = useProductVariants(settings as any);
53
+
54
+ expect(variants.value["group-size"]).toBeDefined();
55
+ expect(variants.value["group-size"].name).toBe("Größe");
56
+ expect(variants.value["group-size"].options).toHaveLength(2);
57
+ expect(variants.value["group-size"].options[0]).toEqual({
58
+ label: "Klein",
59
+ value: "opt-1",
60
+ productId: "opt-1"
61
+ });
62
+
63
+ expect(variants.value["group-color"]).toBeDefined();
64
+ expect(variants.value["group-color"].name).toBe("Farbe");
65
+ expect(variants.value["group-color"].options).toHaveLength(1);
66
+ });
67
+
68
+ it("should avoid duplicate options", () => {
69
+ const settings = ref([
70
+ {
71
+ option: {
72
+ id: "opt-1",
73
+ name: "Small",
74
+ group: { id: "group-size", name: "Size" }
75
+ }
76
+ },
77
+ {
78
+ option: {
79
+ id: "opt-1",
80
+ name: "Small",
81
+ group: { id: "group-size", name: "Size" }
82
+ }
83
+ }
84
+ ]);
85
+
86
+ const { variants } = useProductVariants(settings as any);
87
+ expect(variants.value["group-size"].options).toHaveLength(1);
88
+ });
89
+ });
@@ -0,0 +1,48 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { useProductVariantsZwei } from "../../app/composables/useProductVariantsZwei";
3
+ import { ref } from "vue";
4
+
5
+ describe("useProductVariantsZwei", () => {
6
+ it("should return empty object when no settings provided", () => {
7
+ const settings = ref([]);
8
+ const { variants } = useProductVariantsZwei(settings);
9
+ expect(variants.value).toEqual({});
10
+ });
11
+
12
+ it("should group options by group", () => {
13
+ const settings = ref([
14
+ {
15
+ id: "group-size",
16
+ name: "Size",
17
+ translated: { name: "Größe" },
18
+ options: [
19
+ { id: "opt-1", name: "Small", translated: { name: "Klein" } },
20
+ { id: "opt-2", name: "Large", translated: { name: "Groß" } }
21
+ ]
22
+ }
23
+ ]);
24
+
25
+ const { variants } = useProductVariantsZwei(settings);
26
+
27
+ expect(variants.value["group-size"]).toBeDefined();
28
+ expect(variants.value["group-size"]?.name).toBe("Größe");
29
+ expect(variants.value["group-size"]?.options).toHaveLength(2);
30
+ expect(variants.value["group-size"]?.options[0]?.label).toBe("Klein");
31
+ });
32
+
33
+ it("should avoid duplicate options", () => {
34
+ const settings = ref([
35
+ {
36
+ id: "group-size",
37
+ name: "Size",
38
+ options: [
39
+ { id: "opt-1", name: "Small" },
40
+ { id: "opt-1", name: "Small" }
41
+ ]
42
+ }
43
+ ]);
44
+
45
+ const { variants } = useProductVariantsZwei(settings);
46
+ expect(variants.value["group-size"]?.options).toHaveLength(1);
47
+ });
48
+ });
@@ -0,0 +1,96 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { useScrollAnimation } from "../../app/composables/useScrollAnimation";
3
+ import { mount } from "@vue/test-utils";
4
+ import { defineComponent, nextTick } from "vue";
5
+
6
+ describe("useScrollAnimation", () => {
7
+ let observeMock: any;
8
+ let unobserveMock: any;
9
+ let disconnectMock: any;
10
+ let intersectionCallback: any;
11
+
12
+ beforeEach(() => {
13
+ observeMock = vi.fn();
14
+ unobserveMock = vi.fn();
15
+ disconnectMock = vi.fn();
16
+
17
+ // Mock IntersectionObserver
18
+ global.IntersectionObserver = vi.fn().mockImplementation(function (callback) {
19
+ intersectionCallback = callback;
20
+ this.observe = observeMock;
21
+ this.unobserve = unobserveMock;
22
+ this.disconnect = disconnectMock;
23
+ }) as any;
24
+ });
25
+
26
+ it("should initialize with isVisible false", () => {
27
+ const TestComponent = defineComponent({
28
+ setup() {
29
+ const { isVisible, elementRef } = useScrollAnimation();
30
+ return { isVisible, elementRef };
31
+ },
32
+ template: '<div ref="elementRef"></div>',
33
+ });
34
+
35
+ const wrapper = mount(TestComponent);
36
+ expect(wrapper.vm.isVisible).toBe(false);
37
+ });
38
+
39
+ it("should start observing on mount", async () => {
40
+ const TestComponent = defineComponent({
41
+ setup() {
42
+ const { isVisible, elementRef } = useScrollAnimation();
43
+ return { isVisible, elementRef };
44
+ },
45
+ template: '<div ref="elementRef"></div>',
46
+ });
47
+
48
+ mount(TestComponent);
49
+ await nextTick();
50
+
51
+ expect(global.IntersectionObserver).toHaveBeenCalled();
52
+ expect(observeMock).toHaveBeenCalled();
53
+ });
54
+
55
+ it("should set isVisible to true when intersecting and stop observing", async () => {
56
+ const TestComponent = defineComponent({
57
+ setup() {
58
+ const { isVisible, elementRef } = useScrollAnimation();
59
+ return { isVisible, elementRef };
60
+ },
61
+ template: '<div ref="elementRef"></div>',
62
+ });
63
+
64
+ const wrapper = mount(TestComponent);
65
+ await nextTick();
66
+
67
+ // Simulate intersection
68
+ const mockEntry = { isIntersecting: true, target: wrapper.element };
69
+ intersectionCallback([mockEntry]);
70
+
71
+ await nextTick();
72
+ expect(wrapper.vm.isVisible).toBe(true);
73
+ expect(unobserveMock).toHaveBeenCalledWith(wrapper.element);
74
+ });
75
+
76
+ it("should not set isVisible to true when not intersecting", async () => {
77
+ const TestComponent = defineComponent({
78
+ setup() {
79
+ const { isVisible, elementRef } = useScrollAnimation();
80
+ return { isVisible, elementRef };
81
+ },
82
+ template: '<div ref="elementRef"></div>',
83
+ });
84
+
85
+ const wrapper = mount(TestComponent);
86
+ await nextTick();
87
+
88
+ // Simulate non-intersection
89
+ const mockEntry = { isIntersecting: false, target: wrapper.element };
90
+ intersectionCallback([mockEntry]);
91
+
92
+ await nextTick();
93
+ expect(wrapper.vm.isVisible).toBe(false);
94
+ expect(unobserveMock).not.toHaveBeenCalled();
95
+ });
96
+ });