com.github.mvysny.kaributesting.v10.ContextMenu.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of karibu-testing-v10 Show documentation
Show all versions of karibu-testing-v10 Show documentation
Karibu Testing, support for browserless Vaadin testing in Kotlin
@file:Suppress("FunctionName")
package com.github.mvysny.kaributesting.v10
import com.vaadin.flow.component.ClickEvent
import com.vaadin.flow.component.Component
import com.vaadin.flow.component.contextmenu.*
import com.vaadin.flow.component.grid.Grid
import com.vaadin.flow.component.grid.contextmenu.GridContextMenu
import com.vaadin.flow.component.grid.contextmenu.GridMenuItem
import elemental.json.Json
import elemental.json.JsonObject
import elemental.json.impl.JreJsonObject
import java.lang.reflect.Method
import kotlin.test.expect
import kotlin.test.fail
/**
* Tries to find a menu item matching given [searchSpec] and click it.
* @throws AssertionError if no such menu item exists, or the menu item is not enabled or visible, or it's nested in
* a menu item which is invisible or disabled, or it's attached to a component that's invisible.
*/
public fun HasMenuItems._clickItemMatching(searchSpec: SearchSpec>) {
// fires ContextMenuOpenedListener to simulate menu opening
(this as? ContextMenu)?.setOpened(true)
val parentMap: Map, Component> = (this as Component).getParentMap()
val predicate = searchSpec.toPredicate()
val item: MenuItemBase<*, *, *> = parentMap.keys.firstOrNull(predicate)
?: fail("No menu item with ${searchSpec.toString().removePrefix("MenuItemBase and ")} in this menu:\n${(this as Component).toPrettyTree()}")
(item as MenuItem)._click(parentMap)
// fires ContextMenuOpenedListener to simulate menu closing
(this as? ContextMenu)?.setOpened(false)
}
/**
* Tries to find a menu item with given [caption] and click it.
* @throws AssertionError if no such menu item exists, or the menu item is not enabled or visible, or it's nested in
* a menu item which is invisible or disabled, or it's attached to a component that's invisible.
*/
public fun HasMenuItems._clickItemWithCaption(caption: String) {
_clickItemMatching(SearchSpec(MenuItemBase::class.java, text = caption))
}
/**
* Tries to find a menu item with given [id] and click it.
* @throws AssertionError if no such menu item exists, or the menu item is not enabled or visible, or it's nested in
* a menu item which is invisible or disabled, or it's attached to a component that's invisible.
*/
public fun HasMenuItems._clickItemWithID(id: String) {
_clickItemMatching(SearchSpec(MenuItemBase::class.java, id = id))
}
/**
* Clicks a menu [item]. The item must belong to this menu.
*
* Intended to be used with MenuBars. See [Issue 33](https://github.com/mvysny/karibu-testing/issues/33) for more details.
* @throws AssertionError if no such menu item exists, or the menu item is not enabled or visible, or it's nested in
* a menu item which is invisible or disabled, or it's attached to a component that's invisible.
*/
public fun HasMenuItems._click(item: MenuItem) {
val parentMap: Map, Component> = (this as Component).getParentMap()
if (!parentMap.keys.contains(item)) {
fail("${item.toPrettyString()} is not contained in this menu:\n${(this as Component).toPrettyTree()}")
}
item._click(parentMap)
}
/**
* @receiver can be of type [HasMenuItems] or [GridContextMenu].
*/
private fun Component.getItems(): List> {
return when(this) {
is ContextMenuBase<*, *, *> -> getItems()
else -> {
// every HasMenuItems implementor has the getItems() method including the MenuBar.
// can't use the MenuBar type directly though, to keep compatibility with Vaadin 13
val method: Method = this.javaClass.getMethod("getItems")
@Suppress("UNCHECKED_CAST")
method.invoke(this) as List>
}
}
}
/**
* Tries to find a menu item with given [id] and click it, passing in given [gridItem].
* @throws AssertionError if no such menu item exists, or the menu item is not enabled or visible, or it's nested in
* a menu item which is invisible or disabled, or it's attached to a component that's invisible.
*/
public fun GridContextMenu._clickItemWithID(id: String, gridItem: T?) {
_clickItemMatching(SearchSpec(MenuItemBase::class.java, id = id), gridItem)
}
/**
* Tries to find a menu item with given [caption] and click it, passing in given [gridItem].
* @throws AssertionError if no such menu item exists, or the menu item is not enabled or visible, or it's nested in
* a menu item which is invisible or disabled, or it's attached to a component that's invisible.
*/
public fun GridContextMenu._clickItemWithCaption(caption: String, gridItem: T?) {
_clickItemMatching(SearchSpec(MenuItemBase::class.java, text = caption), gridItem)
}
/**
* Tries to find a menu item matching given [searchSpec] and click it, passing in given [gridItem].
* @throws AssertionError if no such menu item exists, or the menu item is not enabled or visible, or it's nested in
* a menu item which is invisible or disabled, or it's attached to a component that's invisible.
*/
public fun GridContextMenu._clickItemMatching(searchSpec: SearchSpec>, gridItem: T?) {
// fires ContextMenuOpenedListener to simulate menu opening
setOpened(true, gridItem)
val parentMap: Map, Component> = getParentMap()
val predicate = searchSpec.toPredicate()
val item: MenuItemBase<*, *, *> = parentMap.keys.firstOrNull(predicate)
?: fail("No menu item with ${searchSpec.toString().removePrefix("MenuItemBase and ")} in GridContextMenu:\n${toPrettyTree()}")
@Suppress("UNCHECKED_CAST")
(item as GridMenuItem)._click(gridItem)
// fires ContextMenuOpenedListener to simulate menu closing
setOpened(false, gridItem)
}
private fun Component.getParentMap(): Map, Component> {
val result: MutableMap, Component> = mutableMapOf, Component>()
fun fillInParentFor(item: MenuItemBase<*, *, *>, parent: Component) {
result[item] = parent
item.getSubMenu().getItems().forEach { fillInParentFor(it, item) }
}
getItems().forEach { fillInParentFor(it, this) }
return result
}
/**
* Tries to click given menu item. [MenuItem.isChecked] is toggled if [MenuItem.isCheckable].
*
* Fails if no such menu item exists, or the menu item is not enabled or visible, or it's nested in
* a menu item which is invisible or disabled, or it's attached to a component that's invisible.
*
* Doesn't work for MenuItems nested in MenuBar.
* Use either [HasMenuItems._clickItemWithCaption] or [HasMenuItems._click].
* See [Issue 33](https://github.com/mvysny/karibu-testing/issues/33) for more details.
* @throws AssertionError if no such menu item exists, or the menu item is not enabled or visible, or it's nested in
* a menu item which is invisible or disabled, or it's attached to a component that's invisible.
*/
public fun MenuItem._click() {
val contextMenu: ContextMenu = contextMenu ?: fail("This function doesn't work on menu items attached to MenuBars. Use either menuBar._clickItemWithCaption(\"foo\") or menuBar._click(menuItem). See https://github.com/mvysny/karibu-testing/issues/33 for more details")
val parentMap: Map, Component> = contextMenu.getParentMap()
_click(parentMap)
}
/**
* Tries to click given menu item. [MenuItem.isChecked] is toggled if [MenuItem.isCheckable].
* @throws AssertionError if no such menu item exists, or the menu item is not enabled or visible, or it's nested in
* a menu item which is invisible or disabled, or it's attached to a component that's invisible.
*/
private fun MenuItem._click(parentMap: Map, Component>) {
checkMenuItemVisible(this, parentMap)
checkMenuItemEnabled(this, parentMap)
// toggle the isChecked first, so that the click event receives the most current value.
// https://github.com/mvysny/karibu-testing/issues/126
if (isCheckable) {
isChecked = !isChecked
}
_fireEvent(ClickEvent