How can I show a hidden column of a grid using the Vaadin Testbench? - vaadin

I am doing some integration tests, and I have replaced some tables with a grid. At this moment, I have some visible columns by default and other columns are hidden as follows:
column6.setHidable(true);
column6.setHidden(true);
Now I am trying to do some integration tests. For getting the grid, I can use the method (is the only grid present in this view):
$(GridElement.class).first();
This works fine. But for my test (with Vaadin Testbench), I need to check some values that are inside the hidden columns of the grid. I am talking about this button:
I have tried to use the Vaadin debug console to get the name of the button that allows the user to show/hide columns, but the debug console only can select the entire grid element, not this menu.
Also I have check if inside the GridElement exists any kind of already implemented method that give me access to this menu without any success.

Usually, chrome developer tools (or similar for firefox and ie / edge, etc) is your best friend in such cases. So far I'm not aware of anything dedicated for that particular button. However you can workaround this limitation by selecting the items which compose this feature by their specific classes:
The below test method shows a quick implementation which should give you a starting point:
public class GridManipulationTest extends TestBenchTestCase {
#Before
public void setUp() throws Exception {
System.setProperty("webdriver.chrome.driver", "D:\\Kit\\chromedriver_win32\\chromedriver.exe");
setDriver(new ChromeDriver());
}
#After
public void tearDown() throws Exception {
// TODO uncomment below after checking all works as expected
//getDriver().quit();
}
#Test
public void shouldOpenGridColumnVisibilityPopupAndSelectItems() {
// class for the grid sidebar button
String sideBarButtonClass = "v-grid-sidebar-button";
// class for the sidebar content which gets created when the button is clicked
String sideBarContentClass = "v-grid-sidebar-content";
// xpath to select the item corresponding to the necessary column
// there are perhaps more "elegant" solutions, but this is what I came up with at the time
String columnMenuItemXpath = "//*[contains(#class, 'column-hiding-toggle')]/span/div[text()='Name']";
// open the browser
getDriver().get("http://localhost:8080/");
// get the first available grid
GridElement firstGrid = $(GridElement.class).first();
// look for the grid's sidebar button and click it
firstGrid.findElement((By.className(sideBarButtonClass))).click();
// the sidebar content is created outside the grid structure so don't look for it using the grid search context
WebElement sidebarContent = findElement(By.className(sideBarContentClass));
// look for the expected column name and click it
sidebarContent.findElement(By.xpath(columnMenuItemXpath)).click();
}
}
And of course what it looks like in action

Related

Testing-library unable to find rc-menu

I'm trying to implement integration tests on our React frontend which uses Ant design. Whenever we create a table, we add an action column in which we have a Menu and Menu Items to perform certain actions.
However, I seem unable to find the correct button in the menu item when using react-testing-library. The menu Ant design uses is rc-menu and I believe it renders outside of the rendered component.
Reading the testing-library documentation, I've tried using baseElement and queryByRole to get the correct DOM element, but it doesn't find anything.
Here's an example of what I'm trying to do. It's all async since the table has to wait on certain data before it gets filled in, just an FYI.
Tried it on codesandbox
const row = await screen.findByRole('row', {
name: /test/i
})
const menu = await within(row).findByRole('menu')
fireEvent.mouseDown(menu)
expect(queryByRole('button', { name: /delete/i })).toBeDisabled()
the menu being opened with the delete action as menu item
I had a same issue testing antd + rc-menu component. Looks like the issue is related to delayed popup rendering. Here is an example how I solved it:
jest.useFakeTimers();
const { queryByTestId, getByText } = renderMyComponent();
const nav = await waitFor(() => getByText("My Menu item text"));
act(() => {
fireEvent.mouseEnter(nav);
jest.runAllTimers(); // ! <- this was a trick !
});
jest.useRealTimers();
expect(queryByTestId("submenu-item-test-id")).toBeTruthy();

Behaviour of Table context menu in Vaadin 7.3 unclear

