How do I select option in ant design Select component with any e2e automation framework? (I will be able to rewrite your solution to playwright which I am personally using)
I know the question might seem simple so you might be tempted to suggest something like await click('#option-id') I really wish it would be that easy. I have tried almost everything from simple clicking, absolute mouse positioning, virtual={false}, dispatching custom mouse and keyboard events, combinations of timeouts/hoovers/force clicks and everything else stated in this list unfortunately nothing works.
I believe this question could be answered only by somebody who has this option selection logic in his currently maintained code because the component is constantly updated and any assumptions you make now are going to be different after a year or so.
I also read every issue about this problem and maintainers/developers doesn't seem to care much because they are not using such tests.
I don't want to discourage anyone from answering just so you know I have tried.
The Playwright Element Handle has the Query All Selector. If at least a part of the xpath stays the same, you can use the $$ selector.
The function will return <Promise<Array<ElementHandle>>> which you may then resolve and hook onto the index of the selection you want to make.
For instance -
const selector = "//div[contains(#attribute, 'selection-options-partial-id-text')]"
const allSelectionOptions = await page.$$(selector);
await allSelectionOptions[index].click();
This will work, assuming that all the options under Select must have a common portion in their xpath, or if defined, their data-test-id.
Related
I've got a component that grabs the primary names out of an array of names based on it's role, and then creates those as the options within the select statement. The field is required, and I want to test the values within the field.
I'm using react testing library to do this, but man am I new to this stuff. Checkout my code below, essentially I wanna know how to grab a value from a select statement to assert it. Bonus points for the man that teaches a man how to fish, how do you guys check the values that are currently within a test, do you have a way of console logging the elements you use the get commands on?
Here's my code for the test:
And here's the code for the component:
The options are just random values of names of people, there will be no default blank option once it's created that function, and it will auto select the first value
I think this is a very specific case, that we cannot reproduce in a codesandbox as we don't have your components and logic.
However, there are some questions that come to mind and might help you.
I see that you're firing a change event in an input, then a blur and then a click. You can probably use the user-event library and use userEvent.type and userEvent.click to simulate a user behavior. This can help you get rid of that blur and your test would be more legible.
The await getBy... query does not make sense, as getBy is a synchronous query, and you only need to use the await with findBy queries.
I don't understand what the test is suppossed to test. Querying a text inside a innerHTML can be done differently, by doing expect(x).toHaveTextContent('myText') or if you want to query inside another element you can use within, to do something like: within(getByLabelText('Main Contact')).getByText('hello').
This within function is really useful when testing values inside of a dropdown, so that you don't query the whole screen, and instead you query only the specific element.
So I have been plowing the internet to understand or see and example of what I want to do.
It shouldn't be difficult, but something is just missing to me.
The Scenario
I have a search page, built from 2 directives/ ui-views like this:
What I want to achieve
When I press Search, I want to trigger the Search Results directive/ view to fetch the corresponding results based on the search form parameter.
Where I am stuck
Because I have 2 separate directives, I can make them share information using the parent controller, OR the search service I have (to communicate with the backend).
However, The search directive can write information to either one, BUT the results are still not triggered. Unless I actively check for changes every once in a while for changes, I won't get the cling saying I have been triggered.
That is definitely not the the AngularJS way, and I just don't seem to have enough experience to think of something else.
What I am asking you
How would you approach this situation, what will you use to make this page as clean as you can, and modular (of course).
I've had ideas that at the worst case scenario, I will omit the modular approach, and just do it dirty, but working.
Still, this annoys me because as far as I know, this is one of the STRONGEST features of Angular.
I'd appreciate if you could attach some code for all to see and learn
As far as I see, this page is turning around of search functionality. So what I suggest you to implement here - to include search text into your routing parameters.
Your Search box which is help user to write down search query. Make it add search query to routing as some parameter, once user click Search button. It will be the only one responsibility of Search box, to change location URL, literally.
Action: User wrote down Founder in the search box input and pressed button Search.
Result: Location changed from #/search/ to #/search/Founder
The search result view should just respond to the location change. If the search string is changed, it should do all needed calls to the server, and return, process and represent search result in the Search result block.
JS Bin here
This article describes a clever way to see if your (pure Angular) form model has changed since the initial load. In my mind it's a more accurate test of $dirty/$pristine. This allows us to do things like hide the "Save" button for a form if the model hasn't changed, even if the user has typed then deleted text.
So the question is, how can we do this with angular-formly? My hunch is that onChange for each field might be a good starting point, but I'm having a lot of trouble putting together the rest of the solution.
Hope the question makes sense. Any ideas would be very welcome. Thanks!
This might work in a limited capacity:
scope.initialValue;
var listener = scope.$watch(function(oldVal,newVal){
scope.initialValue = oldVal
listener();
})
atinder was correct in that the pure Angular approach actually works fine with angular-formly. I've created a working JS Bin here.
Started with Angular and Protractor.
It just feels wrong to write some heavy css selectors which will break instant when you change something.
Using ID's would make testing way easier.
I'm not using any id attribute for styling yet. Are there any drawbacks using ids for testing I haven't considered?
The general rule is to use IDs whenever possible assuming they are unique across the DOM and not dynamically generated. Quoting Jim Holmes:
Whenever possible, use ID attributes. If the page is valid HTML, then
IDs are unique on the page. They're extraordinarily fast for
resolution in every browser, and the UI can change dramatically but
your script will still locate the element.
Sometimes IDs aren't the right choice. Dynamically generated IDs are
almost always the wrong choice when you're working with something like
a grid control. You rely on an id that is likely tied to the specific
row position and then you're screwed if your row changes.
Also, in general try to use the "data-oriented" approach: by.model, by.binding, by.repeater locators, or if you rely on class names, choose them wisely: do not use layout-oriented classes like .col-xs-4 or .container-fluid.
See also these related topics:
Best Practices for Watir and Selenium Locators
best way to detect an element on a web page for seleniumRC in java
When I started working on my current project I was given quite an arduous task - to build something that in essence suppose to replace big spreadsheet people use internally in my company.
That's why we I thought a paginated table would never work, and quite honestly I think pagination is stupid. Displaying dynamically changing data on a paginated table is lame. Say an item on page #2 with next data update can land on page whatever.
So we needed to build a grid with nice infinite scroll. Don't get me wrong, I've tried many different solutions. First, I built vanilla ng-repeat thing and tried using ng-infinite-scroll, and then ng-scroll from UI.Utils. That quickly get me to the point where scrolling became painfully slow, and I haven't even had used any crazy stuff like complicated cell templates, ng-ifs or filters. Very soon performance became my biggest pain. When I started adding stuff like resizable columns and custom cell templates, no browser could handle all those bindings anymore.
Then I tried ng-grid, and at first I kinda liked it - easy to use, it has a few nice features I needed, but soon I realized - ng-grid is awful. Current version stuffed with bugs, all contributors stopped fixing those and switched to work on a next version. And only God knows when that will be ready to use. ng-grid turned out to be pretty much worse than even vanilla ng-repeat.
I kept trying to find something better. trNgGrid looked good, but way too simplistic and doesn't offer features I was looking for out of the box.
ng-table didn't look much different from ng-grid, probably it would've caused me same performance issues.
And of course I needed to find a way to optimize bindings. Tried bind-once - wasn't satisfied, grid was still laggy. (upd: angular 1.3 offers {{::foo}} syntax for one-time binding)
Then I tried React. Initial experiment looked promising, but in order to build something more complicated I need to learn React specifics, besides that thing feels kinda non-anguleresque and who knows how to test directives built with angular+react. All my efforts to build nice automated testing failed - I couldn't find a way to make React and PhanthomJS to like each other (which is probably more Phantom's problem. is there better headless browser) Also React doesn't solve "appending to DOM" problem - when you push new elements into the data array, for a few milliseconds browser blocks the UI thread. That of course is completely different type of problem.
My colleague (who's working on server-side of things) after seeing my struggles, grumbled to me that I already spent too much, trying to solve performance problems. He made me to try SlickGrid, telling me stories how this is freakin zee best grid widget. I honestly tried it, and quickly wanted to burn my computer. That thing completely depends on jQuery and bunch of jQueryUI plugins and I refuse to suddenly drop to medieval times of web-development and lose all angular goodness. No, thank you.
Then I came by ux-angularjs-datagrid, and I really, really, really liked it. It uses some smart bad-ass algorithm to keep things very responsive. Project is young, yet looks very promising. I was able to build some basic grid with lots of rows (I mean huge number of rows) without straying too much from the way of angular zen and scrolling still smooth. Unfortunately it's not a complete grid widget solution - you won't have resizable columns and other things out of the box, documentation is somewhat lacking, etc.
Also I found this article, and had mixed feelings about it, these guys applied a few non-documented hacks to angular and most probably those would breaks with feature versions of angular.
Of course there are at least couple of paid options like Wijmo and Kendo UI. Those are compatible with angular, however examples shown are quite simple paginated tables and I'm not sure if it is worth even trying them. I might end-up having same performance issues. Also you can't selectively pay just for the grid widget, you have to buy entire suite - full of shit I probably never use.
So, finally to my question - is there good, guaranteed, less painful way to have nice grid with infinite scrolling? Can someone point to good examples, projects or web-pages? Is it safe to use ux-angularjs-datagrid or better to build my own thing using angular and react? Anybody ever tried Kendo or Wijmo grids?
Please! Don't vote for closing this question, I know there are a lot of similar questions on stackoverflow, and I read through almost every single one of them, yet the question remains open.
Maybe the problem is not with the existing widgets but more with the way you use it.
You have to understand that over 2000 bindings angular digest cycles can take too long for the UI to render smoothly. In the same idea the more html nodes you have on your page, the more memory you will use and you might reach the browser capacity to render so many nodes in a smooth way. This is one of the reason why people use this "lame" pagination.
At the end what you need to achieve to get something "smooth" is to limit the amount of displayed data on the page. To make it transparent you can do pagination on scroll.
This plunker shows you the idea, with smart-table. When scrolling down, the next page is loaded (you will have to implement the previous page when scrolling up). And at any time the maximum amount of rows is 40.
function getData(tableState) {
//here you could create a query string from tableState
//fake ajax call
$scope.isLoading = true;
$timeout(function () {
//if we reset (like after a search or an order)
if (tableState.pagination.start === 0) {
$scope.rowCollection = getAPage();
} else {
//we load more
$scope.rowCollection = $scope.rowCollection.concat(getAPage());
//remove first nodes if needed
if (lastStart < tableState.pagination.start && $scope.rowCollection.length > maxNodes) {
//remove the first nodes
$scope.rowCollection.splice(0, 20);
}
}
lastStart = tableState.pagination.start;
$scope.isLoading = false;
}, 1000);
}
This function is called whenever the user scroll down and reach a threshold (with throttle of course for performance reason)
but the important part is where you remove the first entries in the model if you have loaded more than a given amount of data.
I'd like to bring your attention towards Angular Grid. I had the exactly same problems as you said, so ended up writing (and sharing) my own grid widget. It can handle very large datasets and it has excellent scrolling.