-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19337 from guerler/consistent_popper
Refactor and add tests for Popovers
- Loading branch information
Showing
7 changed files
with
270 additions
and
348 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { createPopper } from "@popperjs/core"; | ||
import { mount } from "@vue/test-utils"; | ||
|
||
import PopperComponent from "./Popper.vue"; | ||
|
||
jest.mock("@popperjs/core", () => ({ | ||
createPopper: jest.fn(() => ({ | ||
destroy: jest.fn(), | ||
update: jest.fn(), | ||
})), | ||
})); | ||
|
||
function mountTarget(trigger = "click") { | ||
return mount(PopperComponent, { | ||
propsData: { | ||
title: "Test Title", | ||
placement: "bottom", | ||
trigger: trigger, | ||
}, | ||
slots: { | ||
reference: "<button>Reference</button>", | ||
default: "<p>Popper Content</p>", | ||
}, | ||
}); | ||
} | ||
|
||
describe("PopperComponent.vue", () => { | ||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
test("renders component with default props", async () => { | ||
const wrapper = mountTarget(); | ||
expect(wrapper.find(".popper-element").exists()).toBe(true); | ||
expect(wrapper.find(".popper-element").isVisible()).toBe(false); | ||
const reference = wrapper.find("button"); | ||
await reference.trigger("click"); | ||
expect(wrapper.find(".popper-header").exists()).toBe(true); | ||
expect(wrapper.find(".popper-header").text()).toContain("Test Title"); | ||
}); | ||
|
||
test("opens and closes popper on click trigger", async () => { | ||
const wrapper = mountTarget(); | ||
const reference = wrapper.find("button"); | ||
expect(wrapper.find(".popper-element").isVisible()).toBe(false); | ||
await reference.trigger("click"); | ||
expect(wrapper.find(".popper-element").isVisible()).toBe(true); | ||
await wrapper.find(".popper-close").trigger("click"); | ||
expect(wrapper.find(".popper-element").isVisible()).toBe(false); | ||
}); | ||
|
||
test("disables popper when `disabled` prop is true", async () => { | ||
const wrapper = mountTarget(); | ||
await wrapper.setProps({ disabled: true }); | ||
const reference = wrapper.find("button"); | ||
await reference.trigger("click"); | ||
expect(wrapper.find(".popper-element").isVisible()).toBe(false); | ||
}); | ||
|
||
test("renders the arrow when `arrow` prop is true", () => { | ||
const wrapper = mountTarget(); | ||
expect(wrapper.find(".popper-arrow").exists()).toBe(true); | ||
}); | ||
|
||
test("does not render the arrow when `arrow` prop is false", async () => { | ||
const wrapper = mountTarget(); | ||
await wrapper.setProps({ arrow: false }); | ||
expect(wrapper.find(".popper-arrow").exists()).toBe(false); | ||
}); | ||
|
||
test("applies correct mode class", async () => { | ||
const wrapper = mountTarget(); | ||
await wrapper.setProps({ mode: "light" }); | ||
expect(wrapper.find(".popper-element").classes()).toContain("popper-element-light"); | ||
await wrapper.setProps({ mode: "dark" }); | ||
expect(wrapper.find(".popper-element").classes()).toContain("popper-element-dark"); | ||
}); | ||
|
||
test("uses correct placement prop", () => { | ||
mountTarget(); | ||
expect(createPopper).toHaveBeenCalledWith( | ||
expect.anything(), | ||
expect.anything(), | ||
expect.objectContaining({ placement: "bottom" }) | ||
); | ||
}); | ||
|
||
test("updates visibility when props or watchers change", async () => { | ||
const wrapper = mountTarget(); | ||
await wrapper.setProps({ disabled: false }); | ||
const reference = wrapper.find("button"); | ||
await reference.trigger("click"); | ||
expect(wrapper.find(".popper-element").isVisible()).toBe(true); | ||
await wrapper.setProps({ disabled: true }); | ||
expect(wrapper.find(".popper-element").isVisible()).toBe(false); | ||
}); | ||
|
||
test("shows and hides popper on hover trigger", async () => { | ||
const wrapper = mountTarget("hover"); | ||
const reference = wrapper.find("button"); | ||
const popperElement = wrapper.find(".popper-element"); | ||
expect(popperElement.isVisible()).toBe(false); | ||
await reference.trigger("mouseover"); | ||
expect(popperElement.isVisible()).toBe(true); | ||
await reference.trigger("mouseout"); | ||
expect(popperElement.isVisible()).toBe(false); | ||
}); | ||
|
||
test("popper remains visible when clicked inside of popper", async () => { | ||
const wrapper = mountTarget("click"); | ||
const reference = wrapper.find("button"); | ||
const popperElement = wrapper.find(".popper-element"); | ||
expect(popperElement.isVisible()).toBe(false); | ||
await reference.trigger("click"); | ||
expect(popperElement.isVisible()).toBe(true); | ||
await popperElement.trigger("mouseover"); | ||
expect(popperElement.isVisible()).toBe(true); | ||
await popperElement.trigger("mouseout"); | ||
expect(popperElement.isVisible()).toBe(true); | ||
await popperElement.trigger("click"); | ||
expect(popperElement.isVisible()).toBe(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { createPopper } from "@popperjs/core"; | ||
import { mount } from "@vue/test-utils"; | ||
import { nextTick, ref } from "vue"; | ||
|
||
import { usePopper } from "./usePopper"; | ||
|
||
jest.mock("@popperjs/core", () => ({ | ||
createPopper: jest.fn(() => ({ | ||
destroy: jest.fn(), | ||
update: jest.fn(), | ||
})), | ||
})); | ||
|
||
describe("usePopper", () => { | ||
let referenceElement; | ||
let popperElement; | ||
|
||
beforeEach(() => { | ||
referenceElement = document.createElement("div"); | ||
document.body.appendChild(referenceElement); | ||
|
||
popperElement = document.createElement("div"); | ||
document.body.appendChild(popperElement); | ||
}); | ||
|
||
afterEach(() => { | ||
document.body.innerHTML = ""; | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
const createTestComponent = (trigger = "none") => { | ||
return mount({ | ||
template: "<div></div>", | ||
setup() { | ||
const reference = ref(referenceElement); | ||
const popper = ref(popperElement); | ||
const options = { placement: "bottom", trigger }; | ||
const { visible, instance } = usePopper(reference, popper, options); | ||
return { visible, instance }; | ||
}, | ||
}); | ||
}; | ||
|
||
test("should initialize Popper instance on mount", () => { | ||
createTestComponent(); | ||
expect(createPopper).toHaveBeenCalledWith(referenceElement, popperElement, { | ||
placement: "bottom", | ||
strategy: "absolute", | ||
}); | ||
}); | ||
|
||
test("should destroy Popper instance on unmount", () => { | ||
const wrapper = createTestComponent(); | ||
const popperInstance = createPopper.mock.results[0].value; | ||
wrapper.destroy(); | ||
expect(popperInstance.destroy).toHaveBeenCalled(); | ||
}); | ||
|
||
test("should not change visibility for trigger 'none'", async () => { | ||
const wrapper = createTestComponent("none"); | ||
const { visible } = wrapper.vm; | ||
|
||
expect(visible).toBe(false); | ||
|
||
referenceElement.dispatchEvent(new Event("click")); | ||
await nextTick(); | ||
expect(visible).toBe(false); | ||
}); | ||
}); |
Oops, something went wrong.