diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 724718115..7268d83d9 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -254,6 +254,11 @@ export function setupStatefulComponent(instance: ComponentInstance) { } instance.render = Component.render as RenderFunction } + } else { + if (__DEV__ && !Component.render) { + // TODO warn missing render fn + } + instance.render = Component.render as RenderFunction } } diff --git a/packages/runtime-test/__tests__/testRuntime.spec.ts b/packages/runtime-test/__tests__/testRuntime.spec.ts index ce0b8c83f..630ce5203 100644 --- a/packages/runtime-test/__tests__/testRuntime.spec.ts +++ b/packages/runtime-test/__tests__/testRuntime.spec.ts @@ -4,18 +4,19 @@ import { nodeOps, NodeTypes, TestElement, - TestText - // dumpOps, - // NodeOpTypes, - // nextTick, - // state, - // resetOps, - // serialize, - // triggerEvent + TestText, + ref, + reactive, + dumpOps, + resetOps, + NodeOpTypes, + nextTick, + serialize, + triggerEvent } from '../src' describe('test renderer', () => { - it('should work', async () => { + it('should work', () => { const root = nodeOps.createElement('div') render( h( @@ -40,137 +41,132 @@ describe('test renderer', () => { expect(text.text).toBe('hello') }) - // it('should record ops', async () => { - // const store = state({ - // id: 'test', - // text: 'hello' - // }) + it('should record ops', async () => { + const state = reactive({ + id: 'test', + text: 'hello' + }) - // class App extends Component { - // render() { - // return h( - // 'div', - // { - // id: store.id - // }, - // store.text - // ) - // } - // } - // const root = nodeOps.createElement('div') + const App = { + render() { + return h( + 'div', + { + id: state.id + }, + state.text + ) + } + } + const root = nodeOps.createElement('div') - // resetOps() - // await render(h(App), root) - // const ops = dumpOps() + resetOps() + render(h(App), root) + const ops = dumpOps() - // expect(ops.length).toBe(5) + expect(ops.length).toBe(4) - // expect(ops[0]).toEqual({ - // type: NodeOpTypes.CREATE, - // nodeType: NodeTypes.ELEMENT, - // tag: 'div', - // targetNode: root.children[0] - // }) + 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[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[2]).toEqual({ + type: NodeOpTypes.SET_ELEMENT_TEXT, + text: 'hello', + targetNode: root.children[0] + }) - // expect(ops[3]).toEqual({ - // type: NodeOpTypes.APPEND, - // targetNode: (root.children[0] as TestElement).children[0], - // parentNode: root.children[0] - // }) + expect(ops[3]).toEqual({ + type: NodeOpTypes.INSERT, + targetNode: root.children[0], + parentNode: root, + refNode: null + }) - // expect(ops[4]).toEqual({ - // type: NodeOpTypes.APPEND, - // targetNode: root.children[0], - // parentNode: root - // }) + // test update ops + state.id = 'foo' + state.text = 'bar' + await nextTick() - // // test update ops - // store.id = 'foo' - // store.text = 'bar' - // await nextTick() + const updateOps = dumpOps() + expect(updateOps.length).toBe(2) - // 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[0]).toEqual({ - // type: NodeOpTypes.PATCH, - // targetNode: root.children[0], - // propKey: 'id', - // propPrevValue: 'test', - // propNextValue: 'foo' - // }) + expect(updateOps[1]).toEqual({ + type: NodeOpTypes.SET_ELEMENT_TEXT, + targetNode: root.children[0], + text: 'bar' + }) + }) - // expect(updateOps[1]).toEqual({ - // type: NodeOpTypes.SET_TEXT, - // targetNode: (root.children[0] as TestElement).children[0], - // text: 'bar' - // }) - // }) + it('should be able to serialize nodes', () => { + const App = { + render() { + return h( + 'div', + { + id: 'test' + }, + [h('span', 0, 'foo'), 'hello'] + ) + } + } + const root = nodeOps.createElement('div') + render(h(App), root) + expect(serialize(root)).toEqual( + `
foohello
` + ) + // indented output + expect(serialize(root, 2)).toEqual( + `
+
+ + foo + + hello +
+
` + ) + }) - // it('should be able to serialize nodes', async () => { - // class App extends Component { - // render() { - // return h( - // 'div', - // { - // id: 'test' - // }, - // [h('span', 'foo'), 'hello'] - // ) - // } - // } - // const root = nodeOps.createElement('div') - // await render(h(App), root) - // expect(serialize(root)).toEqual( - // `
foohello
` - // ) - // expect(serialize(root, 2)).toEqual( - // `
- //
- // - // foo - // - // hello - //
- //
` - // ) - // }) + it('should be able to trigger events', async () => { + const count = ref(0) - // it('should be able to trigger events', async () => { - // class App extends Component { - // count = 0 - // inc() { - // this.count++ - // } - // render() { - // return h( - // 'div', - // { - // onClick: this.inc - // }, - // this.count - // ) - // } - // } - // const app = await renderInstance(App) - // triggerEvent(app.$el, 'click') - // expect(app.count).toBe(1) - // await nextTick() - // expect(serialize(app.$el)).toBe(`
1
`) - // }) + const App = () => { + return h( + 'span', + { + onClick: () => { + count.value++ + } + }, + count.value + ) + } + + const root = nodeOps.createElement('div') + render(h(App), root) + triggerEvent(root.children[0] as TestElement, 'click') + expect(count.value).toBe(1) + await nextTick() + expect(serialize(root)).toBe(`
1
`) + }) }) diff --git a/packages/runtime-test/src/nodeOps.ts b/packages/runtime-test/src/nodeOps.ts index 926b36182..b7fa91e72 100644 --- a/packages/runtime-test/src/nodeOps.ts +++ b/packages/runtime-test/src/nodeOps.ts @@ -4,6 +4,15 @@ export const enum NodeTypes { COMMENT = 'comment' } +export const enum NodeOpTypes { + CREATE = 'create', + INSERT = 'insert', + REMOVE = 'remove', + SET_TEXT = 'setText', + SET_ELEMENT_TEXT = 'setElementText', + PATCH = 'patch' +} + export interface TestElement { id: number type: NodeTypes.ELEMENT @@ -30,15 +39,6 @@ export interface TestComment { export type TestNode = TestElement | TestText | TestComment -export const enum NodeOpTypes { - CREATE = 'create', - INSERT = 'insert', - REMOVE = 'remove', - SET_TEXT = 'setText', - SET_ELEMENT_TEXT = 'setElementText', - PATCH = 'patch' -} - export interface NodeOp { type: NodeOpTypes nodeType?: NodeTypes @@ -184,7 +184,14 @@ function setElementText(el: TestElement, text: string) { el.children.forEach(c => { c.parentNode = null }) - el.children = [createText(text)] + el.children = [ + { + id: nodeId++, + type: NodeTypes.TEXT, + text, + parentNode: el + } + ] } function parentNode(node: TestNode): TestElement | null {