saleor-app-sdk-REDIS_APL/src/app-bridge/app-bridge.test.ts

224 lines
5.3 KiB
TypeScript
Raw Normal View History

import { fireEvent } from "@testing-library/dom";
2022-08-11 21:14:41 +00:00
import { beforeEach, describe, expect, it, vi } from "vitest";
import { LocaleCode } from "../locales";
// eslint-disable-next-line
import { actions, AppBridge, DispatchResponseEvent, HandshakeEvent, ThemeEvent } from ".";
// mock document.referrer
const origin = "http://example.com";
2022-08-22 13:53:03 +00:00
const domain = "saleor.domain.host";
Object.defineProperty(window.document, "referrer", {
value: origin,
writable: true,
});
Object.defineProperty(window, "location", {
value: {
2022-08-22 13:53:03 +00:00
href: `${origin}?domain=${domain}&id=appid`,
},
writable: true,
});
2022-08-11 21:14:41 +00:00
const handshakeEvent: HandshakeEvent = {
payload: {
token: "mock-token",
version: 1,
},
type: "handshake",
};
const themeEvent: ThemeEvent = {
type: "theme",
payload: {
theme: "light",
},
};
const delay = (timeout: number) =>
new Promise((res) => {
setTimeout(res, timeout);
});
2022-08-22 13:47:40 +00:00
describe("AppBridge", () => {
let appBridge = new AppBridge();
2022-08-11 21:14:41 +00:00
beforeEach(() => {
2022-08-22 13:47:40 +00:00
appBridge = new AppBridge();
2022-08-11 21:14:41 +00:00
});
2022-08-22 13:47:40 +00:00
it("correctly sets the default domain, if not set in constructor", () => {
expect(appBridge.getState().domain).toEqual(domain);
});
it("authenticates", () => {
2022-08-22 13:47:40 +00:00
expect(appBridge.getState().ready).toBe(false);
const token = "test-token";
fireEvent(
window,
new MessageEvent("message", {
data: { type: "handshake", payload: { token } },
origin,
})
);
2022-08-22 13:47:40 +00:00
expect(appBridge.getState().ready).toBe(true);
expect(appBridge.getState().token).toEqual(token);
});
2022-08-11 21:14:41 +00:00
it("subscribes to an event and returns unsubscribe function", () => {
const callback = vi.fn();
2022-08-22 13:47:40 +00:00
const unsubscribe = appBridge.subscribe("handshake", callback);
expect(callback).not.toHaveBeenCalled();
const token = "fresh-token";
2022-08-11 21:14:41 +00:00
// First call proper event
fireEvent(
window,
new MessageEvent("message", {
2022-08-11 21:14:41 +00:00
data: handshakeEvent,
origin,
})
);
// incorrect event type
fireEvent(
window,
new MessageEvent("message", {
data: { type: "invalid", payload: { token: "invalid" } },
origin,
})
);
// incorrect origin
fireEvent(
window,
new MessageEvent("message", {
data: { type: "handshake", payload: { token } },
origin: "http://wrong.origin.com",
})
);
expect(callback).toHaveBeenCalledTimes(1);
2022-08-11 21:14:41 +00:00
expect(callback).toHaveBeenCalledWith(handshakeEvent.payload);
2022-08-22 13:47:40 +00:00
expect(appBridge.getState().token).toEqual(handshakeEvent.payload.token);
expect(appBridge.getState().id).toEqual("appid");
unsubscribe();
fireEvent(
window,
new MessageEvent("message", {
data: { type: "handshake", payload: { token: "123" } },
origin,
})
);
expect(callback).toHaveBeenCalledTimes(1);
2022-08-22 13:47:40 +00:00
expect(appBridge.getState().token).toEqual("123");
});
it("Subscribes to theme change event and runs callback with new value after delay", async () => {
expect.assertions(2);
const callback = vi.fn();
const unsubscribe = appBridge.subscribe("theme", callback);
await delay(200);
fireEvent(
window,
new MessageEvent("message", {
data: themeEvent,
origin,
})
);
expect(callback).toHaveBeenCalledOnce();
expect(callback).toHaveBeenCalledWith({ theme: "light" });
unsubscribe();
});
it("persists domain", () => {
2022-08-22 13:47:40 +00:00
expect(appBridge.getState().domain).toEqual(domain);
});
it("dispatches valid action", () => {
const target = "/test";
const action = actions.Redirect({ to: target });
window.addEventListener("message", (event) => {
if (event.data.type === action.type) {
fireEvent(
window,
new MessageEvent("message", {
data: {
type: "response",
payload: { ok: true, actionId: action.payload.actionId },
} as DispatchResponseEvent,
origin,
})
);
}
});
2022-08-22 13:47:40 +00:00
return expect(appBridge.dispatch(action)).resolves.toBeUndefined();
});
it("times out after action response has not been registered", () =>
2022-08-22 13:47:40 +00:00
expect(appBridge.dispatch(actions.Redirect({ to: "/test" }))).rejects.toBeInstanceOf(Error));
2022-08-11 21:14:41 +00:00
it("unsubscribes from all listeners", () => {
const cb1 = vi.fn();
const cb2 = vi.fn();
2022-08-22 13:47:40 +00:00
appBridge.subscribe("handshake", cb1);
appBridge.subscribe("handshake", cb2);
2022-08-11 21:14:41 +00:00
fireEvent(
window,
new MessageEvent("message", {
data: handshakeEvent,
origin,
})
);
expect(cb1).toHaveBeenCalledTimes(1);
expect(cb2).toHaveBeenCalledTimes(1);
2022-08-22 13:47:40 +00:00
appBridge.unsubscribeAll();
2022-08-11 21:14:41 +00:00
fireEvent(
window,
new MessageEvent("message", {
data: handshakeEvent,
origin,
})
);
expect(cb1).toHaveBeenCalledTimes(1);
expect(cb2).toHaveBeenCalledTimes(1);
});
2022-08-22 13:47:40 +00:00
it("attaches domain from options in constructor", () => {
appBridge = new AppBridge({
targetDomain: "https://foo.bar",
});
expect(appBridge.getState().domain).toEqual("https://foo.bar");
});
it.each<LocaleCode>(["pl", "en", "it"])("sets initial locale \"%s\" from constructor", (locale) => {
const instance = new AppBridge({
initialLocale: locale,
});
expect(instance.getState().locale).toBe(locale);
});
});