2
0

build: 🏗️ Import typebot-js source

This commit is contained in:
Baptiste Arnaud
2022-03-10 17:47:59 +01:00
parent 31298e39c1
commit d134a265cd
34 changed files with 3321 additions and 64 deletions

View File

@ -0,0 +1,40 @@
import * as Typebot from "../../src";
beforeEach(() => {
document.body.innerHTML = "";
});
it("should have the corresponding custom color", () => {
expect.assertions(1);
Typebot.initBubble({
button: { color: "#222222" },
publishId: "typebot-id",
});
const buttonElement = document.querySelector(
"#typebot-bubble > button"
) as HTMLElement;
expect(buttonElement.style.backgroundColor).toBe("rgb(34, 34, 34)");
});
it("should have the default svg icon", () => {
expect.assertions(1);
Typebot.initBubble({
publishId: "typebot-id",
});
const buttonIconElement = document.querySelector(
"#typebot-bubble > button > .icon"
) as HTMLElement;
expect(buttonIconElement.tagName).toBe("svg");
});
it("should have the corresponding custom icon", () => {
expect.assertions(1);
Typebot.initBubble({
button: { iconUrl: "https://web.com/icon.png" },
publishId: "typebot-id",
});
const buttonIconElement = document.querySelector(
"#typebot-bubble > button > .icon"
) as HTMLImageElement;
expect(buttonIconElement.src).toBe("https://web.com/icon.png");
});

View File

@ -0,0 +1,91 @@
import * as Typebot from "../../src";
beforeEach(() => {
document.body.innerHTML = "";
});
describe("openBubble", () => {
it("should add the opened bubble", () => {
expect.assertions(3);
const { open } = Typebot.initBubble({
publishId: "typebot-id",
});
const bubble = document.getElementById("typebot-bubble") as HTMLDivElement;
expect(bubble.classList.contains("iframe-opened")).toBe(false);
open();
expect(bubble.classList.contains("iframe-opened")).toBe(true);
expect(open).not.toThrow();
});
it("should hide the proactive message", () => {
expect.assertions(2);
const { open, openProactiveMessage } = Typebot.initBubble({
publishId: "typebot-id",
proactiveMessage: {
textContent: "Hi click here!",
avatarUrl: "https://website.com/my-avatar.png",
},
});
const bubble = document.getElementById("typebot-bubble") as HTMLDivElement;
if (openProactiveMessage) openProactiveMessage();
expect(bubble.classList.contains("message-opened")).toBe(true);
open();
expect(bubble.classList.contains("message-opened")).toBe(false);
});
});
describe("closeBubble", () => {
it("should remove the corresponding class", () => {
expect.assertions(2);
const { close, open } = Typebot.initBubble({
publishId: "typebot-id",
});
open();
const bubble = document.getElementById("typebot-bubble") as HTMLDivElement;
expect(bubble.classList.contains("iframe-opened")).toBe(true);
close();
expect(bubble.classList.contains("iframe-opened")).toBe(false);
});
});
describe("openProactiveMessage", () => {
it("should add the opened className", () => {
expect.assertions(1);
const { openProactiveMessage } = Typebot.initBubble({
proactiveMessage: {
textContent: "Hi click here!",
},
publishId: "typebot-id",
});
const bubble = document.getElementById("typebot-bubble") as HTMLDivElement;
if (openProactiveMessage) openProactiveMessage();
expect(bubble.classList.contains("message-opened")).toBe(true);
});
it("shouldn't be returned if no message", () => {
expect.assertions(1);
const { openProactiveMessage } = Typebot.initBubble({
publishId: "typebot-id",
});
expect(openProactiveMessage).toBeUndefined();
});
});
describe("Request commands afterwards", () => {
it("should return defined commands", () => {
Typebot.initBubble({
proactiveMessage: {
textContent: "Hi click here!",
},
publishId: "typebot-id",
});
const { close, open, openProactiveMessage } = Typebot.getBubbleActions();
expect(close).toBeDefined();
expect(open).toBeDefined();
expect(openProactiveMessage).toBeDefined();
open();
const bubble = document.getElementById("typebot-bubble") as HTMLDivElement;
expect(bubble.classList.contains("iframe-opened")).toBe(true);
});
});

View File

