Looping over the map function in protractor

2019-05-07 05:05发布

问题:

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.

回答1:

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"
    }, 
]);


回答2:

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);
 })


回答3:

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.