* Scaffolding for undo-redo * undo redo working Poc commit * memory performance improvements by diffing * dont run update on undo/redo" * merging widget postion update and canvas bottom row update into one dsl update. * fix tabs widget * Visible updates per undo redo action (#6838) Co-authored-by: Rahul R <rahulramesha@Rahuls-MacBook-Pro.local> * resize atomic operation * fix switch control state issue * disallow undo/redo for snipping and comment mode * disallow undo/redo for snipping and comment mode * fix color picker issue in undo/redo * add test for replayDSL * option control fix, adding logs * minor position change undo redo updates * add test cases for replayHelpers * property Upade visual change * remove unused code * global hot key jest test for undo redo * Fixing batch updates on property change.. * add tests for toggle control in property pane * unwanted utils. * add tests for text control * add tests for deletion * add tests for dropping a new widget * adding jest test for replayUtils * add move widget tests * add tests for color picker control * add analytics for undo/redo * add analytics for undo/redo * tab addition atomic * cypress tests for propertyPane, toasts and radiowidget optionControl * replayDSL end of redo stack fix * property update changes * menu option control debounce input * color picker empty undo fix * fix cypress tests * widget add/remove atomic * revert alternative approach to handle atomic operations * update replayDSL test * add some comments * addressing review comments * flash color for property pane controls * Fixing adding of tabs widget as well. * code review comments. * merging widget postion update and canvas bottom row update into one dsl update. * fix ordering of tabs property control * meta property update canvas min height. * fixing failed specs. * Fixing entity explorer update on deleting tab from entity explorer. * address review comments and minor property update changes * fixing failing tests * merge conflicts * changes to cater widget api. * fix suggested widget table issue * draggable list for undo redo * fix widget name focus * excluding canvas updates. * fixing codeEditor update on propertySection collapse * fixed failing test case * ctrl y to redo for windows users Co-authored-by: Abhinav Jha <abhinav@appsmith.com> Co-authored-by: Rahul R <rahulramesha@Rahuls-MacBook-Pro.local> Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain> Co-authored-by: Ashok Kumar M <35134347+marks0351@users.noreply.github.com> Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local>
643 lines
18 KiB
TypeScript
643 lines
18 KiB
TypeScript
import React from "react";
|
|
import { Slide } from "react-toastify";
|
|
|
|
import {
|
|
buildChildren,
|
|
widgetCanvasFactory,
|
|
} from "test/factories/WidgetFactoryUtils";
|
|
import { act, render, fireEvent, waitFor } from "test/testUtils";
|
|
import GlobalHotKeys from "./GlobalHotKeys";
|
|
import MainContainer from "./MainContainer";
|
|
import { MemoryRouter } from "react-router-dom";
|
|
import * as utilities from "selectors/editorSelectors";
|
|
import store from "store";
|
|
import { sagasToRunForTests } from "test/sagas";
|
|
import { all } from "@redux-saga/core/effects";
|
|
import {
|
|
dispatchTestKeyboardEventWithCode,
|
|
MockApplication,
|
|
mockGetCanvasWidgetDsl,
|
|
MockPageDSL,
|
|
useMockDsl,
|
|
} from "test/testCommon";
|
|
import { MockCanvas } from "test/testMockedWidgets";
|
|
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
|
|
import { generateReactKey } from "utils/generators";
|
|
import { redoAction, undoAction } from "actions/pageActions";
|
|
import { StyledToastContainer } from "components/ads/Toast";
|
|
import { createMessage, SAVE_HOTKEY_TOASTER_MESSAGE } from "constants/messages";
|
|
|
|
describe("Canvas Hot Keys", () => {
|
|
const mockGetIsFetchingPage = jest.spyOn(utilities, "getIsFetchingPage");
|
|
const spyGetCanvasWidgetDsl = jest.spyOn(utilities, "getCanvasWidgetDsl");
|
|
|
|
function UpdatedMainContainer({ dsl }: any) {
|
|
useMockDsl(dsl);
|
|
return <MainContainer />;
|
|
}
|
|
// These need to be at the top to avoid imports not being mocked. ideally should be in setup.ts but will override for all other tests
|
|
beforeAll(() => {
|
|
const mockGenerator = function*() {
|
|
yield all([]);
|
|
};
|
|
|
|
// top avoid the first middleware run which wud initiate all sagas.
|
|
jest.mock("sagas", () => ({
|
|
rootSaga: mockGenerator,
|
|
}));
|
|
|
|
// only the deafault exports are mocked to avoid overriding utilities exported out of them. defaults are marked to avoid worker initiation and page api calls in tests.
|
|
jest.mock("sagas/EvaluationsSaga", () => ({
|
|
...jest.requireActual("sagas/EvaluationsSaga"),
|
|
default: mockGenerator,
|
|
}));
|
|
jest.mock("sagas/PageSagas", () => ({
|
|
...jest.requireActual("sagas/PageSagas"),
|
|
default: mockGenerator,
|
|
}));
|
|
});
|
|
|
|
describe("Select all hotkey", () => {
|
|
it("Cmd + A - select all widgets on canvas", async () => {
|
|
const children: any = buildChildren([
|
|
{ type: "TABS_WIDGET", parentId: MAIN_CONTAINER_WIDGET_ID },
|
|
{ type: "SWITCH_WIDGET", parentId: MAIN_CONTAINER_WIDGET_ID },
|
|
]);
|
|
const dsl: any = widgetCanvasFactory.build({
|
|
children,
|
|
});
|
|
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
|
|
mockGetIsFetchingPage.mockImplementation(() => false);
|
|
|
|
const component = render(
|
|
<MemoryRouter
|
|
initialEntries={["/applications/app_id/pages/page_id/edit"]}
|
|
>
|
|
<MockApplication>
|
|
<GlobalHotKeys>
|
|
<UpdatedMainContainer dsl={dsl} />
|
|
</GlobalHotKeys>
|
|
</MockApplication>
|
|
</MemoryRouter>,
|
|
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
|
|
);
|
|
let propPane = component.queryByTestId("t--propertypane");
|
|
expect(propPane).toBeNull();
|
|
const canvasWidgets = component.queryAllByTestId("test-widget");
|
|
expect(canvasWidgets.length).toBe(2);
|
|
act(() => {
|
|
if (canvasWidgets[0].firstChild) {
|
|
fireEvent.mouseOver(canvasWidgets[0].firstChild);
|
|
fireEvent.click(canvasWidgets[0].firstChild);
|
|
}
|
|
});
|
|
const tabsWidgetName: any = component.container.querySelector(
|
|
`span.t--widget-name`,
|
|
);
|
|
fireEvent.click(tabsWidgetName);
|
|
propPane = component.queryByTestId("t--propertypane");
|
|
expect(propPane).not.toBeNull();
|
|
|
|
const artBoard: any = component.queryByTestId("t--canvas-artboard");
|
|
// deselect all other widgets
|
|
fireEvent.click(artBoard);
|
|
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"A",
|
|
65,
|
|
false,
|
|
true,
|
|
);
|
|
let selectedWidgets = component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(2);
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"escape",
|
|
27,
|
|
false,
|
|
false,
|
|
);
|
|
selectedWidgets = component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(0);
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"A",
|
|
65,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
|
|
selectedWidgets = component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(2);
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"C",
|
|
67,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"V",
|
|
86,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
selectedWidgets = component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(2);
|
|
});
|
|
it("Cmd + A - select all widgets inside last selected container", async () => {
|
|
const containerId = generateReactKey();
|
|
const canvasId = generateReactKey();
|
|
const children: any = buildChildren([
|
|
{ type: "CHECKBOX_WIDGET", parentId: canvasId },
|
|
{ type: "SWITCH_WIDGET", parentId: canvasId },
|
|
{ type: "BUTTON_WIDGET", parentId: canvasId },
|
|
]);
|
|
const canvasWidget = buildChildren([
|
|
{
|
|
type: "CANVAS_WIDGET",
|
|
parentId: containerId,
|
|
children,
|
|
widgetId: canvasId,
|
|
},
|
|
]);
|
|
const containerChildren: any = buildChildren([
|
|
{
|
|
type: "CONTAINER_WIDGET",
|
|
children: canvasWidget,
|
|
widgetId: containerId,
|
|
parentId: "0",
|
|
},
|
|
{ type: "CHART_WIDGET", parentId: "0" },
|
|
]);
|
|
const dsl: any = widgetCanvasFactory.build({
|
|
children: containerChildren,
|
|
});
|
|
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
|
|
mockGetIsFetchingPage.mockImplementation(() => false);
|
|
|
|
const component = render(
|
|
<MemoryRouter
|
|
initialEntries={["/applications/app_id/pages/page_id/edit"]}
|
|
>
|
|
<MockApplication>
|
|
<GlobalHotKeys>
|
|
<UpdatedMainContainer dsl={dsl} />
|
|
</GlobalHotKeys>
|
|
</MockApplication>
|
|
</MemoryRouter>,
|
|
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
|
|
);
|
|
const propPane = component.queryByTestId("t--propertypane");
|
|
expect(propPane).toBeNull();
|
|
const canvasWidgets = component.queryAllByTestId("test-widget");
|
|
expect(canvasWidgets.length).toBe(5);
|
|
if (canvasWidgets[0].firstChild) {
|
|
fireEvent.mouseOver(canvasWidgets[0].firstChild);
|
|
fireEvent.click(canvasWidgets[0].firstChild);
|
|
}
|
|
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"A",
|
|
65,
|
|
false,
|
|
true,
|
|
);
|
|
const selectedWidgets = component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(children.length);
|
|
});
|
|
it("Cmd + A - select all widgets inside a form", async () => {
|
|
const children: any = buildChildren([
|
|
{ type: "FORM_WIDGET", parentId: MAIN_CONTAINER_WIDGET_ID },
|
|
]);
|
|
const dsl: any = widgetCanvasFactory.build({
|
|
children,
|
|
});
|
|
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
|
|
mockGetIsFetchingPage.mockImplementation(() => false);
|
|
|
|
const component = render(
|
|
<MemoryRouter
|
|
initialEntries={["/applications/app_id/pages/page_id/edit"]}
|
|
>
|
|
<MockApplication>
|
|
<GlobalHotKeys>
|
|
<UpdatedMainContainer dsl={dsl} />
|
|
</GlobalHotKeys>
|
|
</MockApplication>
|
|
</MemoryRouter>,
|
|
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
|
|
);
|
|
const propPane = component.queryByTestId("t--propertypane");
|
|
expect(propPane).toBeNull();
|
|
const canvasWidgets = component.queryAllByTestId("test-widget");
|
|
expect(canvasWidgets.length).toBe(4);
|
|
if (canvasWidgets[0].firstChild) {
|
|
fireEvent.mouseOver(canvasWidgets[0].firstChild);
|
|
fireEvent.click(canvasWidgets[0].firstChild);
|
|
}
|
|
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"A",
|
|
65,
|
|
false,
|
|
true,
|
|
);
|
|
const selectedWidgets = component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(3);
|
|
});
|
|
it("Cmd + A - select all widgets inside a list", async () => {
|
|
const listId = generateReactKey();
|
|
const containerId = generateReactKey();
|
|
const canvasId = generateReactKey();
|
|
const listCanvasId = generateReactKey();
|
|
const children: any = buildChildren([
|
|
{ type: "CHECKBOX_WIDGET", parentId: canvasId },
|
|
{ type: "SWITCH_WIDGET", parentId: canvasId },
|
|
{ type: "BUTTON_WIDGET", parentId: canvasId },
|
|
]);
|
|
const canvasWidget = buildChildren([
|
|
{
|
|
type: "CANVAS_WIDGET",
|
|
parentId: containerId,
|
|
children,
|
|
widgetId: canvasId,
|
|
bottomRow: 20,
|
|
},
|
|
]);
|
|
const containerChildren: any = buildChildren([
|
|
{
|
|
type: "CONTAINER_WIDGET",
|
|
children: canvasWidget,
|
|
widgetId: containerId,
|
|
parentId: listCanvasId,
|
|
dropDisabled: true,
|
|
bottomRow: 4,
|
|
},
|
|
]);
|
|
const listCanvasChildren: any = buildChildren([
|
|
{
|
|
type: "CANVAS_WIDGET",
|
|
children: containerChildren,
|
|
widgetId: listCanvasId,
|
|
dropDisabled: true,
|
|
parentId: listId,
|
|
bottomRow: 20,
|
|
},
|
|
]);
|
|
const listChildren: any = buildChildren([
|
|
{
|
|
type: "LIST_WIDGET",
|
|
children: listCanvasChildren,
|
|
widgetId: listId,
|
|
parentId: "0",
|
|
},
|
|
]);
|
|
const dsl: any = widgetCanvasFactory.build({
|
|
children: listChildren,
|
|
});
|
|
spyGetCanvasWidgetDsl.mockImplementation(mockGetCanvasWidgetDsl);
|
|
mockGetIsFetchingPage.mockImplementation(() => false);
|
|
|
|
const component = render(
|
|
<MemoryRouter
|
|
initialEntries={["/applications/app_id/pages/page_id/edit"]}
|
|
>
|
|
<MockApplication>
|
|
<GlobalHotKeys>
|
|
<UpdatedMainContainer dsl={dsl} />
|
|
</GlobalHotKeys>
|
|
</MockApplication>
|
|
</MemoryRouter>,
|
|
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
|
|
);
|
|
const propPane = component.queryByTestId("t--propertypane");
|
|
expect(propPane).toBeNull();
|
|
const canvasWidgets = component.queryAllByTestId("test-widget");
|
|
|
|
if (canvasWidgets[0].firstChild) {
|
|
fireEvent.mouseOver(canvasWidgets[0].firstChild);
|
|
fireEvent.click(canvasWidgets[0].firstChild);
|
|
}
|
|
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"A",
|
|
65,
|
|
false,
|
|
true,
|
|
);
|
|
const selectedWidgets = component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(3);
|
|
});
|
|
});
|
|
|
|
afterAll(() => jest.resetModules());
|
|
});
|
|
|
|
describe("Cut/Copy/Paste hotkey", () => {
|
|
it("Should copy and paste all selected widgets with hotkey cmd + c and cmd + v ", async () => {
|
|
const children: any = buildChildren([
|
|
{
|
|
type: "TABS_WIDGET",
|
|
topRow: 5,
|
|
bottomRow: 30,
|
|
leftColumn: 5,
|
|
rightColumn: 30,
|
|
parentId: MAIN_CONTAINER_WIDGET_ID,
|
|
},
|
|
{
|
|
type: "SWITCH_WIDGET",
|
|
topRow: 5,
|
|
bottomRow: 10,
|
|
leftColumn: 40,
|
|
rightColumn: 48,
|
|
parentId: MAIN_CONTAINER_WIDGET_ID,
|
|
},
|
|
]);
|
|
const dsl: any = widgetCanvasFactory.build({
|
|
children,
|
|
});
|
|
const component = render(
|
|
<MockPageDSL dsl={dsl}>
|
|
<GlobalHotKeys>
|
|
<MockCanvas />
|
|
</GlobalHotKeys>
|
|
</MockPageDSL>,
|
|
);
|
|
const artBoard: any = await component.queryByTestId("t--canvas-artboard");
|
|
// deselect all other widgets
|
|
fireEvent.click(artBoard);
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"A",
|
|
65,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
|
|
let selectedWidgets = await component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(2);
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"C",
|
|
67,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"V",
|
|
86,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
await component.findByTestId("t--selection-box");
|
|
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"A",
|
|
65,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
|
|
selectedWidgets = await component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(4);
|
|
});
|
|
it("Should cut and paste all selected widgets with hotkey cmd + x and cmd + v ", async () => {
|
|
const children: any = buildChildren([
|
|
{
|
|
type: "TABS_WIDGET",
|
|
topRow: 5,
|
|
bottomRow: 30,
|
|
leftColumn: 5,
|
|
rightColumn: 30,
|
|
parentId: MAIN_CONTAINER_WIDGET_ID,
|
|
},
|
|
{
|
|
type: "SWITCH_WIDGET",
|
|
topRow: 5,
|
|
bottomRow: 10,
|
|
leftColumn: 40,
|
|
rightColumn: 48,
|
|
parentId: MAIN_CONTAINER_WIDGET_ID,
|
|
},
|
|
]);
|
|
const dsl: any = widgetCanvasFactory.build({
|
|
children,
|
|
});
|
|
const component = render(
|
|
<MockPageDSL dsl={dsl}>
|
|
<GlobalHotKeys>
|
|
<MockCanvas />
|
|
</GlobalHotKeys>
|
|
</MockPageDSL>,
|
|
);
|
|
const artBoard: any = await component.queryByTestId("t--canvas-artboard");
|
|
// deselect all other widgets
|
|
fireEvent.click(artBoard);
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"A",
|
|
65,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
|
|
let selectedWidgets = await component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(2);
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"X",
|
|
88,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
await component.findByTestId("canvas-0");
|
|
selectedWidgets = await component.queryAllByTestId("t--selected");
|
|
//adding extra time to let cut cmd works
|
|
jest.useFakeTimers();
|
|
setTimeout(() => {
|
|
expect(selectedWidgets.length).toBe(0);
|
|
}, 500);
|
|
jest.runAllTimers();
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"V",
|
|
86,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
await component.findByTestId("t--selection-box");
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"A",
|
|
65,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
|
|
selectedWidgets = await component.queryAllByTestId("t--selected");
|
|
expect(selectedWidgets.length).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe("Undo/Redo hotkey", () => {
|
|
it("should dispatch undo Action on cmd + z", () => {
|
|
const dispatchSpy = jest.spyOn(store, "dispatch");
|
|
const component = render(
|
|
<MockPageDSL>
|
|
<GlobalHotKeys>
|
|
<MockCanvas />
|
|
</GlobalHotKeys>
|
|
</MockPageDSL>,
|
|
);
|
|
|
|
dispatchSpy.mockClear();
|
|
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"Z",
|
|
90,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
|
|
expect(dispatchSpy).toBeCalledTimes(1);
|
|
expect(dispatchSpy).toBeCalledWith(undoAction());
|
|
});
|
|
it("should dispatch redo Action on cmd + shift + z", () => {
|
|
const dispatchSpy = jest.spyOn(store, "dispatch");
|
|
const component = render(
|
|
<MockPageDSL>
|
|
<GlobalHotKeys>
|
|
<MockCanvas />
|
|
</GlobalHotKeys>
|
|
</MockPageDSL>,
|
|
);
|
|
|
|
dispatchSpy.mockClear();
|
|
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"Z",
|
|
90,
|
|
true,
|
|
true,
|
|
);
|
|
});
|
|
|
|
expect(dispatchSpy).toBeCalledTimes(1);
|
|
expect(dispatchSpy).toBeCalledWith(redoAction());
|
|
});
|
|
it("should dispatch redo Action on ctrl + y", () => {
|
|
const dispatchSpy = jest.spyOn(store, "dispatch");
|
|
const component = render(
|
|
<MockPageDSL>
|
|
<GlobalHotKeys>
|
|
<MockCanvas />
|
|
</GlobalHotKeys>
|
|
</MockPageDSL>,
|
|
);
|
|
|
|
dispatchSpy.mockClear();
|
|
|
|
act(() => {
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"Y",
|
|
89,
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
|
|
expect(dispatchSpy).toBeCalledTimes(1);
|
|
expect(dispatchSpy).toBeCalledWith(redoAction());
|
|
});
|
|
});
|
|
|
|
describe("cmd + s hotkey", () => {
|
|
it("Should render toast message", async () => {
|
|
const component = render(
|
|
<>
|
|
<StyledToastContainer
|
|
autoClose={5000}
|
|
closeButton={false}
|
|
draggable={false}
|
|
hideProgressBar
|
|
pauseOnHover={false}
|
|
transition={Slide}
|
|
/>
|
|
<GlobalHotKeys>
|
|
<div />
|
|
</GlobalHotKeys>
|
|
</>,
|
|
);
|
|
|
|
dispatchTestKeyboardEventWithCode(
|
|
component.container,
|
|
"keydown",
|
|
"s",
|
|
83,
|
|
false,
|
|
true,
|
|
);
|
|
|
|
await waitFor(() => {
|
|
expect(
|
|
component.getByText(createMessage(SAVE_HOTKEY_TOASTER_MESSAGE)),
|
|
).toBeDefined();
|
|
});
|
|
});
|
|
});
|