سؤال

I have a strange bug I'm trying to re-create with a test. I know what's causing the bug and how to fix it, but I can't figure out how to test it properly.

Scenario:

  • My browser is on http://example.com/foo
  • I click a link on that page with href="/foo" (the same page)
  • The browser should reload the same page

I tried:

class SamePageHyperlinkSpec extends StatelessUserWebGebSpec {

    def 'users is on Foo page and clicks foo link'() {

        when:
            to FooPage

        then:
            // navigation.foo is a property in a super class that references
            // a particular navigation item
            navigation.foo.click()

        and:
            at FooPage
    }
}

...but that gave a false positive because although the browser didn't reload the page, it was already on that page. So, I figured I'd take a look at the PageChangeListener which should allow me to pass/fail on page change:

class SamePageHyperlinkSpec extends StatelessUserWebGebSpec {

    def 'users is on Foo page and clicks foo link'() {

        given:
            def listener = new MyPageChangeListener()
            browser.registerPageChangeListener(listener)

        when:
            to FooPage
        and:
            listener.changeCount = 0

        then:
            // navigation.foo is a property in a super class that references
            // a particular navigation item
            navigation.foo.click()

        and:
            at FooPage

        and:
            listener.changeCount == 1
    }
}

class MyPageChangeListener implements PageChangeListener {

    int changeCount = 0

    void pageWillChange(Browser browser, Page oldPage, Page newPage) {
        println "browser '$browser' changing page from '$oldPage' to '$newPage'"
        changeCount++
    }
}

...that fails (as it should) when there is no page reload, however it also fails when there is a page reload, because the page it ends up on is the same, ergo no page change happened.

I also tried duplicating the Page class (and it's "at" closure), however that always passed regardless of whether there was a page reload or not.

So, how do I test that the page has reloaded when I click a link to the current page?

هل كانت مفيدة؟

المحلول

Taking @PaulHarris' lead, the JS approach seems to do the trick:

class SamePageHyperlinkSpec extends StatelessUserWebGebSpec {

    def 'users is on Foo page and clicks foo link'() {

        when:
            to FooPage

        and:
            browser.js.exec '$(document.body).attr("data-not-reloaded",true);'

        then:
            // navigation.foo is a property in a super class that references
            // a particular navigation item
            navigation.foo.click()

        and:
            at FooPage

        and:
            browser.js.exec 'return $(document.body).attr("data-not-reloaded") === undefined';
    }
}

نصائح أخرى

Here is a better and tested version of WaitForPageLoad implementation in C#.Net

public void WaitForPageLoad(int maxWaitTimeInSeconds) {
string state = string.Empty;
try {
    WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(maxWaitTimeInSeconds));

    //Checks every 500 ms whether predicate returns true if returns exit otherwise keep trying till it returns ture
    wait.Until(d = > {

        try {
            state = ((IJavaScriptExecutor) _driver).ExecuteScript(@"return document.readyState").ToString();
        } catch (InvalidOperationException) {
            //Ignore
        } catch (NoSuchWindowException) {
            //when popup is closed, switch to last windows
            _driver.SwitchTo().Window(_driver.WindowHandles.Last());
        }
        //In IE7 there are chances we may get state as loaded instead of complete
        return (state.Equals("complete", StringComparison.InvariantCultureIgnoreCase) || state.Equals("loaded", StringComparison.InvariantCultureIgnoreCase));

    });
} catch (TimeoutException) {
    //sometimes Page remains in Interactive mode and never becomes Complete, then we can still try to access the controls
    if (!state.Equals("interactive", StringComparison.InvariantCultureIgnoreCase))
        throw;
} catch (NullReferenceException) {
    //sometimes Page remains in Interactive mode and never becomes Complete, then we can still try to access the controls
    if (!state.Equals("interactive", StringComparison.InvariantCultureIgnoreCase))
        throw;
} catch (WebDriverException) {
    if (_driver.WindowHandles.Count == 1) {
        _driver.SwitchTo().Window(_driver.WindowHandles[0]);
    }
    state = ((IJavaScriptExecutor) _driver).ExecuteScript(@"return document.readyState").ToString();
    if (!(state.Equals("complete", StringComparison.InvariantCultureIgnoreCase) || state.Equals("loaded", StringComparison.InvariantCultureIgnoreCase)))
        throw;
}
}

What about if you write down some value in a text field of the page,make a wait routine that waits for this text field to not be included on the page and after that you click the link? So the procedure would be this:

1.- Write some new value in a text field or add a new html tag or something using js.

2.- Make a routine to wait until the element/value that you added to the page is not included on the page.

3.- Click the link.

4.- Call the waiting code.

Let me know if this works for you.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top