I have an angular application where I have a timeline with list event dates and the respective event description. This is the Html source code.
<!-- timeline -->
<h4 class="font-thin m-t-lg m-b-lg text-primary-lt">Historical Timeline</h4>
<p></p>
<div id="timeline"class="timeline m-l-sm m-r-sm b-info b-l">
<div ng-repeat = "timeline in formattedTimelineData | orderBy : '-eventDate'">
<div class = "tl-item">
<i class="pull-left timeline-badge {{timeline.class}} "></i>
<div class="m-l-lg">
<div id="eventDate{{$index}}" class="timeline-title">{{timeline.eventDate}}</div>
<p id="eventDescription{{$index}}" class="timeline-body">{{timeline.description}}</p>
</div>
</div>
</div>
</div>
<!-- / timeline -->
Now I am basically trying to make use protractor to ensure that the correct event date matches the event description. So i decided to use a map function. The issue is I would have a variable x which would tell me how many events there are . For example there can be 2 events, 6 events, etc. Events are dynamically
generated dynamically as you can tell by looking at html code also. Here is the code for my test I wrote.
it('FOO TEST', function(){
var x = 0;
while(x<4){
var timeline = element.all(by.css('#timeline')).map(function (timeline) {
return {
date: timeline.element(by.css('#eventDate'+x)).getText(),
events: timeline.element(by.css('#eventDescription'+x)).getText()
}
});
x++
}
timeline.then(function (Value) {
console.log(Value);
});
});
The issue is that for some reason in command line it only prints the last event out of 5 events. It does not print other events. I am definitely doing something wrong. I am brand new to promises so any suggestion here is appreciated. And yes i want to do like a individual test for each event in the timeline.
The problem is in the timeline
locator: #timeline
matches the timeline container while you need the inner repetative timeline blocks. Here is how you can match them:
var timeline = element.all(by.repeater('timeline in formattedTimelineData')).map(function (timeline) {
return {
date: timeline.element(by.binding('timeline.eventDate')).getText(),
events: timeline.element(by.binding('timeline.description')).getText()
}
});
timeline.then(function (timeline) {
console.log(timeline);
});
You can then loop over items like this:
timeline.then(function (timeline) {
for (var i = 0; i < timeline.length; ++i) {
// do smth with timeline[i]
}
});
Or, you can assert the complete timeline
variable which is a promise and can be implicitly resolved by expect
into an array of objects, for instance:
expect(timeline).toEqual([
{
date: "First date",
events: "Nothing happened"
},
{
date: "Second date",
events: "First base"
},
{
date: "Third date",
events: "Second base"
},
]);
I recommend against putting logic in your test - http://googletesting.blogspot.com/2014/07/testing-on-toilet-dont-put-logic-in.html.
A while loop is logic.
You should know ahead of time how many events will be in your timeline. In the example case 4. Then your specs should look like
element.all(by.css("#timeline")).then(function(events){
expect(events.count).toEqual(4);
expect(events[0].someThing()).toEqual(expectedValue0);
expect(events[1].someThing()).toEqual(expectedValue1);
...
expect(events[3].someThing()).toEqual(expectedValue3);
})
The repeater in my case has a lot of elements. I dont want to repeat through all elementsas my protractor spec times out while looping through so many elements. How can I just restrict the loop to run only for 1st 10 elements of the repeater? I have tried many things but I am just not able to get this working. How to loop only through first 10 elements of a repeater when using map()
The timeline variable in above example returns data for all elements in the repeater. How can i get the timeline variable to just have data for first 10 elements of the repeater as the looping through 1000 of entries of the repeater is time consuming that causes my protractor spec to timeout.