// @vitest-environment jsdom
import {
cleanup,
fireEvent,
render,
screen,
waitFor,
within,
} from "@testing-library/react"
import { afterEach, describe, expect, it } from "vitest"
import {
Date,
defineLexicalAction,
DraggableBlocks,
Image,
LexicalActions,
LexicalContent,
LexicalFixedToolbar,
LexicalRoot,
Link,
Video,
} from "."
afterEach(cleanup)
function RegisteredPlugin() {
return registered
}
const RegisteredCapability = defineLexicalAction({
name: "registered-capability",
label: "Registered capability",
hidden: true,
plugins: [RegisteredPlugin],
execute: () => undefined,
})
describe("Lexical advanced actions", () => {
it("registers non-visual plugins through an action declaration", () => {
render(
undefined}>
)
expect(screen.getByTestId("registered-plugin").textContent).toBe(
"registered"
)
})
it("registers draggable blocks declaratively", async () => {
const { container } = render(
undefined}>
)
await waitFor(() => {
expect(
container
.querySelector("[contenteditable=true]")
?.classList.contains("lexical-draggable-content")
).toBe(true)
})
})
it("registers link nodes and plugins through the Link action", async () => {
const { container } = render(
undefined}
>
)
const link = await waitFor(() => {
const element = container.querySelector("a")
expect(element).not.toBeNull()
return element!
})
Object.defineProperty(link, "getBoundingClientRect", {
value: () => ({
bottom: 80,
height: 20,
left: 20,
right: 120,
top: 60,
width: 100,
x: 20,
y: 60,
toJSON: () => undefined,
}),
})
fireEvent.click(link)
expect(
await screen.findByRole("button", { name: "Edit link" })
).not.toBeNull()
})
it("registers the Date node and popover through the Date action", async () => {
const { container } = render(
undefined}
>
)
const date = await waitFor(() => {
const element = container.querySelector(
"[data-lexical-date]"
)
expect(element).not.toBeNull()
return element!
})
fireEvent.click(date)
expect(await screen.findByRole("grid")).not.toBeNull()
})
it("lets a custom Image control insert and operate on an image", async () => {
const { container } = render(
undefined}>
{({ execute }) => (
)}
)
fireEvent.click(screen.getByRole("button", { name: "Upload image" }))
const image = await screen.findByRole("img", { name: "Custom image" })
expect(image.getAttribute("src")).toBe("/custom-image.png")
expect(screen.getByText("Uploaded externally")).not.toBeNull()
fireEvent.click(image)
await waitFor(() => {
expect(
container.querySelectorAll("[data-lexical-image-resize-handle]")
).toHaveLength(8)
})
fireEvent.click(screen.getByRole("button", { name: "Align image right" }))
await waitFor(() => {
expect(image.closest("figure")?.classList.contains("items-end")).toBe(
true
)
})
expect(screen.getByRole("button", { name: "Delete image" })).not.toBeNull()
fireEvent.click(screen.getByRole("button", { name: "Edit caption" }))
const caption = screen.getByRole("textbox", { name: "Caption" })
fireEvent.change(caption, { target: { value: "Updated caption" } })
expect((caption as HTMLTextAreaElement).value).toBe("Updated caption")
})
it("reads an image selected from the insert dialog as a Base64 data URL", async () => {
const { container } = render(
undefined}>
)
fireEvent.click(screen.getByRole("button", { name: "Insert image" }))
const dialog = await screen.findByRole("dialog")
const file = new File([new Uint8Array([137, 80, 78, 71])], "local.png", {
type: "image/png",
})
fireEvent.change(within(dialog).getByLabelText("Image file"), {
target: { files: [file] },
})
const urlInput = within(dialog).getByRole("textbox", {
name: "Image URL",
})
await waitFor(() => {
expect((urlInput as HTMLInputElement).value).toMatch(
/^data:image\/png;base64,/
)
})
fireEvent.change(
within(dialog).getByRole("textbox", { name: "Alternative text" }),
{
target: { value: "Local image" },
}
)
fireEvent.submit(dialog.querySelector("form")!)
await waitFor(() => {
expect(
screen.getByRole("img", { name: "Local image" }).getAttribute("src")
).toMatch(/^data:image\/png;base64,/)
})
expect(container.querySelector("figure")).not.toBeNull()
})
it("lets a custom Video control insert a video through execute", async () => {
const { container } = render(
undefined}>
)
fireEvent.click(screen.getByRole("button", { name: "Upload video" }))
await waitFor(() => {
const video = container.querySelector("video")
expect(video?.getAttribute("src")).toBe("/custom-video.mp4")
expect(video?.getAttribute("poster")).toBe("/custom-poster.png")
})
})
})