From bb39910e8eb73ac4a7f6147bf3b3ffa1d95c1b34 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 26 Nov 2019 18:07:05 -0500 Subject: [PATCH] test: wip tests for BaseTransition --- .../components/BaseTransition.spec.ts | 176 ++++++++++++++++++ .../__tests__/components/KeepAlive.spec.ts | 2 +- .../__tests__/components/Suspense.spec.ts | 2 +- .../src/components/BaseTransition.ts | 2 +- 4 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 packages/runtime-core/__tests__/components/BaseTransition.spec.ts diff --git a/packages/runtime-core/__tests__/components/BaseTransition.spec.ts b/packages/runtime-core/__tests__/components/BaseTransition.spec.ts new file mode 100644 index 000000000..a0a0e8a79 --- /dev/null +++ b/packages/runtime-core/__tests__/components/BaseTransition.spec.ts @@ -0,0 +1,176 @@ +import { + nodeOps, + render, + h, + BaseTransition, + BaseTransitionProps, + ref, + nextTick, + serializeInner +} from '@vue/runtime-test' + +function mount(props: BaseTransitionProps, slot: () => any) { + const root = nodeOps.createElement('div') + render(h(BaseTransition, props, slot), root) + return root +} + +function mockProps() { + const cbs = { + doneEnter: () => {}, + doneLeave: () => {} + } + const props: BaseTransitionProps = { + onBeforeEnter: jest.fn(el => { + expect(el.parentNode).toBeNull() + }), + onEnter: jest.fn((el, done) => { + cbs.doneEnter = done + }), + onAfterEnter: jest.fn(), + onEnterCancelled: jest.fn(), + onBeforeLeave: jest.fn(), + onLeave: jest.fn((el, done) => { + cbs.doneLeave = done + }), + onAfterLeave: jest.fn(), + onLeaveCancelled: jest.fn() + } + return { + props, + cbs + } +} + +function assertCalls( + props: BaseTransitionProps, + calls: Record +) { + Object.keys(calls).forEach((key: keyof BaseTransitionProps) => { + expect(props[key]).toHaveBeenCalledTimes(calls[key]) + }) +} + +describe('BaseTransition', () => { + describe('with elements', () => { + test('toggle on-off', async () => { + const toggle = ref(true) + const { props, cbs } = mockProps() + const root = mount(props, () => (toggle.value ? h('div') : null)) + + // without appear: true, enter hooks should not be called on mount + expect(props.onBeforeEnter).not.toHaveBeenCalled() + expect(props.onEnter).not.toHaveBeenCalled() + expect(props.onAfterEnter).not.toHaveBeenCalled() + + toggle.value = false + await nextTick() + // comment placeholder enters immediately + expect(serializeInner(root)).toBe('
') + expect(props.onBeforeLeave).toHaveBeenCalledTimes(1) + expect(props.onLeave).toHaveBeenCalledTimes(1) + expect(props.onAfterLeave).not.toHaveBeenCalled() + cbs.doneLeave() + expect(serializeInner(root)).toBe('') + expect(props.onAfterLeave).toHaveBeenCalledTimes(1) + + toggle.value = true + await nextTick() + expect(serializeInner(root)).toBe('
') + // before enter spy asserts node has no parent when it's called + expect(props.onBeforeEnter).toHaveBeenCalledTimes(1) + expect(props.onEnter).toHaveBeenCalledTimes(1) + expect(props.onAfterEnter).not.toHaveBeenCalled() + cbs.doneEnter() + expect(props.onAfterEnter).toHaveBeenCalledTimes(1) + + assertCalls(props, { + onBeforeEnter: 1, + onEnter: 1, + onAfterEnter: 1, + onEnterCancelled: 0, + onBeforeLeave: 1, + onLeave: 1, + onAfterLeave: 1, + onLeaveCancelled: 0 + }) + }) + + test('toggle before finish', async () => { + const toggle = ref(false) + const { props, cbs } = mockProps() + const root = mount(props, () => (toggle.value ? h('div') : null)) + + // start enter + toggle.value = true + await nextTick() + expect(serializeInner(root)).toBe(`
`) + expect(props.onBeforeEnter).toHaveBeenCalledTimes(1) + expect(props.onEnter).toHaveBeenCalledTimes(1) + + // leave before enter finishes + toggle.value = false + await nextTick() + expect(serializeInner(root)).toBe(`
`) + expect(props.onEnterCancelled).toHaveBeenCalled() + expect(props.onBeforeLeave).toHaveBeenCalledTimes(1) + expect(props.onLeave).toHaveBeenCalledTimes(1) + expect(props.onAfterLeave).not.toHaveBeenCalled() + // calling doneEnter now should have no effect + cbs.doneEnter() + expect(props.onAfterEnter).not.toHaveBeenCalled() + + // enter again before leave finishes + toggle.value = true + await nextTick() + expect(props.onBeforeEnter).toHaveBeenCalledTimes(2) + expect(props.onEnter).toHaveBeenCalledTimes(2) + // 1. should remove the previous leaving
so there is only one
+ // 2. should remove the comment placeholder for the off branch + expect(serializeInner(root)).toBe(`
`) + // note onLeaveCancelled is NOT called because it was a forced early + // removal instead of a cancel. Instead, onAfterLeave should be called. + expect(props.onAfterLeave).toHaveBeenCalledTimes(1) + // calling doneLeave again should have no effect now + cbs.doneLeave() + expect(props.onAfterLeave).toHaveBeenCalledTimes(1) + cbs.doneEnter() + expect(props.onAfterEnter).toHaveBeenCalledTimes(1) + + assertCalls(props, { + onBeforeEnter: 2, + onEnter: 2, + onAfterEnter: 1, + onEnterCancelled: 1, + onBeforeLeave: 1, + onLeave: 1, + onAfterLeave: 1, + onLeaveCancelled: 0 + }) + }) + + test('toggle between branches', () => {}) + + test('toggle between branches before finish', () => {}) + + test('persisted: true', () => { + // test onLeaveCancelled + }) + + test('appear: true', () => {}) + + test('mode: "out-in"', () => {}) + + test('mode: "out-in" toggle before finish', () => {}) + + test('mode: "in-out" toggle before finish', () => {}) + }) + + describe('with components', () => { + // TODO + }) + + describe('with KeepAlive', () => { + // TODO + }) +}) diff --git a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts index 9b9e3cc0d..9bcec22e5 100644 --- a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts +++ b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts @@ -11,7 +11,7 @@ import { } from '@vue/runtime-test' import { KeepAliveProps } from '../../src/components/KeepAlive' -describe('keep-alive', () => { +describe('KeepAlive', () => { let one: ComponentOptions let two: ComponentOptions let views: Record diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts index 62e500174..264bd7ca4 100644 --- a/packages/runtime-core/__tests__/components/Suspense.spec.ts +++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts @@ -13,7 +13,7 @@ import { onErrorCaptured } from '@vue/runtime-test' -describe('renderer: suspense', () => { +describe('Suspense', () => { const deps: Promise[] = [] beforeEach(() => { diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index 4f4961b02..a5060a854 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -39,7 +39,7 @@ export interface BaseTransitionProps { onBeforeLeave?: (el: any) => void onLeave?: (el: any, done: () => void) => void onAfterLeave?: (el: any) => void - onLeaveCancelled?: (el: any) => void + onLeaveCancelled?: (el: any) => void // only fired in persisted mode } export interface TransitionHooks {