// Copyright 2022-2024 Yoshiya Hinosawa. All rights reserved. MIT license. import { assert, assertEquals, assertExists, assertThrows } from "@std/assert" import { delay } from "@std/async" import "./dom_polyfill.ts" import { type Context, mount, register, unmount } from "./mod.ts" // disable debug logs because it's too verbose for unit testing // deno-lint-ignore no-explicit-any ;(globalThis as any).__DEV__ = false Deno.test("Component body is called when the component is mounted", () => { const name = randomName() document.body.innerHTML = `
` let called = false function Component() { called = true } register(Component, name) assert(called) }) Deno.test("onUnmount registers the event handler for the unmount event", () => { const name = randomName() document.body.innerHTML = `` let called = false function Component({ onUnmount }: Context) { onUnmount(() => { console.log("onUnmount called") called = true }) } register(Component, name) mount() assert(!called) unmount(name, document.body.firstChild!) assert(called) }) Deno.test("unmount removes the event listeners", () => { const name = randomName() document.body.innerHTML = `` const div = queryByClass(name) let count = 0 function Component({ on }: Context) { on("my-event", (_e) => { count++ }) } register(Component, name) assertEquals(count, 0) div.dispatchEvent(new CustomEvent("my-event")) assertEquals(count, 1) div.dispatchEvent(new CustomEvent("my-event")) assertEquals(count, 2) unmount(name, div!) div.dispatchEvent(new CustomEvent("my-event")) assertEquals(count, 2) }) Deno.test("on[event] is called when the event is dispatched", () => { const name = randomName() document.body.innerHTML = `` const div = queryByClass(name) let called = false function Component({ on }: Context) { on("click", () => { called = true }) on("click", () => { called = true }) } register(Component, name) div.dispatchEvent(new Event("click")) assert(called) }) Deno.test("on(selector)[event] is called when the event is dispatched only under the selector", async () => { const name = randomName() document.body.innerHTML = `` let onBtn1ClickCalled = false let onBtn2ClickCalled = false function Component({ on }: Context) { on("click", ".btn1", () => { onBtn1ClickCalled = true }) on("click", ".btn2", () => { onBtn2ClickCalled = true }) } register(Component, name) const btn = queryByClass("btn1") // FIXME(kt3k): workaround for deno_dom & deno issue // deno_dom doesn't bubble event when the direct target dom doesn't have event handler btn.addEventListener("click", () => {}) btn.dispatchEvent(new Event("click", { bubbles: true })) await new Promise((r) => setTimeout(r, 100)) assert(onBtn1ClickCalled) assert(!onBtn2ClickCalled) }) Deno.test("on(option)[event] is called with option as AddEventListnerOptions", () => { const name = randomName() document.body.innerHTML = `` let count = 0 function Component({ on }: Context) { on("click", { once: true }, (_e) => count++) // for checking type on("touchmove", { passive: false }, (_e) => {}) } register(Component, name) const div = queryByClass(name) div.dispatchEvent(new Event("click")) div.dispatchEvent(new Event("click")) assertEquals(count, 1) }) Deno.test("on.outside.event works", () => { const name = randomName() document.body.innerHTML = `foo
bar
baz
hello
" } register(Component, name) assertEquals(queryByClass(name).innerHTML, "hello
") }) Deno.test("Resolved string from Component is rendered as innerHTML", async () => { const name = randomName() document.body.innerHTML = `hello
") } register(Component, name) await delay(100) assertEquals(queryByClass(name).innerHTML, "hello
") })