withKeepAlive = false
) {
const root = nodeOps.createElement('div')
- render(
- h(BaseTransition, props, () => {
- return withKeepAlive ? h(KeepAlive, null, slot()) : slot()
- }),
- root
- )
- return root
+ const show = ref(true)
+ const unmount = () => (show.value = false)
+ const App = {
+ render() {
+ return show.value
+ ? h(BaseTransition, props, () => {
+ return withKeepAlive ? h(KeepAlive, null, slot()) : slot()
+ })
+ : null
+ }
+ }
+ render(h(App), root)
+
+ return { root, unmount }
}
function mockProps(extra: BaseTransitionProps = {}, withKeepAlive = false) {
) {
const toggle = ref(true)
const { props, cbs } = mockProps({ mode })
- const root = mount(props, () =>
+ const { root } = mount(props, () =>
toggle.value ? trueBranch() : falseBranch()
)
}: ToggleOptions) {
const toggle = ref(false)
const { props, cbs } = mockProps()
- const root = mount(props, () =>
+ const { root } = mount(props, () =>
toggle.value ? trueBranch() : falseBranch()
)
) {
const toggle = ref(true)
const { props, cbs } = mockProps({}, withKeepAlive)
- const root = mount(
+ const { root } = mount(
props,
() => (toggle.value ? trueBranch() : falseBranch()),
withKeepAlive
) {
const toggle = ref(true)
const { props, cbs } = mockProps({}, withKeepAlive)
- const root = mount(
+ const { root } = mount(
props,
() => (toggle.value ? trueBranch() : falseBranch()),
withKeepAlive
) {
const toggle = ref(true)
const { props, cbs } = mockProps({ mode: 'out-in' }, withKeepAlive)
- const root = mount(
+ const { root } = mount(
props,
() => (toggle.value ? trueBranch() : falseBranch()),
withKeepAlive
})
})
+
+ // #6835
+ describe('mode: "out-in" toggle again after unmounted', () => {
+ async function testOutIn(
+ {
+ trueBranch,
+ falseBranch,
+ trueSerialized,
+ falseSerialized
+ }: ToggleOptions,
+ withKeepAlive = false
+ ) {
+ const toggle = ref(true)
+ const { props, cbs } = mockProps({ mode: 'out-in' }, withKeepAlive)
+ const { root, unmount } = mount(
+ props,
+ () => (toggle.value ? trueBranch() : falseBranch()),
+ withKeepAlive
+ )
+
+ // trigger toggle
+ toggle.value = false
+ await nextTick()
+ // a placeholder is injected until the leave finishes
+ expect(serializeInner(root)).toBe(`${trueSerialized}<!---->`)
+ expect(props.onBeforeLeave).toHaveBeenCalledTimes(1)
+ assertCalledWithEl(props.onBeforeLeave, trueSerialized)
+ expect(props.onLeave).toHaveBeenCalledTimes(1)
+ assertCalledWithEl(props.onLeave, trueSerialized)
+ expect(props.onAfterLeave).not.toHaveBeenCalled()
+ // enter should not have started
+ expect(props.onBeforeEnter).not.toHaveBeenCalled()
+ expect(props.onEnter).not.toHaveBeenCalled()
+ expect(props.onAfterEnter).not.toHaveBeenCalled()
+
+ cbs.doneLeave[trueSerialized]()
+ expect(props.onAfterLeave).toHaveBeenCalledTimes(1)
+ assertCalledWithEl(props.onAfterLeave, trueSerialized)
+ // have to wait for a tick because this triggers an update
+ await nextTick()
+ expect(serializeInner(root)).toBe(falseSerialized)
+ // enter should start
+ expect(props.onBeforeEnter).toHaveBeenCalledTimes(1)
+ assertCalledWithEl(props.onBeforeEnter, falseSerialized)
+ expect(props.onEnter).toHaveBeenCalledTimes(1)
+ assertCalledWithEl(props.onEnter, falseSerialized)
+ expect(props.onAfterEnter).not.toHaveBeenCalled()
+ // finish enter
+ cbs.doneEnter[falseSerialized]()
+ expect(props.onAfterEnter).toHaveBeenCalledTimes(1)
+ assertCalledWithEl(props.onAfterEnter, falseSerialized)
+
+ unmount()
+ // toggle again after unmounted should not throw error
+ toggle.value = true
+ await nextTick()
+ expect(serializeInner(root)).toBe(`<!---->`)
+
+ assertCalls(props, {
+ onBeforeEnter: 1,
+ onEnter: 1,
+ onAfterEnter: 1,
+ onEnterCancelled: 0,
+ onBeforeLeave: 1,
+ onLeave: 1,
+ onAfterLeave: 1,
+ onLeaveCancelled: 0
+ })
+ }
+
+ test('w/ elements', async () => {
+ await runTestWithElements(testOutIn)
+ })
+
+ test('w/ components', async () => {
+ await runTestWithComponents(testOutIn)
+ })
+
+ test('w/ KeepAlive', async () => {
+ await runTestWithKeepAlive(testOutIn)
+ })
+ })
+
describe('mode: "out-in" toggle before finish', () => {
async function testOutInBeforeFinish(
{ trueBranch, falseBranch, trueSerialized }: ToggleOptions,
) {
const toggle = ref(true)
const { props, cbs } = mockProps({ mode: 'out-in' }, withKeepAlive)
- const root = mount(
+ const { root } = mount(
props,
() => (toggle.value ? trueBranch() : falseBranch()),
withKeepAlive
) {
const toggle = ref(true)
const { props, cbs } = mockProps({ mode: 'out-in' }, withKeepAlive)
- const root = mount(
+ const { root } = mount(
props,
() => (toggle.value ? trueBranch() : falseBranch()),
withKeepAlive
) {
const toggle = ref(true)
const { props, cbs } = mockProps({ mode: 'in-out' }, withKeepAlive)
- const root = mount(
+ const { root } = mount(
props,
() => (toggle.value ? trueBranch() : falseBranch()),
withKeepAlive
) {
const toggle = ref(true)
const { props, cbs } = mockProps({ mode: 'in-out' }, withKeepAlive)
- const root = mount(
+ const { root } = mount(
props,
() => (toggle.value ? trueBranch() : falseBranch()),
withKeepAlive