|
1 | | -import { Fragment, _fnSignal, _jsxSorted, component$, type JSXOutput } from '@qwik.dev/core'; |
| 1 | +import { |
| 2 | + Fragment, |
| 3 | + _fnSignal, |
| 4 | + _jsxSorted, |
| 5 | + component$, |
| 6 | + useSignal, |
| 7 | + useStore, |
| 8 | + type JSXChildren, |
| 9 | + type JSXOutput, |
| 10 | +} from '@qwik.dev/core'; |
2 | 11 | import { vnode_fromJSX } from '@qwik.dev/core/testing'; |
3 | 12 | import { describe, expect, it } from 'vitest'; |
4 | 13 | import type { SignalImpl } from '../reactive-primitives/impl/signal-impl'; |
5 | | -import { _hasStoreEffects, getOrCreateStore } from '../reactive-primitives/impl/store'; |
| 14 | +import { |
| 15 | + _hasStoreEffects, |
| 16 | + getOrCreateStore, |
| 17 | + getStoreHandler, |
| 18 | +} from '../reactive-primitives/impl/store'; |
6 | 19 | import type { WrappedSignalImpl } from '../reactive-primitives/impl/wrapped-signal-impl'; |
7 | 20 | import { createSignal } from '../reactive-primitives/signal-api'; |
8 | 21 | import { StoreFlags } from '../reactive-primitives/types'; |
@@ -1581,4 +1594,99 @@ describe('vNode-diff', () => { |
1581 | 1594 | expect((vnode_getNode(vNode) as Element).outerHTML).toEqual('<div q:key="KA_0">Hello</div>'); |
1582 | 1595 | }); |
1583 | 1596 | }); |
| 1597 | + |
| 1598 | + describe('cleanup - clearAllEffects', () => { |
| 1599 | + it('should call clearAllEffects for VNode elements', () => { |
| 1600 | + const { vParent, container } = vnode_fromJSX(<div key="KA_0">Hello</div>); |
| 1601 | + |
| 1602 | + const signal = createSignal('test') as SignalImpl; |
| 1603 | + const test = _jsxSorted('div', { class: signal }, null, [], 0, 'KA_0'); |
| 1604 | + vnode_diff(container, test, vParent, null); |
| 1605 | + vnode_applyJournal(container.$journal$); |
| 1606 | + |
| 1607 | + expect(signal.$effects$).toBeDefined(); |
| 1608 | + expect(signal.$effects$!.size).toBeGreaterThan(0); |
| 1609 | + |
| 1610 | + vnode_diff(container, _jsxSorted('div', {}, null, [], 0, 'KA_0'), vParent, null); |
| 1611 | + vnode_applyJournal(container.$journal$); |
| 1612 | + |
| 1613 | + expect(signal.$effects$!.size).toBe(0); |
| 1614 | + }); |
| 1615 | + |
| 1616 | + it('should call clearAllEffects for VirtualVNode components', async () => { |
| 1617 | + const { vParent, container } = vnode_fromJSX(<Fragment></Fragment>); |
| 1618 | + |
| 1619 | + const signal = createSignal('initial') as SignalImpl; |
| 1620 | + |
| 1621 | + const Child = component$((props: any) => { |
| 1622 | + return <span>{props.value}</span>; |
| 1623 | + }); |
| 1624 | + |
| 1625 | + const test1 = _jsxSorted(Child, null, { value: signal }, null, 3, null) as JSXChildren; |
| 1626 | + await vnode_diff(container, test1, vParent, null); |
| 1627 | + await waitForDrain(container.$scheduler$); |
| 1628 | + vnode_applyJournal(container.$journal$); |
| 1629 | + |
| 1630 | + expect(signal.$effects$).toBeDefined(); |
| 1631 | + expect(signal.$effects$!.size).toBeGreaterThan(0); |
| 1632 | + |
| 1633 | + await vnode_diff(container, <Fragment></Fragment>, vParent, null); |
| 1634 | + await waitForDrain(container.$scheduler$); |
| 1635 | + vnode_applyJournal(container.$journal$); |
| 1636 | + |
| 1637 | + expect(signal.$effects$!.size).toBe(0); |
| 1638 | + }); |
| 1639 | + |
| 1640 | + it('should call clearAllEffects for SignalImpl objects in ELEMENT_SEQ', async () => { |
| 1641 | + const { vParent, container } = vnode_fromJSX(<Fragment></Fragment>); |
| 1642 | + |
| 1643 | + (globalThis as any).innerSignal = undefined; |
| 1644 | + |
| 1645 | + const Child = component$(() => { |
| 1646 | + (globalThis as any).innerSignal = useSignal('inner'); |
| 1647 | + return <span>{(globalThis as any).innerSignal.value}</span>; |
| 1648 | + }); |
| 1649 | + |
| 1650 | + const test = _jsxSorted(Child as unknown as any, null, null, null, 3, null) as any; |
| 1651 | + vnode_diff(container, test, vParent, null); |
| 1652 | + await waitForDrain(container.$scheduler$); |
| 1653 | + vnode_applyJournal(container.$journal$); |
| 1654 | + |
| 1655 | + expect((globalThis as any).innerSignal.$effects$).toBeDefined(); |
| 1656 | + expect((globalThis as any).innerSignal.$effects$!.size).toBeGreaterThan(0); |
| 1657 | + |
| 1658 | + vnode_diff(container, <Fragment></Fragment>, vParent, null); |
| 1659 | + await waitForDrain(container.$scheduler$); |
| 1660 | + vnode_applyJournal(container.$journal$); |
| 1661 | + |
| 1662 | + expect((globalThis as any).innerSignal.$effects$.size).toBe(0); |
| 1663 | + }); |
| 1664 | + |
| 1665 | + it('should call clearAllEffects for Store objects in ELEMENT_SEQ', async () => { |
| 1666 | + const { vParent, container } = vnode_fromJSX(<Fragment></Fragment>); |
| 1667 | + |
| 1668 | + (globalThis as any).store = undefined; |
| 1669 | + |
| 1670 | + const Child = component$(() => { |
| 1671 | + (globalThis as any).store = useStore({ count: 10 }); |
| 1672 | + return <span>Count: {(globalThis as any).store.count}</span>; |
| 1673 | + }); |
| 1674 | + |
| 1675 | + const test = _jsxSorted(Child as unknown as any, null, null, null, 3, null) as any; |
| 1676 | + vnode_diff(container, test, vParent, null); |
| 1677 | + await waitForDrain(container.$scheduler$); |
| 1678 | + vnode_applyJournal(container.$journal$); |
| 1679 | + |
| 1680 | + const store = getStoreHandler((globalThis as any).store); |
| 1681 | + |
| 1682 | + expect(store!.$effects$?.size).toBeGreaterThan(0); |
| 1683 | + |
| 1684 | + container.$journal$ = []; |
| 1685 | + vnode_diff(container, <Fragment></Fragment>, vParent, null); |
| 1686 | + await waitForDrain(container.$scheduler$); |
| 1687 | + vnode_applyJournal(container.$journal$); |
| 1688 | + |
| 1689 | + expect(store!.$effects$?.size).toBe(0); |
| 1690 | + }); |
| 1691 | + }); |
1584 | 1692 | }); |
0 commit comments