Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add method to wait for loading to complete in Add Panel table #21109

Merged
merged 3 commits into from
Jul 25, 2018
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion test/functional/services/dashboard/add_panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ export function DashboardAddPanelProvider({ getService, getPageObjects }) {
}
}

async waitForEuiTableLoading() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this function could go somewhere more general as it might be useful for other places that use the eui table and want to wait for it to load. I don't see a good spot for it right now. Maybe a new service named euiComponents? Could take in an optional selector name to use to narrow down but I wonder if you can use it without an element, directly on remote (just like we do for the global loading indicator - making sure it doesn't exist at all, anywhere on the page).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that. But the euiBasicTable can get populated from any data source and doesn't necessarily require a request/response to Elasticsearch so I'm not sure what to do.

Again, the retry loop in setValue seems like it should always handle the case where the field isn't initially user-editable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this function could go somewhere more general as it might be useful for other places that use the eui table and want to wait for it to load. I don't see a good spot for it right now. Maybe a new service named euiComponents?

There is a flyout service and I have a PR out for a combo box service. #21219.

const addPanel = await testSubjects.find('dashboardAddPanel');
await addPanel.waitForDeletedByClassName('euiBasicTable-loading');
}

async closeAddPanel() {
log.debug('DashboardAddPanel.closeAddPanel');
const isOpen = await this.isAddPanelOpen();
Expand Down Expand Up @@ -172,7 +177,12 @@ export function DashboardAddPanelProvider({ getService, getPageObjects }) {
}

async filterEmbeddableNames(name) {
await testSubjects.setValue('savedObjectFinderSearchInput', name);
// The search input field may be disabled while the table is loading so wait for it
await this.waitForEuiTableLoading();
// This try loop lets us recover it the field wasn't enabled yet
await retry.try(async () => {
await testSubjects.setValue('savedObjectFinderSearchInput', name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this extra retry loop adds anything because there is already a retry loop on the inside of setValue:

async setValue(selector, text) {
      return await retry.try(async () => {
        await this.click(selector);
        // in case the input element is actually a child of the testSubject, we
        // call clearValue() and type() on the element that is focused after
        // clicking on the testSubject
        const input = await remote.getActiveElement();
        await input.clearValue();
        await input.type(text);
      });
    }

We could think about confirming that the value was actually set by adding something in that function call that does like:

async setValue(selector, text) {
      return await retry.try(async () => {
        await this.click(selector);
        // in case the input element is actually a child of the testSubject, we
        // call clearValue() and type() on the element that is focused after
        // clicking on the testSubject
        const input = await remote.getActiveElement();
        await input.clearValue();
        await input.type(text);
        const newValue = await this.getVisibleText(selector);
         if (newValue != text) {
           throw new Error('Value was not set');
          } 
      });
    }

But I'm not sure if getVisibleText is what we'd want or if it's work on all element types (might be something like getValue we should use?).

Copy link
Author

@LeeDr LeeDr Jul 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize that setValue method had a retry loop. But that makes me wonder why it wasn't solving this problem from the beginning. The first error in this case was coming from the clearValue() step in that setValue method;
invalid element state: Element must be user-editable in order to clear it.

But then the next message says that it failed to find the element.
no such element: Unable to locate element: {"method":"css selector","selector":"[data-test-subj~="savedObjectFinderSearchInput"]"}

And when the test finally fails and takes a screenshot, we see that it has navigated away from the Add Panel flyout and has opened the New visualization page (which might explain why it can no longer find the element). It seems as if this inner-most retry isn't staying in this loop for some reason, and an outer retry is trying to clicking on "Add" again, or somewhere else that causes the incorrect navigation.

What you don't see here is the debug logging I had in place which did show that the euiBasicTable did initially show the euiBasicTable-loading class every time we opened the Add Panel flyout and that it was gone after we waited for it to be deleted;

         │ debg  DashboardAddPanel.isAddPanelOpen
         │ debg  TestSubjects.exists(dashboardAddPanel)
         │ debg  existsByDisplayedByCssSelector [data-test-subj~="dashboardAddPanel"]
         │ debg  TestSubjects.find(dashboardAddPanel)
         │ debg  findByCssSelector [data-test-subj~="dashboardAddPanel"]
         │ debg  ################################################################# euiBasicTable euiBasicTable-loading
         │ debg  ##############################++++++++++++++++++++++++++++++++++++++ euiBasicTable
         │ debg  TestSubjects.find(savedObjectFinderSearchInput)
         │ debg  findByCssSelector [data-test-subj~="savedObjectFinderSearchInput"]
         │ debg  isGlobalLoadingIndicatorVisible
         │ debg  TestSubjects.exists(globalLoadingIndicator)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, so my suspicion is that the mechanism for typing selenium uses is accidentally hitting the Add Visualization button. Once the page navigates away, doesn't matter how many times it loops, it's going to fail. That's why I think we have to add a function that waits till the flyout finishes it's transition before we even start typing into that field.

});
await PageObjects.header.waitUntilLoadingHasFinished();
}

Expand Down