diff --git a/packages/inula-novdom/src/core.ts b/packages/inula-novdom/src/core.ts index b681c09c..9b2a2f60 100644 --- a/packages/inula-novdom/src/core.ts +++ b/packages/inula-novdom/src/core.ts @@ -13,7 +13,7 @@ * See the Mulan PSL v2 for more details. */ -import {insert} from './dom'; +import { insert } from './dom'; import { untrack } from 'inula-reactive/dist'; type ComponentConstructor = (props: T) => any; @@ -23,9 +23,24 @@ export function runComponent(Comp: ComponentConstructor, props: T = {} as return untrack(() => Comp(props)); } +const ELEMENT_NODE = 1; +const DOCUMENT_NODE = 9; +const COMMENT_NODE = 8; +const DOCUMENT_FRAGMENT_NODE = 11; + +function isValidContainer(container: HTMLElement | null): boolean { + return !!( + container && + (container.nodeType === ELEMENT_NODE || + container.nodeType === DOCUMENT_FRAGMENT_NODE || + container.nodeType === DOCUMENT_NODE || + container.nodeType === COMMENT_NODE) + ); +} + export function render(codeFn: CodeFunction, element: HTMLElement): () => void { - if (!element) { - throw new Error('Render target is not provided'); + if (!isValidContainer(element)) { + throw new Error('Render target is not valid.'); } const disposer = (): void => { diff --git a/packages/inula-novdom/tests/For.bench.ts b/packages/inula-novdom/tests/For.bench.tsx similarity index 100% rename from packages/inula-novdom/tests/For.bench.ts rename to packages/inula-novdom/tests/For.bench.tsx diff --git a/packages/inula-novdom/tests/dom-manipulation.test.ts b/packages/inula-novdom/tests/dom-manipulation.test.tsx similarity index 100% rename from packages/inula-novdom/tests/dom-manipulation.test.ts rename to packages/inula-novdom/tests/dom-manipulation.test.tsx diff --git a/packages/inula-novdom/tests/render.test.ts b/packages/inula-novdom/tests/render.test.tsx similarity index 90% rename from packages/inula-novdom/tests/render.test.ts rename to packages/inula-novdom/tests/render.test.tsx index 5bd3ed6e..b193a66a 100644 --- a/packages/inula-novdom/tests/render.test.ts +++ b/packages/inula-novdom/tests/render.test.tsx @@ -21,6 +21,7 @@ import { effect as $$effect, style as $$style, className as $$className, + setAttribute as $$setAttribute, } from '../src/dom'; import { runComponent as $$runComponent, render } from '../src/core'; import { delegateEvents as $$delegateEvents, addEventListener as $$on } from '../src/event'; @@ -262,6 +263,14 @@ describe('render', () => { expect(container.querySelector('h1').innerHTML).toMatchInlineSnapshot('"1"'); }); + it('should throw error when container is not valid', () => { + [undefined, null, 0, 1, true, false, 'string', Symbol('symbol'), {}].forEach(container => { + expect(() => render(() => $$runComponent(() => null, undefined), container)).toThrowError( + 'Render target is not valid.' + ); + }); + }); + it('should render string of style', ({ container }) => { /** * 源码: @@ -550,4 +559,52 @@ describe('render', () => { render(() => $$runComponent(Comp, {}), container); expect(container.querySelector('div').className).toEqual('red green'); }); + + it('should render attribute', ({ container }) => { + /** + * 源码: + * function App() { + * return ( + *

parallel

+ * ); + * } + */ + // 编译后: + const $tmpl = /*#__PURE__*/ $$template('
Count value is 0.'); + const Comp = () => { + return (() => { + const _el$ = $tmpl(); + $$setAttribute(_el$, 'id', 'test'); + return _el$; + })(); + }; + render(() => $$runComponent(Comp, {}), container); + expect(container.querySelector('div').id).toEqual('test'); + }); + + it('should update attribute', ({ container }) => { + /** + * 源码: + * function App() { + * const id = reactive('el'); + * return ( + *

parallel

+ * ); + * } + */ + // 编译后: + const $tmpl = /*#__PURE__*/ $$template('
Count value is 0.'); + const id = reactive('el'); + const Comp = () => { + return (() => { + const _el$ = $tmpl(); + $$effect(() => $$setAttribute(_el$, 'id', id.get())); + return _el$; + })(); + }; + render(() => $$runComponent(Comp, {}), container); + expect(container.querySelector('div').id).toEqual('el'); + id.set('test'); + expect(container.querySelector('div').id).toEqual('test'); + }); });