diff --git a/src/element/textElement.test.ts b/src/element/textElement.test.ts new file mode 100644 index 00000000..3c08b279 --- /dev/null +++ b/src/element/textElement.test.ts @@ -0,0 +1,140 @@ +import { wrapText } from "./textElement"; +import { FontString } from "./types"; + +describe("Test wrapText", () => { + const font = "20px Cascadia, width: Segoe UI Emoji" as FontString; + + describe("When text doesn't contain new lines", () => { + const text = "Hello whats up"; + [ + { + desc: "break all words when width of each word is less than container width", + width: 140, + res: `Hello +whats +up`, + }, + { + desc: "break all characters when width of each character is less than container width", + width: 75, + res: `H +e +l +l +o +w +h +a +t +s +u +p`, + }, + { + desc: "break words as per the width", + + width: 200, + res: `Hello whats +up`, + }, + { + desc: "fit the container", + + width: 250, + res: "Hello whats up", + }, + ].forEach((data) => { + it(`should ${data.desc}`, () => { + const res = wrapText(text, font, data.width); + expect(res).toEqual(data.res); + }); + }); + }); + describe("When text contain new lines", () => { + const text = `Hello +whats up`; + [ + { + desc: "break all words when width of each word is less than container width", + width: 140, + res: `Hello +whats +up`, + }, + { + desc: "break all characters when width of each character is less than container width", + width: 75, + res: `H +e +l +l +o +w +h +a +t +s +u +p`, + }, + { + desc: "break words as per the width", + + width: 200, + res: `Hello +whats up`, + }, + { + desc: "fit the container", + + width: 250, + res: `Hello +whats up`, + }, + ].forEach((data) => { + it(`should respect new lines and ${data.desc}`, () => { + const res = wrapText(text, font, data.width); + expect(res).toEqual(data.res); + }); + }); + }); + describe("When text is long", () => { + const text = `hellolongtextthisiswhatsupwithyouIamtypingggggandtypinggg break it now`; + [ + { + desc: "fit characters of long string as per container width", + width: 220, + res: `hellolongtextth +isiswhatsupwith +youIamtypingggg +gandtypinggg +break it now`, + }, + + { + desc: "fit characters of long string as per container width and break words as per the width", + + width: 180, + res: `hellolongte +xtthisiswha +tsupwithyou +Iamtypinggg +ggandtyping +gg break it +now`, + }, + { + desc: "fit the long text when container width is greater than text length and move the rest to next line", + + width: 650, + res: `hellolongtextthisiswhatsupwithyouIamtypingggggandtypinggg +break it now`, + }, + ].forEach((data) => { + it(`should ${data.desc}`, () => { + const res = wrapText(text, font, data.width); + expect(res).toEqual(data.res); + }); + }); + }); +}); diff --git a/src/element/textElement.ts b/src/element/textElement.ts index 713f87ac..155ca201 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -1,4 +1,4 @@ -import { getFontString, arrayToMap } from "../utils"; +import { getFontString, arrayToMap, isTestEnv } from "../utils"; import { ExcalidrawBindableElement, ExcalidrawElement, @@ -200,6 +200,12 @@ const getTextWidth = (text: string, font: FontString) => { canvas2dContext.font = font; const metrics = canvas2dContext.measureText(text); + // since in test env the canvas measureText algo + // doesn't measure text and instead just returns number of + // characters hence we assume that each letteris 10px + if (isTestEnv()) { + return metrics.width * 10; + } return metrics.width; }; diff --git a/src/utils.ts b/src/utils.ts index f085bf3c..82ab78d1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -458,3 +458,5 @@ export const arrayToMap = ( return acc; }, new Map()); }; + +export const isTestEnv = () => process?.env?.NODE_ENV === "test";