/* eslint-disable sonarjs/no-duplicate-string */ import { GridCellKind, type GridCell, BooleanIndeterminate } from "../src/index.js"; import { decodeHTML, getCopyBufferContents, type CellBuffer } from "../src/data-editor/copy-paste.js"; import { expect, describe, test } from "vitest"; function makeCellBuffer( rawValue: string | string[], formatted = rawValue, format: CellBuffer["format"] = "string" ): CellBuffer { return { rawValue, formatted, format, } as CellBuffer; } describe("copy-paste", () => { test("decode html", () => { const html = `
1 2
3 4
`; const decoded = decodeHTML(html); expect(decoded).toEqual([ [makeCellBuffer("1"), makeCellBuffer("2")], [makeCellBuffer("3"), makeCellBuffer("4")], ]); }); test("decode html line breaks", () => { const html = `
1
1.1
2
2.1
3 4
`; const decoded = decodeHTML(html); expect(decoded).toEqual([ [makeCellBuffer("1\n1.1"), makeCellBuffer("2\n2.1")], [makeCellBuffer("3"), makeCellBuffer("4")], ]); }); test("Simple text cell", () => { const cells: GridCell[][] = [ [ { kind: GridCellKind.Text, data: "Hello", allowOverlay: true, displayData: "Display Hello", }, ], ]; const columnIndexes = [0]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe("Display Hello"); expect(result.textHtml).toContain('Display Hello'); }); test("Simple text cell with multiple spaces", () => { const cells: GridCell[][] = [ [ { kind: GridCellKind.Text, data: "Hello", allowOverlay: true, displayData: "Display Hello", }, ], ]; const columnIndexes = [0]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe("Display Hello"); expect(result.textHtml).toContain( 'Display Hello' ); }); test("Simple text cell with special chars", () => { const cells: GridCell[][] = [ [ { kind: GridCellKind.Text, data: '"Hello"', allowOverlay: true, displayData: 'Display "Hello"', }, ], ]; const columnIndexes = [0]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe('"Display ""Hello"""'); expect(result.textHtml).toContain( 'Display "Hello"' ); }); test("Bubble cell encoding", () => { const cells: GridCell[][] = [ [ { kind: GridCellKind.Bubble, data: ["Bubble1", "Bubble2"], allowOverlay: true, }, ], ]; const columnIndexes = [0]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe("Bubble1,Bubble2"); expect(result.textHtml).toContain( '
  1. Bubble1
  2. Bubble2
' ); }); test("format empty bubble cell", () => { expect( getCopyBufferContents( [ [ { kind: GridCellKind.Bubble, allowOverlay: true, data: [], }, ], ], [0] ).textPlain ).toEqual(""); }); test("format url cell", () => { expect( getCopyBufferContents( [ [ { kind: GridCellKind.Uri, allowOverlay: true, data: "https://www.google.com", }, ], ], [0] ).textPlain ).toEqual("https://www.google.com"); }); test("format url cell with display value", () => { expect( getCopyBufferContents( [ [ { kind: GridCellKind.Uri, allowOverlay: true, data: "https://www.google.com", displayData: "Google", }, ], ], [0] ).textPlain ).toEqual("https://www.google.com"); }); test("format empty bubble cell with comma", () => { expect( getCopyBufferContents( [ [ { kind: GridCellKind.Bubble, allowOverlay: true, data: ["foo, bar", "baz"], }, ], ], [0] ).textPlain ).toEqual('"foo, bar",baz'); }); test("format respects copyData", () => { expect( getCopyBufferContents( [ [ { kind: GridCellKind.Bubble, allowOverlay: true, data: ["foo, bar", "baz"], copyData: "override", }, ], ], [0] ).textPlain ).toEqual("override"); }); test("Custom cell type", () => { const cells: GridCell[][] = [ [ { kind: GridCellKind.Custom, copyData: "CustomData", allowOverlay: true, data: "data", }, ], ]; const columnIndexes = [0]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe("CustomData"); expect(result.textHtml).toContain('CustomData'); }); test.each([ [true, "TRUE"], [false, "FALSE"], [BooleanIndeterminate, "INDETERMINATE"], [null, ""], ])("Boolean cell type %p", (data, expectedFormatted) => { const cells: GridCell[][] = [ [ { kind: GridCellKind.Boolean, data, allowOverlay: false, }, ], ]; const columnIndexes = [0]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe(expectedFormatted); expect(result.textHtml).toContain( `${expectedFormatted}` ); }); test("Image cell type", () => { const cells: GridCell[][] = [ [ { kind: GridCellKind.Image, data: ["image1.jpg", "image2.jpg"], allowOverlay: true, readonly: false, }, ], ]; const columnIndexes = [0]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe("image1.jpg,image2.jpg"); expect(result.textHtml).toContain( '
  1. image1.jpg
  2. image2.jpg
' ); }); test.each([ [GridCellKind.Markdown, "markdownContent", "markdownContent", "string"], [GridCellKind.RowID, "row123", "row123", "string"], [GridCellKind.Number, 1234, "1234", "number"], [GridCellKind.Loading, undefined, "#LOADING", "string"], [GridCellKind.Protected, undefined, "************", "string"], ])("Special cell type %p", (kind, data, expectedFormatted, format) => { const cells: GridCell[][] = [ [ { kind, data, displayData: data?.toString(), allowOverlay: true, } as GridCell, ], ]; const columnIndexes = [0]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe(expectedFormatted); expect(result.textHtml).toContain( `${expectedFormatted}` ); }); test("decode html with URLs", () => { const html = `
Example Link
  1. Item1
  2. Item2
`; const decoded = decodeHTML(html); expect(decoded).toEqual([ [ makeCellBuffer("https://example.com", "Example Link", "url"), makeCellBuffer(["item1", "item2"], ["Item1", "Item2"], "string-array"), ], ]); }); }); test("Drilldown cell conversion", () => { const cells: GridCell[][] = [ [ { kind: GridCellKind.Drilldown, data: [{ text: "Drill1" }, { text: "Drill2" }], allowOverlay: true, }, ], ]; const columnIndexes = [0]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe("Drill1,Drill2"); expect(result.textHtml).toContain( '
  1. Drill1
  2. Drill2
' ); }); test("decode non-table HTML", () => { const html = `
Non-table content
`; const decoded = decodeHTML(html); expect(decoded).toBeUndefined(); }); test("handle cell span", () => { const cells: GridCell[][] = [ [ { kind: GridCellKind.Text, data: "Hello", displayData: "Display Hello", span: [0, 1], allowOverlay: true, }, ], ]; const columnIndexes = [1]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe(""); // It should be empty since span doesn't match }); test("escape string with tab character", () => { const cells: GridCell[][] = [ [ { kind: GridCellKind.Text, data: "Hello\tWorld", displayData: "Hello\tWorld", allowOverlay: true, }, ], ]; const columnIndexes = [0]; const result = getCopyBufferContents(cells, columnIndexes); expect(result.textPlain).toBe('"Hello\tWorld"'); }); test("decode ordered list", () => { const html = `
  1. Test1
  2. Test2
`; const decoded = decodeHTML(html); expect(decoded).toEqual([ [ { rawValue: ["test1", "test2"], formatted: ["Test1", "Test2"], format: "string-array", }, ], ]); }); test("decode apple numbers", () => { const html = `

Test

This

Out

With a
newline and such

`; const decoded = decodeHTML(html); expect(decoded).toEqual([ [makeCellBuffer("Test"), makeCellBuffer("This")], [makeCellBuffer("Out"), makeCellBuffer("With a\nnewline and such")], ]); }); test("decode html attributes", () => { const html = `
Hello
`; const decoded = decodeHTML(html); expect(decoded).toEqual([ [ { rawValue: '"Hello"', formatted: "Hello", format: "string", }, ], ]); });