/*
* Copyright 2021 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { waitFor } from "@testing-library/dom";
import { afterAll, assert, beforeAll, beforeEach, describe, it } from "@blueprintjs/test-commons/vitest";
import { dispatchMouseEvent } from "@blueprintjs/test-commons/vitest-utils";
import { Classes, Utils } from "../../common";
import { Menu } from "../menu/menu";
import { MenuItem } from "../menu/menuItem";
import { hideContextMenu, showContextMenu } from "./contextMenuSingleton";
// use a unique ID to avoid collisons with other tests
const MENU_CLASSNAME = Utils.uniqueId("test-menu");
const MENU = (
);
const DEFAULT_CONTEXT_MENU_POPOVER_PROPS = {
content: MENU,
targetOffset: {
left: 10,
top: 10,
},
transitionDuration: 0,
};
function assertMenuState(isOpen = true) {
const ctxMenuElement = document.querySelectorAll(`.${MENU_CLASSNAME}`);
if (isOpen) {
assert.isTrue(ctxMenuElement.length === 1, "Expected menu to be rendered on the page");
assert.isNotNull(ctxMenuElement[0].closest(`.${Classes.OVERLAY_OPEN}`), "Expected overlay to be open");
} else {
if (ctxMenuElement.length > 0) {
assert.isNull(ctxMenuElement[0].closest(`.${Classes.OVERLAY_OPEN}`), "Expected overlay to be closed");
}
}
}
function dismissContextMenu() {
const backdrop = document.querySelector(`.${Classes.CONTEXT_MENU_BACKDROP}`);
if (backdrop != null) {
dispatchMouseEvent(backdrop, "mousedown");
}
}
describe("showContextMenu() + hideContextMenu()", () => {
let containerElement: HTMLElement;
beforeAll(() => {
// create an element on the page with non-zero dimensions so that we can trigger a context menu above it
containerElement = document.createElement("div");
containerElement.setAttribute("style", "width: 100px; height: 100px;");
document.body.appendChild(containerElement);
});
beforeEach(async () => {
// The prior test's dismissal may still be flushing through React when the next test starts;
// poll briefly so we don't fail on leftover overlay state.
await waitFor(() => assertMenuState(false));
});
afterAll(() => {
containerElement.remove();
});
it("shows a menu with the imperative API", () =>
new Promise(done => {
showContextMenu({
...DEFAULT_CONTEXT_MENU_POPOVER_PROPS,
onOpened: () =>
// defer assertions until the next animation frame; otherwise, this might throw an error
// inside the , which may throw off test debugging
requestAnimationFrame(() => {
assertMenuState(true);
// important: close menu for the next test
dismissContextMenu();
done();
}),
});
}));
describe("hides a menu", () => {
it("by clicking on the backdrop (when onClose prop is defined)", () =>
new Promise(done => {
const handleClose = () =>
requestAnimationFrame(() => {
assertMenuState(false);
done();
});
showContextMenu({
...DEFAULT_CONTEXT_MENU_POPOVER_PROPS,
onClose: handleClose,
onOpened: () =>
requestAnimationFrame(() => {
dismissContextMenu();
}),
});
}));
it("via hideContextMenu()", () =>
new Promise(done => {
showContextMenu({
...DEFAULT_CONTEXT_MENU_POPOVER_PROPS,
onOpened: () =>
// defer assertions until the next animation frame
requestAnimationFrame(() => {
hideContextMenu();
assertMenuState(false);
done();
}),
});
}));
});
});