@ -0,0 +1,30 @@
import * as Typebot from "../../src";
describe("initBubble", () => {
beforeEach(() => {
document.body.innerHTML = "";
});
it("should initialize a bubble embed", () => {
expect.assertions(2);
Typebot.initBubble({ publishId: "typebot-id" });
const bubbleElement = document.getElementById("typebot-bubble");
const frame = document.getElementsByTagName("iframe")[0];
expect(frame).toBeDefined();
expect(bubbleElement).toBeDefined();
});
it("should overwrite bubble if exists", () => {
expect.assertions(2);
Typebot.initBubble({
publishId: "typebot-id",
hiddenVariables: { var1: "test" },
});
Typebot.initBubble({ publishId: "typebot-id2" });
const frames = document.getElementsByTagName("iframe");
expect(frames).toHaveLength(1);
expect(frames[0].dataset.src).toBe(
"https://typebot-viewer.vercel.app/typebot-id2?hn=localhost"
);
});
});

View File

@ -0,0 +1,104 @@
import * as Typebot from "../../src";
beforeEach(() => {
document.body.innerHTML = "";
});
it("should create the message", () => {
expect.assertions(2);
Typebot.initBubble({
proactiveMessage: { textContent: "Hi click here!" },
publishId: "typebot-id",
});
const paragraphElement = document.querySelector(
"#typebot-bubble > .proactive-message > p"
);
const closeButton = document.querySelector(
"#typebot-bubble > .proactive-message > .close-button"
);
expect(paragraphElement?.textContent).toBe("Hi click here!");
expect(closeButton).toBeTruthy();
});
it("should have the corresponding avatar", () => {
expect.assertions(1);
Typebot.initBubble({
proactiveMessage: {
textContent: "Hi click here!",
avatarUrl: "https://website.com/my-avatar.png",
},
publishId: "typebot-id",
});
const avatarElement = document.querySelector(
"#typebot-bubble > .proactive-message > img"
) as HTMLImageElement;
expect(avatarElement.src).toBe("https://website.com/my-avatar.png");
});
it("shouldn't have opened class if delay not defined", () => {
expect.assertions(1);
Typebot.initBubble({
proactiveMessage: {
textContent: "Hi click here!",
},
publishId: "typebot-id",
});
const bubble = document.querySelector("#typebot-bubble") as HTMLDivElement;
expect(bubble.classList.contains("message-opened")).toBe(false);
});
it("should show almost immediately if delay is 0", async () => {
expect.assertions(1);
Typebot.initBubble({
proactiveMessage: {
textContent: "Hi click here!",
delay: 0,
},
publishId: "typebot-id",
});
const bubble = document.querySelector("#typebot-bubble") as HTMLDivElement;
await new Promise((r) => setTimeout(r, 1));
expect(bubble.classList.contains("message-opened")).toBe(true);
});
it("show after the corresponding delay", async () => {
expect.assertions(2);
Typebot.initBubble({
proactiveMessage: {
textContent: "Hi click here!",
delay: 1000,
},
publishId: "typebot-id",
});
const bubble = document.querySelector("#typebot-bubble") as HTMLDivElement;
expect(bubble.classList.contains("message-opened")).toBe(false);
await new Promise((r) => setTimeout(r, 1000));
expect(bubble.classList.contains("message-opened")).toBe(true);
});
it("should remember close decision if set to true", () => {
expect.assertions(2);
Typebot.initBubble({
proactiveMessage: {
textContent: "Hi click here!",
delay: 1000,
},
publishId: "typebot-id",
});
const rememberCloseDecisionFromStorage = localStorage.getItem(
Typebot.localStorageKeys.rememberClose
);
expect(rememberCloseDecisionFromStorage).toBeNull();
Typebot.initBubble({
proactiveMessage: {
textContent: "Hi click here!",
delay: 1000,
rememberClose: true,
},
publishId: "typebot-id",
});
const refreshedRememberCloseDecisionFromStorage = localStorage.getItem(
Typebot.localStorageKeys.rememberClose
);
expect(refreshedRememberCloseDecisionFromStorage).toBe("true");
});

View File

