Fix flaky AppTile tests (#31442)
* Bit of cleanup * Attempts to fix * uncomment * Restructure tests * Better reset * Descrew up tests * fix comment * Remove redundant calls
This commit is contained in:
@@ -122,7 +122,6 @@ export default class ThemeWatcher extends TypedEventEmitter<ThemeWatcherEvent, T
|
|||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.log("returning theme value");
|
|
||||||
return SettingsStore.getValue("theme");
|
return SettingsStore.getValue("theme");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Room, type MatrixClient } from "matrix-js-sdk/src/matrix";
|
import { Room, type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
import { type IWidget, MatrixWidgetType } from "matrix-widget-api";
|
import { type IWidget, MatrixWidgetType } from "matrix-widget-api";
|
||||||
import { act, render, type RenderResult, waitForElementToBeRemoved, waitFor } from "jest-matrix-react";
|
import { act, render, waitForElementToBeRemoved, waitFor } from "jest-matrix-react";
|
||||||
import userEvent from "@testing-library/user-event";
|
import userEvent from "@testing-library/user-event";
|
||||||
import {
|
import {
|
||||||
type ApprovalOpts,
|
type ApprovalOpts,
|
||||||
@@ -51,6 +51,8 @@ jest.mock("../../../../../src/stores/OwnProfileStore", () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const realGetValue = SettingsStore.getValue;
|
||||||
|
|
||||||
describe("AppTile", () => {
|
describe("AppTile", () => {
|
||||||
let cli: MatrixClient;
|
let cli: MatrixClient;
|
||||||
let sdkContext: SdkContextClass;
|
let sdkContext: SdkContextClass;
|
||||||
@@ -106,27 +108,40 @@ describe("AppTile", () => {
|
|||||||
if (roomId === "r2") return [app2];
|
if (roomId === "r2") return [app2];
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
// Do not carry across settings from previous tests
|
||||||
|
SettingsStore.reset();
|
||||||
|
sdkContext = new SdkContextClass();
|
||||||
|
// @ts-ignore
|
||||||
|
await WidgetMessagingStore.instance.onReady();
|
||||||
|
|
||||||
// Wake up various stores we rely on
|
// Wake up various stores we rely on
|
||||||
WidgetLayoutStore.instance.useUnitTestClient(cli);
|
WidgetLayoutStore.instance.useUnitTestClient(cli);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await WidgetLayoutStore.instance.onReady();
|
await WidgetLayoutStore.instance.onReady();
|
||||||
|
|
||||||
RightPanelStore.instance.useUnitTestClient(cli);
|
RightPanelStore.instance.useUnitTestClient(cli);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await RightPanelStore.instance.onReady();
|
await RightPanelStore.instance.onReady();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
afterEach(async () => {
|
||||||
sdkContext = new SdkContextClass();
|
|
||||||
jest.spyOn(SettingsStore, "getValue").mockRestore();
|
jest.spyOn(SettingsStore, "getValue").mockRestore();
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await WidgetMessagingStore.instance.onReady();
|
await WidgetLayoutStore.instance.onNotReady();
|
||||||
|
// @ts-ignore
|
||||||
|
await RightPanelStore.instance.onNotReady();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("destroys non-persisted right panel widget on room change", async () => {
|
it("destroys non-persisted right panel widget on room change", async () => {
|
||||||
// Set up right panel state
|
// Set up right panel state
|
||||||
const realGetValue = SettingsStore.getValue;
|
jest.spyOn(SettingsStore, "getValue").mockImplementation((name, roomId) => {
|
||||||
const mockSettings = jest.spyOn(SettingsStore, "getValue").mockImplementation((name, roomId) => {
|
|
||||||
if (name !== "RightPanel.phases") return realGetValue(name, roomId);
|
if (name !== "RightPanel.phases") return realGetValue(name, roomId);
|
||||||
if (roomId === "r1") {
|
if (roomId === "r1") {
|
||||||
return {
|
return {
|
||||||
@@ -189,8 +204,6 @@ describe("AppTile", () => {
|
|||||||
|
|
||||||
expect(renderResult.queryByText("Example 1")).not.toBeInTheDocument();
|
expect(renderResult.queryByText("Example 1")).not.toBeInTheDocument();
|
||||||
expect(ActiveWidgetStore.instance.isLive("1", "r1")).toBe(false);
|
expect(ActiveWidgetStore.instance.isLive("1", "r1")).toBe(false);
|
||||||
|
|
||||||
mockSettings.mockRestore();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("distinguishes widgets with the same ID in different rooms", async () => {
|
it("distinguishes widgets with the same ID in different rooms", async () => {
|
||||||
@@ -327,50 +340,57 @@ describe("AppTile", () => {
|
|||||||
expect(ActiveWidgetStore.instance.isLive("1", "r1")).toBe(true);
|
expect(ActiveWidgetStore.instance.isLive("1", "r1")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
// @ts-ignore
|
|
||||||
await WidgetLayoutStore.instance.onNotReady();
|
|
||||||
// @ts-ignore
|
|
||||||
await RightPanelStore.instance.onNotReady();
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("for a pinned widget", () => {
|
describe("for a pinned widget", () => {
|
||||||
let renderResult: RenderResult;
|
|
||||||
let moveToContainerSpy: jest.SpyInstance<void, [room: Room, widget: IWidget, toContainer: Container]>;
|
let moveToContainerSpy: jest.SpyInstance<void, [room: Room, widget: IWidget, toContainer: Container]>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
renderResult = render(
|
moveToContainerSpy = jest.spyOn(WidgetLayoutStore.instance, "moveToContainer");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render", async () => {
|
||||||
|
const renderResult = render(
|
||||||
<MatrixClientContext.Provider value={cli}>
|
<MatrixClientContext.Provider value={cli}>
|
||||||
<AppTile key={app1.id} app={app1} room={r1} />
|
<AppTile key={app1.id} app={app1} room={r1} />
|
||||||
</MatrixClientContext.Provider>,
|
</MatrixClientContext.Provider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
moveToContainerSpy = jest.spyOn(WidgetLayoutStore.instance, "moveToContainer");
|
|
||||||
await waitForElementToBeRemoved(() => renderResult.queryByRole("progressbar"));
|
await waitForElementToBeRemoved(() => renderResult.queryByRole("progressbar"));
|
||||||
});
|
|
||||||
|
|
||||||
it("should render", () => {
|
|
||||||
const { asFragment } = renderResult;
|
const { asFragment } = renderResult;
|
||||||
|
|
||||||
expect(asFragment()).toMatchSnapshot(); // Take a snapshot of the pinned widget
|
expect(asFragment()).toMatchSnapshot(); // Take a snapshot of the pinned widget
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not display the »Popout widget« button", () => {
|
it("should not display the »Popout widget« button", async () => {
|
||||||
|
const renderResult = render(
|
||||||
|
<MatrixClientContext.Provider value={cli}>
|
||||||
|
<AppTile key={app1.id} app={app1} room={r1} />
|
||||||
|
</MatrixClientContext.Provider>,
|
||||||
|
);
|
||||||
|
await waitForElementToBeRemoved(() => renderResult.queryByRole("progressbar"));
|
||||||
expect(renderResult.queryByLabelText("Popout widget")).not.toBeInTheDocument();
|
expect(renderResult.queryByLabelText("Popout widget")).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("clicking 'minimise' should send the widget to the right", async () => {
|
it("clicking 'minimise' should send the widget to the right", async () => {
|
||||||
|
const renderResult = render(
|
||||||
|
<MatrixClientContext.Provider value={cli}>
|
||||||
|
<AppTile key={app1.id} app={app1} room={r1} />
|
||||||
|
</MatrixClientContext.Provider>,
|
||||||
|
);
|
||||||
|
await waitForElementToBeRemoved(() => renderResult.queryByRole("progressbar"));
|
||||||
await userEvent.click(renderResult.getByLabelText("Minimise"));
|
await userEvent.click(renderResult.getByLabelText("Minimise"));
|
||||||
expect(moveToContainerSpy).toHaveBeenCalledWith(r1, app1, Container.Right);
|
expect(moveToContainerSpy).toHaveBeenCalledWith(r1, app1, Container.Right);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("clicking 'maximise' should send the widget to the center", async () => {
|
it("clicking 'maximise' should send the widget to the center", async () => {
|
||||||
|
const renderResult = render(
|
||||||
|
<MatrixClientContext.Provider value={cli}>
|
||||||
|
<AppTile key={app1.id} app={app1} room={r1} />
|
||||||
|
</MatrixClientContext.Provider>,
|
||||||
|
);
|
||||||
|
await waitForElementToBeRemoved(() => renderResult.queryByRole("progressbar"));
|
||||||
await userEvent.click(renderResult.getByLabelText("Maximise"));
|
await userEvent.click(renderResult.getByLabelText("Maximise"));
|
||||||
expect(moveToContainerSpy).toHaveBeenCalledWith(r1, app1, Container.Center);
|
expect(moveToContainerSpy).toHaveBeenCalledWith(r1, app1, Container.Center);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render permission request", () => {
|
it("should render permission request", async () => {
|
||||||
jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts, widgetInfo) => {
|
jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts, widgetInfo) => {
|
||||||
if (lifecycleEvent === WidgetLifecycle.PreLoadRequest && (widgetInfo as WidgetInfo).id === app1.id) {
|
if (lifecycleEvent === WidgetLifecycle.PreLoadRequest && (widgetInfo as WidgetInfo).id === app1.id) {
|
||||||
(opts as ApprovalOpts).approved = false;
|
(opts as ApprovalOpts).approved = false;
|
||||||
@@ -378,21 +398,17 @@ describe("AppTile", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// userId and creatorUserId are different
|
// userId and creatorUserId are different
|
||||||
const renderResult = render(
|
const { container, asFragment, queryByRole } = render(
|
||||||
<MatrixClientContext.Provider value={cli}>
|
<MatrixClientContext.Provider value={cli}>
|
||||||
<AppTile key={app1.id} app={app1} room={r1} userId="@user1" creatorUserId="@userAnother" />
|
<AppTile key={app1.id} app={app1} room={r1} userId="@user1" creatorUserId="@userAnother" />
|
||||||
</MatrixClientContext.Provider>,
|
</MatrixClientContext.Provider>,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { container, asFragment } = renderResult;
|
|
||||||
|
|
||||||
expect(container.querySelector(".mx_Spinner")).toBeFalsy();
|
expect(container.querySelector(".mx_Spinner")).toBeFalsy();
|
||||||
|
expect(queryByRole("button", { name: "Continue" })).toBeInTheDocument();
|
||||||
expect(asFragment()).toMatchSnapshot();
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
|
||||||
expect(renderResult.queryByRole("button", { name: "Continue" })).toBeInTheDocument();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not display 'Continue' button on permission load", () => {
|
it("should not display 'Continue' button on permission load", async () => {
|
||||||
jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts, widgetInfo) => {
|
jest.spyOn(ModuleRunner.instance, "invoke").mockImplementation((lifecycleEvent, opts, widgetInfo) => {
|
||||||
if (lifecycleEvent === WidgetLifecycle.PreLoadRequest && (widgetInfo as WidgetInfo).id === app1.id) {
|
if (lifecycleEvent === WidgetLifecycle.PreLoadRequest && (widgetInfo as WidgetInfo).id === app1.id) {
|
||||||
(opts as ApprovalOpts).approved = true;
|
(opts as ApprovalOpts).approved = true;
|
||||||
@@ -405,6 +421,7 @@ describe("AppTile", () => {
|
|||||||
<AppTile key={app1.id} app={app1} room={r1} userId="@user1" creatorUserId="@userAnother" />
|
<AppTile key={app1.id} app={app1} room={r1} userId="@user1" creatorUserId="@userAnother" />
|
||||||
</MatrixClientContext.Provider>,
|
</MatrixClientContext.Provider>,
|
||||||
);
|
);
|
||||||
|
await waitForElementToBeRemoved(() => renderResult.queryByRole("progressbar"));
|
||||||
|
|
||||||
expect(renderResult.queryByRole("button", { name: "Continue" })).not.toBeInTheDocument();
|
expect(renderResult.queryByRole("button", { name: "Continue" })).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
@@ -418,7 +435,17 @@ describe("AppTile", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.spyOn(WidgetLayoutStore.instance, "isInContainer").mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
it("clicking 'un-maximise' should send the widget to the top", async () => {
|
it("clicking 'un-maximise' should send the widget to the top", async () => {
|
||||||
|
const renderResult = render(
|
||||||
|
<MatrixClientContext.Provider value={cli}>
|
||||||
|
<AppTile key={app1.id} app={app1} room={r1} />
|
||||||
|
</MatrixClientContext.Provider>,
|
||||||
|
);
|
||||||
|
await waitForElementToBeRemoved(() => renderResult.queryByRole("progressbar"));
|
||||||
await userEvent.click(renderResult.getByLabelText("Un-maximise"));
|
await userEvent.click(renderResult.getByLabelText("Un-maximise"));
|
||||||
expect(moveToContainerSpy).toHaveBeenCalledWith(r1, app1, Container.Top);
|
expect(moveToContainerSpy).toHaveBeenCalledWith(r1, app1, Container.Top);
|
||||||
});
|
});
|
||||||
@@ -440,36 +467,28 @@ describe("AppTile", () => {
|
|||||||
|
|
||||||
const mockWidget = new ElementWidget(app1);
|
const mockWidget = new ElementWidget(app1);
|
||||||
WidgetMessagingStore.instance.storeMessaging(mockWidget, r1.roomId, messaging);
|
WidgetMessagingStore.instance.storeMessaging(mockWidget, r1.roomId, messaging);
|
||||||
|
});
|
||||||
|
|
||||||
renderResult = render(
|
it("should display the »Popout widget« button", async () => {
|
||||||
|
const renderResult = render(
|
||||||
<MatrixClientContext.Provider value={cli}>
|
<MatrixClientContext.Provider value={cli}>
|
||||||
<AppTile key={app1.id} app={app1} room={r1} />
|
<AppTile key={app1.id} app={app1} room={r1} />
|
||||||
</MatrixClientContext.Provider>,
|
</MatrixClientContext.Provider>,
|
||||||
);
|
);
|
||||||
});
|
await waitForElementToBeRemoved(() => renderResult.queryByRole("progressbar"));
|
||||||
|
|
||||||
it("should display the »Popout widget« button", () => {
|
|
||||||
expect(renderResult.getByLabelText("Popout widget")).toBeInTheDocument();
|
expect(renderResult.getByLabelText("Popout widget")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("for a persistent app", () => {
|
describe("for a persistent app", () => {
|
||||||
let renderResult: RenderResult;
|
it("should render", async () => {
|
||||||
|
const { asFragment, queryByRole } = render(
|
||||||
beforeEach(async () => {
|
|
||||||
renderResult = render(
|
|
||||||
<MatrixClientContext.Provider value={cli}>
|
<MatrixClientContext.Provider value={cli}>
|
||||||
<AppTile key={app1.id} app={app1} fullWidth={true} room={r1} miniMode={true} showMenubar={false} />
|
<AppTile key={app1.id} app={app1} room={r1} fullWidth={true} miniMode={true} showMenubar={false} />
|
||||||
</MatrixClientContext.Provider>,
|
</MatrixClientContext.Provider>,
|
||||||
);
|
);
|
||||||
|
await waitForElementToBeRemoved(() => queryByRole("progressbar"));
|
||||||
await waitForElementToBeRemoved(() => renderResult.queryByRole("progressbar"));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should render", async () => {
|
|
||||||
const { asFragment } = renderResult;
|
|
||||||
|
|
||||||
expect(asFragment()).toMatchSnapshot();
|
expect(asFragment()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ exports[`AppTile for a pinned widget should render 1`] = `
|
|||||||
class="mx_AppTileMenuBar_widgets"
|
class="mx_AppTileMenuBar_widgets"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-label="Un-maximise"
|
aria-label="Maximise"
|
||||||
class="mx_AccessibleButton mx_AppTileMenuBar_widgets_button"
|
class="mx_AccessibleButton mx_AppTileMenuBar_widgets_button"
|
||||||
role="button"
|
role="button"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@@ -145,7 +145,7 @@ exports[`AppTile for a pinned widget should render 1`] = `
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M12 11.034a1 1 0 0 0 .29.702l.005.005c.18.18.43.29.705.29h8a1 1 0 0 0 0-2h-5.586L22 3.445a1 1 0 0 0-1.414-1.414L14 8.617V3.031a1 1 0 1 0-2 0zm0 1.963a1 1 0 0 0-.29-.702l-.005-.004A1 1 0 0 0 11 12H3a1 1 0 1 0 0 2h5.586L2 20.586A1 1 0 1 0 3.414 22L10 15.414V21a1 1 0 0 0 2 0z"
|
d="M21 3.997a1 1 0 0 0-.29-.702l-.005-.004A1 1 0 0 0 20 3h-8a1 1 0 1 0 0 2h5.586L5 17.586V12a1 1 0 1 0-2 0v8.003a1 1 0 0 0 .29.702l.005.004c.18.18.43.291.705.291h8a1 1 0 1 0 0-2H6.414L19 6.414V12a1 1 0 1 0 2 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@@ -244,7 +244,7 @@ exports[`AppTile for a pinned widget should render permission request 1`] = `
|
|||||||
class="mx_AppTileMenuBar_widgets"
|
class="mx_AppTileMenuBar_widgets"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-label="Un-maximise"
|
aria-label="Maximise"
|
||||||
class="mx_AccessibleButton mx_AppTileMenuBar_widgets_button"
|
class="mx_AccessibleButton mx_AppTileMenuBar_widgets_button"
|
||||||
role="button"
|
role="button"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@@ -258,7 +258,7 @@ exports[`AppTile for a pinned widget should render permission request 1`] = `
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M12 11.034a1 1 0 0 0 .29.702l.005.005c.18.18.43.29.705.29h8a1 1 0 0 0 0-2h-5.586L22 3.445a1 1 0 0 0-1.414-1.414L14 8.617V3.031a1 1 0 1 0-2 0zm0 1.963a1 1 0 0 0-.29-.702l-.005-.004A1 1 0 0 0 11 12H3a1 1 0 1 0 0 2h5.586L2 20.586A1 1 0 1 0 3.414 22L10 15.414V21a1 1 0 0 0 2 0z"
|
d="M21 3.997a1 1 0 0 0-.29-.702l-.005-.004A1 1 0 0 0 20 3h-8a1 1 0 1 0 0 2h5.586L5 17.586V12a1 1 0 1 0-2 0v8.003a1 1 0 0 0 .29.702l.005.004c.18.18.43.291.705.291h8a1 1 0 1 0 0-2H6.414L19 6.414V12a1 1 0 1 0 2 0z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@@ -340,8 +340,8 @@ exports[`AppTile for a pinned widget should render permission request 1`] = `
|
|||||||
<span>
|
<span>
|
||||||
Using this widget may share data
|
Using this widget may share data
|
||||||
<div
|
<div
|
||||||
aria-describedby="_r_2n_"
|
aria-describedby="_r_2f_"
|
||||||
aria-labelledby="_r_2m_"
|
aria-labelledby="_r_2e_"
|
||||||
class="mx_TextWithTooltip_target mx_TextWithTooltip_target--helpIcon"
|
class="mx_TextWithTooltip_target mx_TextWithTooltip_target--helpIcon"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
|
|||||||
Reference in New Issue
Block a user