0

So, I noticed that the it() functions inside describe() blocks don't (always) run in the order I wrote them.

Are they asynchronous then? And how to force them to run in a certain order ?

I want to chain a bunch of UI mutations and basically have each it() function check the state of the UI after the previous step.

If they are executed asynchronously, that kind of beats the point. That would mean each it() block would need to contain all the steps from the previous one?

it('should do something', function() {
  // app is in state 1
  // do something
  // leave app in state 2
});
it('should continue from the state left after the previous block', function() {
  // app is in state 2
  // do something
  // leave app in state 3
});
it('should continue from the state left after the previous block', function() {
  // app is in state 3
  // do something
  // leave app in state 4
});
it('should continue from the state left after the previous block', function() {
  // app is in state 4
  // do something
  // leave app in state 5
});
...
holographic-principle
  • 19,688
  • 10
  • 46
  • 62

1 Answers1

3

Everything inside an "it" function is an independent test. What you need to do is put shared steps in a "beforeEach" function

describe('Check pdf popup', function() {
    beforeEach(function() {
        element('.navbar a:eq(3)').click();
    });

    it('We should see the pdf popup', function() {
        expect(element('.modal h4:visible').text()).toMatch(/Email PDF/);
    });

    it('Cancel should dispel the pdf popup', function() {
        // exit pdf box
        element('input[value="Cancel"]').click();
        expect(repeater('.modal h4:visible').count()).toBe(0);
    });

    it('if customer email not set, display input for email', function() {
        expect(repeater('.modal #pdfemail:visible').count()).toBe(1);
        expect(repeater('.modal #pdfcustomercheckbox:visible').count()).toBe(0);
    });

});

You can nest additional "describe" blocks inside each other, containing additional "beforeEach" functions, having the effect of issuing consecutive commands.

describe('fuel comparison', function() {
    beforeEach(function() {
        element("#gasvsdiesel").click();
    });

    it('should switch to Fuel Comparison calculator', function() {
        expect(element('.brand').text()).
            toBe("Fuel Comparison");
    });

    describe('changing gas price', function() {
        beforeEach(function() {
            input("compareFuelPrice").enter("5.888");
        });

        it('should change fuelinfo text to show reset link', function() {
            element('#content .nav-pills a[tap-click="tab=\'calculations\'"]').click();
            expect(element("#fuelinfo span:visible").text()).toBe("(Click here to set fuel prices to California defaults)");
        });

    });
   });
Karen Zilles
  • 7,633
  • 3
  • 34
  • 33
  • In my case, they don't really have 'shared steps'. I just need every subsequent `it()` to continue from the state the previous one left the application in. How would I achieve this? – holographic-principle Jun 30 '13 at 21:15
  • I edited my question to better illustrate what I'm looking for. – holographic-principle Jun 30 '13 at 21:22
  • Each "it" must be completely independent. You have to restart from scratch between tests. I understood what you were asking for, but you're thinking about it the wrong way. The structure above is the right way to accomplish what you want. – Karen Zilles Jun 30 '13 at 21:29
  • As I said, I have no shared steps. So it doesn't apply to my case at all. Are the `it()` blocks executed synchronously or asynchronously? – holographic-principle Jun 30 '13 at 21:39
  • 1
    You're still thinking about it the wrong way. Every test is completely independent.. It should not matter which one runs first, because a correctly written test should not depend on any other test. Each block of code in an "it" statement is a completely separate test. I understand that you don't want to use it that way, but that's the way it's designed to be used. – Karen Zilles Jun 30 '13 at 21:44
  • In the first "beforeEach" statement, you navigate to the page, starting from scratch: beforeEach(function() { browser().navigateTo('/index.php/webapp/e2e'); }); – Karen Zilles Jun 30 '13 at 21:46
  • That would reset the state of the application, and that's the opposite of what I want. What I want is to preserve the state of the previous step (as a form of code reuse), in a long chain of steps with no branching (no branching == no use for beforeEach == no shared steps). – holographic-principle Jun 30 '13 at 21:48
  • Otherwise, writing more complicated tests would be VERY redundant. If there's really no way to achieve this, then I'd have to say I'm quite surprised with the inefficiency of these frameworks. – holographic-principle Jun 30 '13 at 21:50
  • You can always put multiple expect statements into the same test if you're worried about reloading the application too many times. In practice this hasn't been necessary for me. The e2e running is quite fast. – Karen Zilles Jun 30 '13 at 22:01
  • I'm worried about having to copy paste too many lines of code. In my example, `it #2` would need to have all code from `it #1`, `it #3` all code from `it #2` etc. – holographic-principle Jun 30 '13 at 22:04
  • Those are your shared steps. You nest them in beforeEach statements. At each level of depth you write "it" functions to test the current state, and write describe/beforeEach combos to move to the next state. Go in, not down :) – Karen Zilles Jun 30 '13 at 22:07
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/32652/discussion-between-finishingmove-and-karl-zilles) – holographic-principle Jun 30 '13 at 22:09