@ -0,0 +1,86 @@
import { initContainer } from "../src/embedTypes/container";
const observe = jest.fn();
const unobserve = jest.fn();
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
window.IntersectionObserver = jest.fn(() => ({
observe,
unobserve,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
})) as any;
describe("initContainer", () => {
beforeEach(() => (document.body.innerHTML = ``));
it("should initialize a valid typebot container", () => {
expect.assertions(3);
const containerId = "container-id";
document.body.innerHTML = `<div id="${containerId}"></div>`;
const iframe = initContainer(containerId, { publishId: "typebot-id" });
const container = document.getElementById(containerId);
expect(container?.children).toHaveLength(1);
expect(container?.children[0].tagName).toBe("IFRAME");
expect(iframe).toBeDefined();
});
it("should return undefined if container doesn't exist", () => {
expect.assertions(1);
const containerId = "container-id";
const iframe = initContainer(containerId, { publishId: "typebot-id" });
expect(iframe).toBeUndefined();
});
it("should return exisiting container", () => {
expect.assertions(1);
const containerId = "container-id";
document.body.innerHTML = `<div id="${containerId}"></div>`;
const iframe1 = initContainer(containerId, { publishId: "typebot-id" });
const iframe2 = initContainer(containerId, { publishId: "typebot-id" });
expect(iframe1?.id).toBe(iframe2?.id);
});
it("should create multiple containers correctly", () => {
expect.assertions(5);
const firstId = "container-1";
const secondId = "container-2";
document.body.innerHTML = `<div id="${firstId}"></div><div id="${secondId}"></div>`;
const firstIframeElement = initContainer(firstId, {
publishId: "typebot-id",
});
const secondIframeElement = initContainer(firstId, {
publishId: "typebot-id",
});
const thirdIframeElement = initContainer(secondId, {
publishId: "typebot-id",
});
expect(firstIframeElement).toBeDefined();
expect(secondIframeElement).toBeDefined();
expect(thirdIframeElement).toBeDefined();
expect(firstIframeElement?.id).toBe(secondIframeElement?.id);
expect(firstIframeElement?.id).not.toBe(thirdIframeElement?.id);
});
it("should be lazy loading by default", () => {
expect.assertions(2);
const containerId = "container";
document.body.innerHTML = `<div id="${containerId}"></div>`;
const iframe = initContainer(containerId, {
publishId: "typebot-id",
}) as HTMLIFrameElement;
expect(iframe.dataset.src).toBeDefined();
expect(iframe.src).toBeFalsy();
});
it("shouldn't be lazy if setting param to false", () => {
expect.assertions(2);
const containerId = "container";
document.body.innerHTML = `<div id="${containerId}"></div>`;
const iframe = initContainer(containerId, {
publishId: "typebot-id",
loadWhenVisible: false,
}) as HTMLIFrameElement;
expect(iframe.dataset.src).toBeUndefined();
expect(iframe.src).toBeTruthy();
});
});

View File

@ -0,0 +1,132 @@
import { createIframe } from "../src/iframe";
describe("createIframe", () => {
it("should create a valid iframe element", () => {
expect.assertions(3);
const iframeElement = createIframe({
publishId: "typebot-id",
});
expect(iframeElement.tagName).toBe("IFRAME");
expect(iframeElement.getAttribute("data-id")).toBe("typebot-id");
expect(iframeElement.getAttribute("src")).toBe(
"https://typebot-viewer.vercel.app/typebot-id?hn=localhost"
);
});
it("should parse the right src prop if custom domain and starterVariables", () => {
expect.assertions(1);
const iframes = [
createIframe({
publishId: "typebot-id",
hiddenVariables: { var1: "value1", var2: "value2", var3: undefined },
}),
];
expect(iframes[0].getAttribute("src")).toBe(
"https://typebot-viewer.vercel.app/typebot-id?hn=localhost&var1=value1&var2=value2"
);
});
it("should have a custom background color if defined", () => {
expect.assertions(1);
const iframeElement = createIframe({
publishId: "typebot-id",
backgroundColor: "green",
});
expect(iframeElement.style.backgroundColor).toBe("green");
});
it("should have a lazy loading behavior if defined", () => {
expect.assertions(2);
const iframeElement = createIframe({
publishId: "typebot-id",
loadWhenVisible: true,
});
expect(iframeElement.getAttribute("data-src")).toBe(
"https://typebot-viewer.vercel.app/typebot-id?hn=localhost"
);
expect(iframeElement.getAttribute("src")).toBeFalsy();
});
it("should redirect on event", async () => {
expect.assertions(1);
createIframe({
publishId: "typebot-id",
});
window.open = jest.fn();
window.postMessage(
{
from: "typebot",
redirectUrl: "https://google.fr",
},
"*"
);
await new Promise((r) => setTimeout(r, 1));
expect(window.open).toHaveBeenCalledWith("https://google.fr");
});
it("should trigger var callback on var event", async () => {
expect.assertions(2);
let n, v;
createIframe({
publishId: "typebot-id",
onNewVariableValue: ({ name, value }) => {
v = value;
n = name;
},
});
window.postMessage(
{
from: "typebot",
newVariableValue: { name: "varName", value: "varValue" },
},
"*"
);
await new Promise((r) => setTimeout(r, 1));
expect(n).toBe("varName");
expect(v).toBe("varValue");
});
it("should notify when video played", async () => {
expect.assertions(1);
let hit = false;
createIframe({
publishId: "typebot-id",
onVideoPlayed: () => {
hit = true;
},
});
window.postMessage(
{
from: "typebot",
videoPlayed: true,
},
"*"
);
await new Promise((r) => setTimeout(r, 1));
expect(hit).toBe(true);
});
it("shouldn't execute callbacks if event from other than typebot", async () => {
expect.assertions(3);
let n, v;
createIframe({
publishId: "typebot-id",
onNewVariableValue: ({ name, value }) => {
v = value;
n = name;
},
});
window.open = jest.fn();
window.postMessage(
{
redirectUrl: "https://google.fr",
newVariableValue: { name: "varName", value: "varValue" },
},
"*"
);
await new Promise((r) => setTimeout(r, 1));
expect(window.open).not.toHaveBeenCalled();
expect(n).toBeUndefined();
expect(v).toBeUndefined();
});
});

