@canva/create-app
Version:
A command line tool for creating Canva Apps.
253 lines (245 loc) • 9.17 kB
text/typescript
import { TableWrapper } from "../table_wrapper";
import type { Cell, TableElement } from "@canva/design";
describe("TableWrapper", () => {
describe("create", () => {
it("should create a new table", () => {
const wrapper = TableWrapper.create(2, 3);
const element = wrapper.toElement();
expect(element.rows.length).toBe(2);
expect(element.rows[0].cells.length).toBe(3);
expect(element.rows[1].cells.length).toBe(3);
});
it("should throw an error if the row count is less than 1", () => {
expect(() => TableWrapper.create(0, 1)).toThrow();
});
it("should throw an error if the column count is less than 1", () => {
expect(() => TableWrapper.create(1, 0)).toThrow();
});
it("should throw an error if the number of cells exceeds 225", () => {
expect(() => TableWrapper.create(16, 15)).toThrow();
});
});
describe("fromElement", () => {
it("should create a table wrapper from an existing table element", () => {
const element: TableElement = {
type: "table",
rows: [
{
cells: [
{ colSpan: 2, type: "empty" },
{ type: "empty" },
{ rowSpan: 2, type: "empty" },
],
},
{
cells: [
{
type: "string",
value: "hello",
},
{
type: "empty",
attributes: { backgroundColor: "#ff00ff" },
},
{ type: "empty" },
],
},
],
};
const wrapper = TableWrapper.fromElement(element);
expect(wrapper.toElement()).toEqual(element);
// Make sure the new element is not a reference
if (element.rows[1].cells[1]?.attributes) {
element.rows[1].cells[1].attributes.backgroundColor = "#ff0000";
}
expect(wrapper.toElement()).not.toEqual(element);
});
it("should throw an error if the element is not a table", () => {
const element = {
type: "TEXT",
children: ["hello"],
};
expect(() => {
TableWrapper.fromElement(element as unknown as TableElement);
}).toThrow();
});
it("should throw an error if the element has no rows", () => {
expect(() => {
TableWrapper.fromElement({
type: "TABLE",
} as unknown as TableElement);
}).toThrow();
expect(() => {
TableWrapper.fromElement({
type: "table",
rows: [],
});
}).toThrow();
});
it("should throw an error if any row of the element has no cells", () => {
const element: TableElement = {
type: "table",
rows: [{ cells: [] }],
};
expect(() => {
TableWrapper.fromElement(element);
}).toThrow();
});
it("should throw an error if number of cells is inconsistent", () => {
const element: TableElement = {
type: "table",
rows: [
{ cells: [{ type: "empty" }, { type: "empty" }] },
{ cells: [{ type: "empty" }] },
],
};
expect(() => {
TableWrapper.fromElement(element);
}).toThrow();
});
});
describe("addRow", () => {
it("should add a row to the table", () => {
const wrapper = TableWrapper.create(2, 3);
wrapper.addRow(0);
const element = wrapper.toElement();
expect(element.rows.length).toBe(3);
expect(element.rows[0].cells.length).toBe(3);
});
it("should copy the fill value if top and bottom cells are the same", () => {
const wrapper = TableWrapper.create(2, 3);
wrapper.setCellDetails(1, 1, {
type: "empty",
attributes: { backgroundColor: "#ff0000" },
});
wrapper.setCellDetails(2, 1, {
type: "empty",
attributes: { backgroundColor: "#ff0000" },
});
wrapper.addRow(1);
const newCell = wrapper.getCellDetails(2, 1);
expect(newCell?.attributes).toBeDefined();
expect(newCell?.attributes?.backgroundColor).toBe("#ff0000");
});
it("should expand the row span if top and bottom cells belong to the same merged cell", () => {
const wrapper = TableWrapper.create(2, 3);
wrapper.setCellDetails(1, 1, { rowSpan: 2, type: "empty" });
wrapper.addRow(1);
const mergedCell = wrapper.getCellDetails(1, 1);
expect(mergedCell?.rowSpan).toBe(3);
});
it("should throw an error if the row position is out of bounds", () => {
const wrapper = TableWrapper.create(2, 3);
expect(() => wrapper.addRow(-1)).toThrow();
expect(() => wrapper.addRow(3)).toThrow();
});
});
describe("addColumn", () => {
it("should add a column to the table", () => {
const wrapper = TableWrapper.create(2, 3);
wrapper.addColumn(0);
const element = wrapper.toElement();
expect(element.rows.length).toBe(2);
expect(element.rows[0].cells.length).toBe(4);
});
it("should copy the fill value if left and right cells are the same", () => {
const wrapper = TableWrapper.create(2, 3);
wrapper.setCellDetails(1, 1, {
type: "empty",
attributes: { backgroundColor: "#ff0000" },
});
wrapper.setCellDetails(1, 2, {
type: "empty",
attributes: { backgroundColor: "#ff0000" },
});
wrapper.addColumn(1);
const newCell = wrapper.getCellDetails(1, 2);
expect(newCell?.attributes).toBeDefined();
expect(newCell?.attributes?.backgroundColor).toBe("#ff0000");
});
it("should expand the column span if left and right cells belong to the same merged cell", () => {
const wrapper = TableWrapper.create(2, 3);
wrapper.setCellDetails(1, 1, { type: "empty", colSpan: 2 });
wrapper.addColumn(1);
const mergedCell = wrapper.getCellDetails(1, 1);
expect(mergedCell?.colSpan).toBe(3);
});
it("should throw an error if the column position is out of bounds", () => {
const wrapper = TableWrapper.create(2, 3);
expect(() => wrapper.addColumn(-1)).toThrow();
expect(() => wrapper.addColumn(4)).toThrow();
});
});
describe("isGhostCell", () => {
it("should return true if the cell is a ghost cell", () => {
const wrapper = TableWrapper.create(2, 3);
wrapper.setCellDetails(1, 1, { type: "empty", colSpan: 2 });
expect(wrapper.isGhostCell(1, 1)).toBe(false);
expect(wrapper.isGhostCell(1, 2)).toBe(true);
expect(wrapper.isGhostCell(1, 3)).toBe(false);
});
it("should throw an error if the position is out of bounds", () => {
const wrapper = TableWrapper.create(2, 3);
expect(() => wrapper.isGhostCell(0, 1)).toThrow();
expect(() => wrapper.isGhostCell(3, 1)).toThrow();
expect(() => wrapper.isGhostCell(1, 0)).toThrow();
expect(() => wrapper.isGhostCell(1, 4)).toThrow();
});
});
describe("setCellDetails", () => {
it("should set the cell details", () => {
const wrapper = TableWrapper.create(2, 3);
wrapper.setCellDetails(1, 1, {
colSpan: 2,
rowSpan: 2,
type: "string",
value: "hello",
attributes: { backgroundColor: "#ff0000" },
});
expect(wrapper.isGhostCell(1, 1)).toBe(false);
expect(wrapper.isGhostCell(1, 2)).toBe(true);
expect(wrapper.isGhostCell(2, 1)).toBe(true);
expect(wrapper.isGhostCell(2, 2)).toBe(true);
const element = wrapper.toElement();
const firstCell = element.rows[0].cells[0] as Cell & {
type: "string";
value: string;
};
expect(firstCell?.type).toBe("string");
expect(firstCell.value).toBe("hello");
expect(firstCell.attributes).toBeDefined();
expect(firstCell.attributes?.backgroundColor).toBe("#ff0000");
});
it("should throw an error if the position is out of bounds", () => {
const wrapper = TableWrapper.create(2, 3);
expect(() => wrapper.setCellDetails(0, 1, { type: "empty" })).toThrow();
expect(() => wrapper.setCellDetails(3, 1, { type: "empty" })).toThrow();
expect(() => wrapper.setCellDetails(1, 0, { type: "empty" })).toThrow();
expect(() => wrapper.setCellDetails(1, 4, { type: "empty" })).toThrow();
});
it("should throw an error if the rowSpan is invalid", () => {
const wrapper = TableWrapper.create(2, 3);
expect(() =>
wrapper.setCellDetails(1, 1, { type: "empty", rowSpan: -1 }),
).toThrow();
expect(() =>
wrapper.setCellDetails(1, 1, { type: "empty", rowSpan: 0 }),
).toThrow();
expect(() =>
wrapper.setCellDetails(1, 1, { type: "empty", rowSpan: 3 }),
).toThrow();
});
it("should throw an error if the colSpan is invalid", () => {
const wrapper = TableWrapper.create(2, 3);
expect(() =>
wrapper.setCellDetails(1, 1, { type: "empty", colSpan: -1 }),
).toThrow();
expect(() =>
wrapper.setCellDetails(1, 1, { type: "empty", colSpan: 0 }),
).toThrow();
expect(() =>
wrapper.setCellDetails(1, 1, { type: "empty", colSpan: 4 }),
).toThrow();
});
});
});