// @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") }) }) })