Protractor - Page Object is not updating when the

2019-05-11 11:22发布

问题:

I am testing a SPA built with angular.js and im using Page Objects pattern to write my tests. In the app we have a number of lists that will be updated. For example there is a list of attachments that will update when ever attachments are added/removed. To add an attachment we have a modal window and when we upload a file and click ok. The file uploads and the lists update.

I have written 2 page objects, one for the upload modal window and the other one for the preview of the attachment list. In my tests i first get the current count of the attachments then i click on a button to activate the modal window and attach the file. Then i take another count of the attachments in the preview page and compare it to be incremented by 1. But the tests fails. The page object is not updated and it still shows attachment count as 2.

Test

it('Should attach a file when a file is selected and OK button is pressed.', function () {
            var currentFileCount = viewMeetingTabPage.getMeetingAttachmentCount();

            viewMeetingPage.clickAddAttachmentButton();
            addAttchmentPage.attachFile();
            addAttchmentPage.clickConfimAttachFileButton();

            currentFileCount.then(function (curCount) {
                viewMeetingTabPage.getMeetingAttachmentCount().then(function (newCount) {
                    expect(newCount).toBe(curCount + 1);
                    //expect(viewMeetingTabPage.getMeetingAttachmentName()).toBe('test-file.pdf');
                });
            });
        });

ViewMeetingTabPage

this.getMeetingAttchments = function () {
        return element.all(by.repeater('attachment in meeting.AttachmentViewModelList track by $index'));
    };

this.getMeetingAttachmentCount = function () {
        return this.getMeetingAttchments().count();
    };

What i need to have is to somehow update the page object after i upload the file. How can i do that.

回答1:

This is how the control-flow works. Executing the code for the test queues a bunch of promises. They get resolved in the order they were added to the flow while each of them waits for the previous to finish.

it('Should attach a file when a file is selected and OK button is pressed.', function () {
        # Queues the count promise
        var currentFileCount = viewMeetingTabPage.getMeetingAttachmentCount();

        # Queues some other promises that would start
        # to get executed once the one above finishes
        viewMeetingPage.clickAddAttachmentButton();
        addAttchmentPage.attachFile();
        addAttchmentPage.clickConfimAttachFileButton();

        # This piece of code branches-off the control-flow
        # and gets executed immediately after currentFileCount is resolved
        # i.e. before the clickAddAttachmentButton
        currentFileCount.then(function (curCount) {
            # That's why newCount equals curCount,
            # they are counting the same number of elements
            # since nothing changed in the meantime
            viewMeetingTabPage.getMeetingAttachmentCount().then(function (newCount) {
                expect(newCount).toBe(curCount + 1);
                //expect(viewMeetingTabPage.getMeetingAttachmentName()).toBe('test-file.pdf');
            });
        });
    });

currentFileCount could be considered a setup phase for the test so you can extract it to a beforeEach block:

var initialFileCount;
beforeEach(function() {
    viewMeetingTabPage.getMeetingAttachmentCount().then(function(count) {
        initialFileCount = count;
    });
});

it('Should attach a file when a file is selected and OK button is pressed.', function () {
    viewMeetingPage.clickAddAttachmentButton();
    addAttchmentPage.attachFile();
    addAttchmentPage.clickConfimAttachFileButton();
    expect(viewMeetingTabPage.getMeetingAttachmentCount()).toBe(initialFileCount + 1);
});

Since protractor patches jasmine to wait between the test-blocks for the control-flow to empty, this would probably work.

Keep in mind expect is also patched to handle promises so you don't need to place it in a then.

UPDATE:

Actually, you shouldn't need the beforeEach above, it is supposed to work like that too:

var initialFileCount;

it('Should attach a file when a file is selected and OK button is pressed.', function () {
    viewMeetingTabPage.getMeetingAttachmentCount().then(function(count) {
        initialFileCount = count;
    });
    viewMeetingPage.clickAddAttachmentButton();
    addAttchmentPage.attachFile();
    addAttchmentPage.clickConfimAttachFileButton();
    expect(viewMeetingTabPage.getMeetingAttachmentCount()).toBe(initialFileCount + 1);
});

It's called framing in the WebDriverJS User’s Guide.