Let's take a deeper look at selecting specific elements on the page with Protractor locators. We can also divide our tests up into specific suites of related tests with a bit of configuration.
Protractor offers a lot of different ways to select items on the page, which it refers to as "locators," and we're going to look at a couple of different ones today.
You can see here we just have our basic page structure set up here. We're going to load our IndexPage. We're going to get the page before each of our tests, and then what we've done here is I've added a list to our page. It's just an unordered list with a class of list.
The ng-repeat is going to iterate over items, which I've defined in the controller as just as string of names. Then we've got a click action and an ng-class based on whether or not the item is selected.
Basically, clicking on the item is just going to toggle it between red and regular text. You can see that here, if we go in and click on any of these names, it turns them red. If you click on it again, it will turn that back off. That's what we're looking at here.
If we go into our locators.spec file here...I've just started a fresh spec file. We add in "First item should be Ben." What we're going to say here is "element.all," which is going to return an element array. That's going to be multiple items.
We're going to select those multiple items by binding item.name. If we go back and look at our template, we can see that item.name is in fact our binding here, so that's what's going to get selected. It's going to select all of those list items.
We're then going to tell it "Select the first item of that array that you get back, then get the text, and then expect that to be Ben." If we save this and go run our tests, you can see that it will start up, and we'll get a success there because Ben is in fact the first item in that list.
If we then add a second test here, we can say that the third item should be Sophi. We're going to have a different way to select these things this time. This time, we're going to say, "by.css('.list')," so that is going to match our ul tag here. This is just wrapped in a regular element call, so we're going to get that list element there.
Then we're going to say, "From that element, get all of the li items within that list." Once we've gotten all of those li items so we're back to an array of elements again, we're then going to say, "Get the item at the second index, the third item in the list, and expect that text to be Sophi." We can save that, again run our file or our tests, and again we get a pass.
The next thing we'll do is we're going to look at a Protractor-specific selector. These items more or less just come straight from WebDriver, but this next one is specific to Protractor. We're going to use the by.repeater selector here, so "by.repeater('item in items')," which of course maps to our ng-repeat attribute here.
"by.repeater('item in items').row(4)," the row at the index of four, and then we're going to select the column by the binding name. I'm not crazy about this syntax. It's a little bit odd, and it's very finicky.
You can see here that I actually have spaces between my curly braces and the item.name, and that is because I have that here as well. It has to match exactly.
Whereas if you're just doing a regular by binding, you just say, "By binding messageText," and the spaces around that don't matter. Be careful about that if you are going to use this sort of selector.
We can say, "Get the row at index four, the column where the binding is item.name, and then expect that text to be Henry." We can go run that here and again see that we will get a passing test.
The last thing I want to look at is just basically another form of selecting items from the same list. We're going to use the "by.css('.list')" again. That's wrapped in an element.
All of the li items again. Then we're just going to use "first" and "get(2)" here. We're really just repeating what we've got up here, but in this case, we're saving references to these items.
Then we're going to click on the one named "sophi," and then we're going to inspect these items to make sure that sophi has been given the class of selected and ben has not because we've not clicked on that. Now we're actually testing a little bit of interaction. Run this again, and see that those tests pass.
We could refine this a little bit more. Since we're actually repeating this part of the selector, we could actually just say, "var listItems =" that, and then we could do "listItems.first()" and "listItems.get(2)." That would work the same.
You've seen that each time we run this, these tests, we're actually running six tests, whereas we've only got four in here. The other two are the basic tests we started out, where it's just checking the title of the page and that our button click works.
As your collection of tests starts to grow, a lot of times, it's advantageous to be able to just run different pieces of them. The way that you do that is using the suite argument to Protractor.
Over here, in my Protractor config, I have set up this suites property rather than the specs property and told it that we've got two different suites here. We've got the basics, which maps to our basic tests, and then our locators.
What we can now do, when we've got it separated out like that...If we take this Protractor argument that we've been using in the terminal and then add "--suite=locators," we can then run that.
It will only run our locators tests, and we can skip over the ones that we're not particularly interested in right now. You can see this time, we just ran those four tests that we're actually interested in.