New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UITester support for TableEditor #1707
Conversation
…dding needed commands queries and locators
… are allowed failures already)
…specific test for sorting)
Note that the index error provides more | ||
""" | ||
check_q_model_index_valid(index) | ||
return model.data(index, QtCore.Qt.DisplayRole) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is data
the right thing here for displayed text? (look at Qt docs for QAbstractItemModel
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, data
with DisplayRole
should provide the text to display.
On master the following TableEditor Tests fail on wx:
(Note this is effectively every test - I run Given this, I intend to skip all these tests on wx. Note this is now a part of #1533. Even further, I intend to rewrite the tests to use the new UI Tester support on Qt. Thus, even if the TableEditor issues are fixed, we will need to follow through with the UI Tester support to simply stop skipping these tests on wx. Either that or use this PR as a ref and revert the tests back to their old non UITester using state. I am doing this based off the following section of the developer guide in the traitsui docs: https://docs.enthought.com/traitsui/traitsui_dev_guide/testing.html#where-are-the-tests |
|
||
@requires_toolkit([ToolkitName.qt, ToolkitName.wx]) | ||
def test_table_editor_select_rows(self): | ||
object_list = ObjectListWithSelection( | ||
values=[ListItem(value=str(i ** 2)) for i in range(10)] | ||
) | ||
object_list.selections = object_list.values[5:7] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have shift click functionality to do this sort of thing with the tester...
target_class=SimpleEditor, | ||
interaction_class=SelectedIndices, | ||
handler=lambda wrapper, _: wrapper._target.selected_indices | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just added a SelectedIndices
query class.
For the current implementation, for TableEditor
, Selected
and SelectedIndices
effectively just serve as proxies to the selected
and selected_indices
traits on the table editor (see code above.)
In theory it may be better for these to dive down to the Qt level (?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one of the weird things with UITester support though IMO. We want to test traitsui editors are working correctly.
So having tests be down at qt level is really what we want. Ie I do something in traitsUI and we verify that does what we expect down in qt land.
However, say I were implementing the handler for the TableEditor to do a SelectedIndices
query. I would end up basically rewriting:
traitsui/traitsui/qt4/table_editor.py
Lines 626 to 643 in 347f0b5
@cached_property | |
def _get_selected_indices(self): | |
"""Gets the row,column indices which match the selected trait""" | |
selection_items = self.table_view.selectionModel().selection() | |
indices = self.model.mapSelectionToSource(selection_items).indexes() | |
if self.factory.selection_mode.startswith("row"): | |
indices = sorted(set(index.row() for index in indices)) | |
elif self.factory.selection_mode.startswith("column"): | |
indices = sorted(set(index.column() for index in indices)) | |
else: | |
indices = [(index.row(), index.column()) for index in indices] | |
if self.factory.selection_mode in {"rows", "columns", "cells"}: | |
return indices | |
elif len(indices) > 0: | |
return indices[0] | |
else: | |
return -1 |
It creates sort of a weird chasing your own tail scenario 🤔
For downstream users they just want to see that when they run their code, ____ is selected. For which this (just using traits on the editor) is perfectly fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UITester
strikes me as being useful for two things:
- testing that TraitsUI editors are integrating correctly with the toolkit
- as a framework for integration tests for TraitsUI apps
For unit tests of applications you can usually get away with tests at the traits level (does changing this trait in a UI change the corresponding thing in the model? or vice-versa) where you don't really care/can trust that the UI then does the right thing.
I believe once this PR gets the green light, a lot of the code can be pulled to add support for TabularEditor which also ends up wrapping a |
traitsui/testing/tester/_ui_tester_registry/qt4/_traitsui/table_editor.py
Outdated
Show resolved
Hide resolved
traitsui/testing/tester/query.py
Outdated
Implementations should return either a list of indicies of the selected | ||
objects, a single index of a lone selected object, or -1 if nothing is | ||
selected. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the rationality behind this API? Why not just return None
if nothing is selected? Also, why not always return a list - which might contain one or more elements depending on the size of the selection.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH it was because I am currently just mirroring the implementation of selected_indices
in the TableEditor
itself. See comment: #1707 (comment) and code:
traitsui/traitsui/qt4/table_editor.py
Lines 627 to 643 in 762f66b
def _get_selected_indices(self): | |
"""Gets the row,column indices which match the selected trait""" | |
selection_items = self.table_view.selectionModel().selection() | |
indices = self.model.mapSelectionToSource(selection_items).indexes() | |
if self.factory.selection_mode.startswith("row"): | |
indices = sorted(set(index.row() for index in indices)) | |
elif self.factory.selection_mode.startswith("column"): | |
indices = sorted(set(index.column() for index in indices)) | |
else: | |
indices = [(index.row(), index.column()) for index in indices] | |
if self.factory.selection_mode in {"rows", "columns", "cells"}: | |
return indices | |
elif len(indices) > 0: | |
return indices[0] | |
else: | |
return -1 |
I agree this is confusing though and lazy. I can at the very least wrap this with a special handler to give a more consistent return type. The SelectedIndices
query class has no reason to be at all tied with a specific Editor (in fact it definitely shouldn't be).
Nonetheless I do still have the question of whether or not I should be reimplementing/rewriting the above code in the UITester TableEditor support code as a specifc handler for the SelectedIndices
query. As mentioned in my comment I think that is a little unnecessary / we have this strange chase your own tail scenario... 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to carefully think about the best api for Selected and SelectedIndices before pushing this through 🤔
It i tricky because with a TableEditor, one could have rows, columns, cells, etc. selected. The api needs to accommodate this use case but also be general and not overly complex for other Editors to use
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am going to update Selected
so that it also always returns a list (either a singleton list for one selection, list of all objects selected, or an empty list if nothing is selected).
It is also a bit strange with SelectedText
as in that case it doesn't really make sense to want to make that query if multiple objects are selected (at least I can't imagine a use case). Hence for that I think I will not update it to enforce that it returns a list.
traitsui/testing/tester/query.py
Outdated
Note that an index could be an integer, or it could be a tuple e.g. | ||
corresponding to a specific cell at some (row, column) in a table. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
under what circumstances do we return an integer vs a tuple.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, it would be an int if selecting entire rows or columns, whereas it would be a tuple if selecting specific cells. However, if used with say a ListEditor, InstanceEditor, or EnumEditor, a selected index would likely be an integer. Currently those implementations do not exist (in current tests querying what is selected we just use SelectedText
rather than inspecting the object itself that is selected). These implementations can be added in the future though.
I've updated the doc string to try to make this more clear. ~(will push commit shortly)~Edit: done
Co-authored-by: Poruri Sai Rahul <rporuri@enthought.com>
|
||
process_cascade_events() | ||
self.assertEqual(selected, [object_list.values[5]]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the list here slightly clunkier than before... However, i think being consistent with the api of SelectedIndices
is more important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good at a high level. From examples of usage, looks like it is reasonably user-friendly.
After looking though these changes again, I felt like this branch (same as #1706) really was a good starting point. I went ahead and rebased on top of master, and will clean up this PR as needed with the intention that this ultimately will be merged.
I'm struggling to remember why I hadn't opened a PR for this previously. I suspect it was that the wx implementation is incomplete. Qt I believe is fully functional (?)
wx has allowed failures on CI, and many TableEditor tests already fail. I remember this making adding functionality difficult because even if I thought i had wx support working tests may have still failed for other reasons...
EDIT: I am going to remove any wx changes in this PR and defer adding wx support for TableEditor to a later PR
Checklist