From dfc855cd5423b9c2360c3db3e6f8be046e955405 Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 1 Oct 2018 16:42:53 -0400 Subject: [PATCH] test: test ops logging for test renderer --- packages/core/src/componentComputed.ts | 4 +- .../__tests__/testRenderer.spec.ts | 99 ++++++++++++++++++- packages/renderer-test/src/index.ts | 10 +- packages/renderer-test/src/nodeOps.ts | 83 ++++++---------- packages/renderer-test/src/patchData.ts | 17 ++++ 5 files changed, 147 insertions(+), 66 deletions(-) create mode 100644 packages/renderer-test/src/patchData.ts diff --git a/packages/core/src/componentComputed.ts b/packages/core/src/componentComputed.ts index bf8ddca4..2a00fe9e 100644 --- a/packages/core/src/componentComputed.ts +++ b/packages/core/src/componentComputed.ts @@ -49,7 +49,9 @@ export function initializeComputed( {}, { get(_, key: any) { - return handles[key]() + if (handles.hasOwnProperty(key)) { + return handles[key]() + } } // TODO should be readonly } diff --git a/packages/renderer-test/__tests__/testRenderer.spec.ts b/packages/renderer-test/__tests__/testRenderer.spec.ts index 3974388f..20936dc9 100644 --- a/packages/renderer-test/__tests__/testRenderer.spec.ts +++ b/packages/renderer-test/__tests__/testRenderer.spec.ts @@ -5,19 +5,30 @@ import { nodeOps, NodeTypes, TestElement, - TestText + TestText, + dumpOps, + NodeOpTypes, + nextTick, + observable, + resetOps } from '../src' describe('test renderer', () => { it('should work', () => { class App extends Component { + data() { + return { + id: 'test', + text: 'hello' + } + } render() { return h( 'div', { - id: 'test' + id: this.id }, - 'hello' + this.text ) } } @@ -36,7 +47,85 @@ describe('test renderer', () => { expect(text.text).toBe('hello') }) - it('should record ops', () => { - // TODO + it('should record ops', async () => { + const state = observable({ + id: 'test', + text: 'hello' + }) + + class App extends Component { + render() { + return h( + 'div', + { + id: state.id + }, + state.text + ) + } + } + const root = nodeOps.createElement('div') + + resetOps() + render(h(App), root) + const ops = dumpOps() + + expect(ops.length).toBe(5) + + expect(ops[0]).toEqual({ + type: NodeOpTypes.CREATE, + nodeType: NodeTypes.ELEMENT, + tag: 'div', + targetNode: root.children[0] + }) + + expect(ops[1]).toEqual({ + type: NodeOpTypes.PATCH, + targetNode: root.children[0], + propKey: 'id', + propPrevValue: null, + propNextValue: 'test' + }) + + expect(ops[2]).toEqual({ + type: NodeOpTypes.CREATE, + nodeType: NodeTypes.TEXT, + text: 'hello', + targetNode: (root.children[0] as TestElement).children[0] + }) + + expect(ops[3]).toEqual({ + type: NodeOpTypes.APPEND, + targetNode: (root.children[0] as TestElement).children[0], + parentNode: root.children[0] + }) + + expect(ops[4]).toEqual({ + type: NodeOpTypes.APPEND, + targetNode: root.children[0], + parentNode: root + }) + + // test update ops + state.id = 'foo' + state.text = 'bar' + await nextTick() + + const updateOps = dumpOps() + expect(updateOps.length).toBe(2) + + expect(updateOps[0]).toEqual({ + type: NodeOpTypes.PATCH, + targetNode: root.children[0], + propKey: 'id', + propPrevValue: 'test', + propNextValue: 'foo' + }) + + expect(updateOps[1]).toEqual({ + type: NodeOpTypes.SET_TEXT, + targetNode: (root.children[0] as TestElement).children[0], + text: 'bar' + }) }) }) diff --git a/packages/renderer-test/src/index.ts b/packages/renderer-test/src/index.ts index 2c8f648c..6436f98b 100644 --- a/packages/renderer-test/src/index.ts +++ b/packages/renderer-test/src/index.ts @@ -1,14 +1,6 @@ import { createRenderer, VNode } from '@vue/core' import { nodeOps, TestElement } from './nodeOps' - -function patchData( - el: TestElement, - key: string, - prevValue: any, - nextValue: any -) { - el.props[key] = nextValue -} +import { patchData } from './patchData' const { render: _render } = createRenderer({ nodeOps, diff --git a/packages/renderer-test/src/nodeOps.ts b/packages/renderer-test/src/nodeOps.ts index 05b4c508..f36eadea 100644 --- a/packages/renderer-test/src/nodeOps.ts +++ b/packages/renderer-test/src/nodeOps.ts @@ -21,57 +21,44 @@ export interface TestText { export type TestNode = TestElement | TestText -const enum OpTypes { +export const enum NodeOpTypes { CREATE = 'create', INSERT = 'insert', APPEND = 'append', REMOVE = 'remove', SET_TEXT = 'setText', CLEAR = 'clearContent', - NEXT_SIBLING = 'nextSibling', - PARENT_NODE = 'parentNode' + PATCH = 'patch' } -interface Op { - type: OpTypes +export interface NodeOp { + type: NodeOpTypes nodeType?: NodeTypes tag?: string text?: string targetNode?: TestNode parentNode?: TestElement refNode?: TestNode + propKey?: string + propPrevValue?: any + propNextValue?: any } let nodeId: number = 0 -let isRecording: boolean = false -let recordedOps: Op[] = [] +let recordedNodeOps: NodeOp[] = [] -function logOp(op: Op) { - if (isRecording) { - recordedOps.push(op) - } +export function logNodeOp(op: NodeOp) { + recordedNodeOps.push(op) } -export function startRecordingOps() { - if (!isRecording) { - isRecording = true - recordedOps = [] - } else { - throw new Error( - '`startRecordingOps` called when there is already an active session.' - ) - } +export function resetOps() { + recordedNodeOps = [] } -export function dumpOps(): Op[] { - if (!isRecording) { - throw new Error( - '`dumpOps` called without a recording session. ' + - 'Call `startRecordingOps` first to start a session.' - ) - } - isRecording = false - return recordedOps.slice() +export function dumpOps(): NodeOp[] { + const ops = recordedNodeOps.slice() + resetOps() + return ops } function createElement(tag: string): TestElement { @@ -83,8 +70,8 @@ function createElement(tag: string): TestElement { props: {}, parentNode: null } - logOp({ - type: OpTypes.CREATE, + logNodeOp({ + type: NodeOpTypes.CREATE, nodeType: NodeTypes.ELEMENT, targetNode: node, tag @@ -99,8 +86,8 @@ function createText(text: string): TestText { text, parentNode: null } - logOp({ - type: OpTypes.CREATE, + logNodeOp({ + type: NodeOpTypes.CREATE, nodeType: NodeTypes.TEXT, targetNode: node, text @@ -109,8 +96,8 @@ function createText(text: string): TestText { } function setText(node: TestText, text: string) { - logOp({ - type: OpTypes.SET_TEXT, + logNodeOp({ + type: NodeOpTypes.SET_TEXT, targetNode: node, text }) @@ -118,8 +105,8 @@ function setText(node: TestText, text: string) { } function appendChild(parent: TestElement, child: TestNode) { - logOp({ - type: OpTypes.APPEND, + logNodeOp({ + type: NodeOpTypes.APPEND, targetNode: child, parentNode: parent }) @@ -140,8 +127,8 @@ function insertBefore(parent: TestElement, child: TestNode, ref: TestNode) { console.error('parent: ', parent) throw new Error('ref is not a child of parent') } - logOp({ - type: OpTypes.INSERT, + logNodeOp({ + type: NodeOpTypes.INSERT, targetNode: child, parentNode: parent, refNode: ref @@ -160,8 +147,8 @@ function replaceChild( } function removeChild(parent: TestElement, child: TestNode) { - logOp({ - type: OpTypes.REMOVE, + logNodeOp({ + type: NodeOpTypes.REMOVE, targetNode: child, parentNode: parent }) @@ -177,8 +164,8 @@ function removeChild(parent: TestElement, child: TestNode) { } function clearContent(node: TestNode) { - logOp({ - type: OpTypes.CLEAR, + logNodeOp({ + type: NodeOpTypes.CLEAR, targetNode: node }) if (node.type === NodeTypes.ELEMENT) { @@ -192,18 +179,10 @@ function clearContent(node: TestNode) { } function parentNode(node: TestNode): TestElement | null { - logOp({ - type: OpTypes.PARENT_NODE, - targetNode: node - }) return node.parentNode } function nextSibling(node: TestNode): TestNode | null { - logOp({ - type: OpTypes.NEXT_SIBLING, - targetNode: node - }) const parent = node.parentNode if (!parent) { return null @@ -229,3 +208,5 @@ export const nodeOps = { nextSibling, querySelector } + +export function patchData() {} diff --git a/packages/renderer-test/src/patchData.ts b/packages/renderer-test/src/patchData.ts new file mode 100644 index 00000000..7f635afc --- /dev/null +++ b/packages/renderer-test/src/patchData.ts @@ -0,0 +1,17 @@ +import { TestElement, logNodeOp, NodeOpTypes } from './nodeOps' + +export function patchData( + el: TestElement, + key: string, + prevValue: any, + nextValue: any +) { + logNodeOp({ + type: NodeOpTypes.PATCH, + targetNode: el, + propKey: key, + propPrevValue: prevValue, + propNextValue: nextValue + }) + el.props[key] = nextValue +}