View File

@ -0,0 +1,111 @@
import { getPopupActions, initPopup } from "../src/embedTypes/popup";
describe("initPopup", () => {
beforeEach(() => {
document.body.innerHTML = "";
});
it("should return the popupElement with lazy iframe", () => {
expect.assertions(2);
initPopup({ publishId: "typebot-id" });
const popupElement = document.getElementById("typebot-popup");
const iframeElement = popupElement?.children[0] as HTMLIFrameElement;
expect(popupElement).toBeTruthy();
expect(iframeElement.dataset.src).toBeDefined();
});
it("should overwrite if exists", () => {
expect.assertions(2);
initPopup({ publishId: "typebot-id", hiddenVariables: { test1: "yo" } });
initPopup({ publishId: "typebot-id2" });
const elements = document.getElementsByTagName("iframe");
expect(elements).toHaveLength(1);
expect(elements[0].dataset.src).toBe(
"https://typebot-viewer.vercel.app/typebot-id2?hn=localhost"
);
});
it("shouldn't have opened classname if no delay", () => {
expect.assertions(1);
initPopup({ publishId: "typebot-id" });
const popupElement = document.getElementById("typebot-popup");
expect(popupElement?.classList.contains("opened")).toBe(false);
});
it("should have the opened classname after the delay", async () => {
expect.assertions(2);
initPopup({ delay: 500, publishId: "typebot-id" });
const popupElement = document.getElementById("typebot-popup");
expect(popupElement?.classList.contains("opened")).toBe(false);
await new Promise((r) => setTimeout(r, 1000));
expect(popupElement?.classList.contains("opened")).toBe(true);
});
});
describe("openPopup", () => {
beforeEach(() => {
document.body.innerHTML = "";
});
it("should add opened className and lazy load", () => {
expect.assertions(5);
const { open } = initPopup({ publishId: "typebot-id" });
const popupElement = document.getElementById("typebot-popup");
expect(popupElement?.children[0].getAttribute("data-src")).toBeTruthy();
open();
expect(popupElement?.classList.contains("opened")).toBe(true);
expect(document.body.style.overflowY).toBe("hidden");
expect(popupElement?.children[0].getAttribute("data-src")).toBeFalsy();
expect(open).not.toThrow();
});
it("should still work if initializing a second time", () => {
expect.assertions(2);
initPopup({ publishId: "typebot-id" });
const { open } = initPopup({ publishId: "typebot-id" });
const popupElement = document.getElementById("typebot-popup");
open();
expect(popupElement?.classList.contains("opened")).toBe(true);
expect(document.body.style.overflowY).toBe("hidden");
});
});
describe("closePopup", () => {
beforeEach(() => {
document.body.innerHTML = "";
});
it("shouldn remove opened className", () => {
expect.assertions(2);
const { close } = initPopup({ publishId: "typebot-id" });
const popupElement = document.getElementById("typebot-popup");
close();
expect(popupElement?.classList.contains("opened")).toBe(false);
expect(document.body.style.overflowY).toBe("auto");
});
it("should still work if initializing a second time", () => {
expect.assertions(2);
initPopup({ publishId: "typebot-id" });
const { close } = initPopup({ publishId: "typebot-id" });
const popupElement = document.getElementById("typebot-popup");
close();
expect(popupElement?.classList.contains("opened")).toBe(false);
expect(document.body.style.overflowY).toBe("auto");
});
});
describe("Request commands afterwards", () => {
it("should return defined commands", () => {
initPopup({
publishId: "typebot-id",
});
const { close, open } = getPopupActions();
expect(close).toBeDefined();
expect(open).toBeDefined();
open();
const popup = document.getElementById("typebot-popup") as HTMLDivElement;
expect(popup.classList.contains("opened")).toBe(true);
});
});