I have a simple use case: in a multi select Table
when the user selects 1 row, a context menu with two actions must be returned (DELETE and DOWNLOAD)
when the user selects more than one row, only the DELETE Action should be in the context menu
This is the code I use:
contactList.setMultiSelect(true);
final Action delete = new Action("Delete", FontAwesome.TIMES);
final Action download = new Action("Download", FontAwesome.DOWNLOAD);
contactList.addActionHandler(new Action.Handler() {
#Override
public Action[] getActions(Object target, Object sender) {
final Table table = (Table)sender;
// if Table is in multi select mode, getValues() returns Set of item id's
if (table.isMultiSelect() && ((Set)table.getValue()).size() > 1) {
return new Action[] {delete};
} else {
return new Action[] {delete, download};
}
}
...
I see that getActions() is called by the Table component every time a row selection is made. It returns the correct Action array. However, in the UI, only one context menu is used, independent of the actions returned.
This topic is not covered in The Book of Vaadin. There is an old question but the solutions is way too complicated and the solution suggested by Joonas is not working (in fact the case i describe here).
Its a well-known issue in Vaadin from version 6. Most people (including me) work-around this by using ContextMenu Addon

Extending SAP Fiori App - Adding button in the footer

I am extending hcm.emp.payslip app and need to add a button in the footer....what is the right way of doing it?..
option 1: placing a extension point as described in page 13 of this pdf.. -- it didnt work..I followed exactly the steps mentioned. or will this not work as we are inserting an extension point ourselfs and which is not supported now.?
option 2: extending UI controller hooks as described here -- I couldnt try this as the documentation is very brief and I am a beginner...Also I am not sure if we can change the view by extending controller
I am using eclipse, and installed the Tool kit plug-in, some places I saw they recommended using Web IDE, but we would like to do it using tool kit, as I am not sure if we have cloud HANA access. or is it still fine to use the UI tool kit way..
would like to suggest the right approach with detailed steps...
Your Option 1 is not possible(Why? Because to add button to the footer there is controllerHook not UI extension point)
Go with Option 2 there are already extensionHooks given in all the controllers (S3.controller.js and in S3_phone.controller.js) of detail pages of the application.
controllerHook : extHookChangeFooterButtons
by Default SAP builds headerFooterOptions and sends that object to your extension Hook
/**
* #ControllerHook Modify the footer buttons
* This hook method can be used to add and change buttons for the detail view footer
* It is called when the decision options for the detail item are fetched successfully
* #callback hcm.emp.payslip.view.S3_Phone~extHookChangeFooterButtons
* #param {object} objHdrFtr-Header Footer Object
* #return {object} objHdrFtr-Header Footer Object
*/
if (this.extHookChangeFooterButtons) {
objHdrFtr = this.extHookChangeFooterButtons(objHdrFtr);
}
So you in the extended controller, receive the same append:
extHookChangeFooterButtons: function (objHdrFtr) {
//first if the buttonsList is empty, create one.
//Actually in S3.controller.js buttonsList is not defined since there are no buttons
if (!objHdrFtr.buttonList) {
objHdrFtr.buttonList = [];
}
//then create a button:
var extendedButton = {
sId: "EXT_BUTTON",
sI18nBtnTxt: "SAMPLE", //make sure you add texts in respective i18n files
bEnabled: true,
onBtnPressed: function (evt) {
that.handleExtButtonPress(evt);
}
};
objHdrFtr.buttonList.append(extendedButton)
//as you can see SAP says to return the object
return objHdrFtr;
}
Suggestion: Its very easy to do it in Web IDE.
Why?
It takes no time SETUP.
Very easy to use, saves lot of time
Shows all controllerHooks,
extension Points in UI
For the above example in Fiori Inbox use B.aButtonList.push(extendedButton); which will add the button to the end of the list (instead of append)

Getting selected ListBox values on button Click | ZK

I am very new to ZK framework and trying to customize few things and have struck at one point which I am not sure how to achieve that.
I have a predefined section where I need to show 2 drop down and a button and need to persist those drop down values on button click event.
This is how It has been define in Spring file
<bean id="mybean" parent="parentBean" class="WidgetRenderer">
<property name="detailRenderer">
<bean class="DetailsListRenderer" parent="abstractWidgetDetailRenderer"/>
</property>
</bean>
Here mybean is being used to show main section and I am adding my drop down using this bean while button are being added to detailRenderer.
Save button is bind to onClick event, but I am not sure how I can fetch values from my custom drop down?
I am aware about binding those Dropdown with onClick event but they have to be in same class.
Can any one suggest me how I can fetch values of those drop down.I am creating down down with following code
Listbox listbox = new Listbox();
listbox.appendItem("item1", "item1");
listbox.appendItem("item2", "item2");
This is my button code in another class
protected void createUpdateStatusButton(Widget widget,Div container)
{
Button button = new Button(LabelUtils.getLabel(widget, buttonLabelName, new Object[0]));
button.setParent(container);
button.addEventListener("onClick", new EventListener()
{
public void onEvent(Event event)throws Exception
{
MyClass.this.handleSaveStatusEvent(widget, event);
}
});
}
You may want to listen to the onSelect (I prefer to use Events.ON_SELECT rather than writing the strings) which is more specific to when the Listbox selection changes.
Either way, the key is to get the information you want from the Event passed to your EventListener, rather than going back to your Listbox itself. The basic Event usually carries useful information on getTarget and getData but using more specific events (SelectEvent in this case) will give you access to more relevant info.
button.addEventListener(Events.ON_SELECT, new EventListener<SelectEvent<Listitem, MyDataObject>() {
public void onEvent(SelectEvent<Listitem, MyDataObject> event) {
// Now you can access the details of the selection event..
List<Listitem> selectedItems = event.getSelectedItems();
List<MyDataObject> selectedObjects = event.getSelectedObjects();
}
});
You can find out what events are available for different ZK widgets in their Component Reference documentation.
If I understand the question (I don't think I did in my previous response) you want to gather information from the page (eg: Listbox selection state) when the user clicks a button. Your problem being that you are using disparate classes to compose the page and so don't have access to the various ZK Components when the button is clicked.
(Ignoring the multiple class issue for a minute)
From a high level, there are sort of two camps in the ZK community. The newer MVVM approach suggests the view should push the relevant state to the back end as the user interacts with the front end. This way, the back end never needs to ask for the client state, and when the button is clicked, the values/state are on the server ready to be used.
The other camp binds the client to the server such that the back end always has access to the client Components and when the button is clicked, the values/state can easily be retrieved by interacting with the components.
Another approach is more like what I was talking about in my previous answer, to not bind the back end to the client at all but to rely on event data as much as possible. I favor this approach where it is sufficient.
Now, you're free to choose your favored approach and ZK has lots of documentation on how to work in either of these camps. The question then is where is the client state stored on the server (either pushed there by the client in MVVM or bound there in MVC). I don't think that's a question that can be solved here, that's a software engineering challenge. I personally suggest you take on standard ZK patterns so as not to but heads with the framework. If you really want to go your route, you can grab a reference to the Listbox on the fly like so:
public class Foo {
public static final String LISTBOX_ID = "myListbox";
public void renderListbox(Component parent, MyItem items) {
Listbox listbox = new Listbox();
listbox.setId(LISTBOX_ID);
listbox.setParent(parent);
for (MyItem item : items) {
listbox.appendItem(item.getName(), item);
}
}
}
public class Bar {
#Listen(Events.ON_CLICK + " = #saveButton")
public void saveButtonClicked(Event event) {
Component saveButton = event.getTarget();
Listbox listbox = (Listbox) saveButton.getFellow(Foo.LISTBOX_ID);
Set<Listitem> selection = listbox.getSelectedItems();
// do something
}

How to call a MXML class in ActionScript3.0 in Flex 3

I have a page made of custom components. In that page I have a button. If I click the button I have to call another page (page.mxml consisting of custom components). Then click event handler is written in Action-script, in a separate file.
How to make a object of an MXML class, in ActionScript? How to display the object (i.e. the page)?
My code:
page1.mxml
<comp:BackgroundButton x="947" y="12" width="61" height="22"
paddingLeft="2" paddingRight="2" label="logout" id="logout"
click="controllers.AdminSession.logout()"
/>
This page1.mxml has to call page2.mxml using ActionScript code in another class:
static public function logout():void {
var startPage:StartSplashPage = new StartSplashPage();
}
Your Actionscript class needs a reference to the display list in order to add your component to the stage. MXML is simply declarative actionscript, so there is no difference between creating your instance in Actionscript or using the MXML notation.
your function:
static public function logout():void {
var startPage:StartSplashPage = new StartSplashPage();
}
could be changed to:
static public function logout():StartSplashPage {
return new StartSplashPage();
}
or:
static public function logout():void {
var startPage:StartSplashPage = new StartSplashPage();
myReferenceToDisplayListObject.addChild( startPage );
}
If your actionscript does not have a reference to the display list, than you cannot add the custom component to the display list. Adding an MXML based custom component is no different than adding ANY other DisplayObject to the display list:
var mySprite:Sprite = new Sprite();
addChild(mySprite)
is the same as:
var startPage:StartSplashPage = new StartSplashPage();
myReferenceToDisplayListObject.addChild( startPage );
Both the Sprite and the StartSplashPage are extensions of DisplayObject at their core.
You reference MVC in the comments to another answer. Without knowing the specific framework you've implemented, or providing us with more code in terms of the context you are trying to perform this action in, it is difficult to give a more specific answer.
I assume that you are on a page with a set of components and want to replace this set of components on the page with a different set of components. My apologies in advance if this is not what you are trying to do.
You can do this using ViewStacks and switching the selected index on selection -- this can be done either by databinding or by firing an event in controllers.AdminSession.logout() and listening for that event in the Main Page and switching the selectedIndex of the view stack in the handler function.
MainPage.mxml
<mx:ViewStack>
<views:Page1...>
...
<comp:BackgroundButton x="947" y="12" width="61" height="22"
paddingLeft="2" paddingRight="2" label="logout" id="logout"
click="controllers.AdminSession.logout()"/>
</views:Page1...>
<views:Page2 ...>
...
<comp:Comp1 .../>
<comp:Comp2 .../>
</views:Page2>
I think you may use state to do you work.
You may take a look at http://blog.flexexamples.com/2007/10/05/creating-view-states-in-a-flex-application/#more-221
Edit:
I am not sure I fully understand your case.
As I know, you may make a new state in page1.mxml, and name it, eg. secondPageState, and then put the custom component page2.mxml in the secondPageState.
In the controller, you need an import statement to import the page1 component and make a public var for the page1 component, eg. firstPage.
Then, the code will similar to:
public function logout():voild
{
firstPage.currentState = "secondPageState";
}
Another solution:
If you don't like the change state solution, you may try to use the addchild, to add the custom component to your application.

Resources