Click all anchor tags on page with given class, but cancel prior to navigation

人走茶凉 提交于 2019-12-04 19:31:38
Artjom B.

There are two problems that you're dealing with.

1. Select elements based on class

Usually a class is used multiple times. So when you first select elements based on this class, you will get elements that have that class, but it is not guaranteed that this will be unique. See for example this selection of element that you may select by .myClass:

  1. myClass
  2. myClass myClass2
  3. myClass myClass3
  4. myClass
  5. myClass myClass3

When you later iterate over those class names, you've got a problem, because 4 and 5 can never be clicked using casper.click("." + links[i].replace(" ", ".")) (you need to additionally replace spaces with dots). casper.click only clicks the first occurrence of the specific selector. That is why I used createXPathFromElement taken from stijn de ryck to find the unique XPath expression for every element inside the page context.

You can then click the correct element via the unique XPath like this

casper.click(x(xpathFromPageContext[i]));

2. Cancelling navigation

This may depend on what your page actually is.

Note: I use the casper.test property which is the Tester module. You get access to it by invoking casper like this: casperjs test script.js.

Note: There is also the casper.waitForResource function. Have a look at it.

2.1 Web 1.0

When a click means a new page will be loaded, you may add an event handler to the page.resource.requested event. You can then abort() the request without resetting the page back to the startURL.

var resourceAborted = false;
casper.on('page.resource.requested', function(requestData, request){
    if (requestData.url.match(/someURLMatching/)) {
        // you can also check requestData.headers which is an array of objects:
        // [{name: "header name", value: "some value"}]
        casper.test.pass("resource passed");
    } else {
        casper.test.fail("resource failed");
    }
    if (requestData.url != startURL) {
        request.abort();
    }
    resourceAborted = true;
});

and in the test flow:

casper.each(links, function(self, link){
    self.thenClick(x(link));
    self.waitFor(function check(){
        return resourceAborted;
    });
    self.then(function(){
        resourceAborted = false; // reset state
    });
});

2.2 Single page application

There may be so many event handlers attached, that it is quite hard to prevent them all. An easier way (at least for me) is to

  1. get all the unique element paths,
  2. iterate over the list and do every time the following:
    1. Open the original page again (basically a reset for every link)
    2. do the click on the current XPath

This is basically what I do in this answer.

Since single page apps don't load pages. The navigation.requested and page.resource.requested will not be triggered. You need the resource.requested event if you want to check some API call:

var clickPassed = -1;
casper.on('resource.requested', function(requestData, request){
    if (requestData.url.match(/someURLMatching/)) {
        // you can also check requestData.headers which is an array of objects:
        // [{name: "header name", value: "some value"}]
        clickPassed = true;
    } else {
        clickPassed = false;
    }
});

and in the test flow:

casper.each(links, function(self, link){
    self.thenOpen(startURL);
    self.thenClick(x(link));
    self.waitFor(function check(){
        return clickPassed !== -1;
    }, function then(){
        casper.test.assert(clickPassed);
        clickPassed = -1;
    }, function onTimeout(){
        casper.test.fail("Resource timeout");
    });
});
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!