2016-06-08 1 views
1

나는 Checking JavaScript AJAX loaded resources with Mink/Zombie in PHP?과 같은 예를 사용하고 있습니다 :AJAX를 검사하여 CasperJS로 JS 객체/클래스를로드 했습니까?

test_JSload.php 다음

<?php 
if (array_key_exists("QUERY_STRING", $_SERVER)) { 
    if ($_SERVER["QUERY_STRING"] == "getone") { 
    echo "<!doctype html> 
    <html> 
    <head> 
    <script src='test_JSload.php?gettwo'></script> 
    </head> 
    </html> 
    "; 
    exit; 
    } 

    if ($_SERVER["QUERY_STRING"] == "gettwo") { 
    header('Content-Type: application/javascript'); 
    echo " 
    function person(firstName) { 
    this.firstName = firstName; 
    this.changeName = function (name) { 
     this.firstName = name; 
    }; 
    } 
    "; 
    exit; 
    } 
} 
?> 
<html> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 
    <style type="text/css"> 
.my_btn { background-color:yellow; } 
    </style> 
    <script src="http://code.jquery.com/jquery-1.12.4.min.js"></script> 
    <script type="text/javascript"> 
var thishref = window.location.href.slice(0, window.location.href.indexOf('?')+1); 
var qstr = window.location.href.slice(window.location.href.indexOf('?')+1); 

function OnGetdata(inbtn) { 
    console.log("OnGetdata; loading ?getone via AJAX call"); 
    //~ $.ajax(thishref + "?getone", { // works 
    var ptest = {}; // init as empty object 
    console.log(" ptest pre ajax is ", ptest); 

    $.ajax({url: thishref + "?getone", 
    async: true, // still "Synchronous XMLHttpRequest on the main thread is deprecated", because we load a script; https://stackoverflow.com/q/24639335 
    success: function(data) { 
     console.log("got getone data "); //, data); 
     $("#dataholder").html(data); 
     ptest = new person("AHA"); 
     console.log(" ptest post getone is ", ptest); 
    }, 
    error: function(xhr, ajaxOptions, thrownError) { 
     console.log("getone error " + thishref + " : " + xhr.status + "/" + thrownError); 
    } 
    }); 

    ptest.changeName("Somename"); 
    console.log(" ptest post ajax is ", ptest); 
} 

ondocready = function() { 
    $("#getdatabtn").click(function(){ 
    OnGetdata(this); 
    }); 
} 
$(document).ready(ondocready); 
    </script> 
</head> 


<body> 
    <h1>Hello World!</h1> 

    <button type="button" id="getdatabtn" class="my_btn">Get Data!</button> 
    <div id="dataholder"></div> 
</body> 
</html> 

, 당신은 단지 PHP> 5.4 CLI (명령 행)와 임시 서버를 실행할 수 있습니다, 같은 디렉토리에 합니다 (.php 파일의) : 마지막으로 다음

php -S localhost:8080 

... 그리고, 당신은 http://127.0.0.1:8080/test_JSload.php에 페이지를 방문 할 수 있습니다.

간단히 말해서이 페이지에서 버튼을 클릭하면 자바 스크립트 클래스가 두 번의 패스로로드됩니다. 먼저 HTML에 <script> 태그가 붙어 있으며이 스크립트의 스크립트는 두 번째 패스에로드됩니다. 파이어 폭스 콘솔에서이 작업 인쇄를 위해 :

OnGetdata; loading ?getone via AJAX call  test_JSload.php:13:3 
ptest pre ajax is Object { }    test_JSload.php:16:3 
TypeError: ptest.changeName is not a function test_JSload.php:31:3 
got getone data        test_JSload.php:21:7 
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help http://xhr.spec.whatwg.org/ jquery-1.12.4.min.js:4:26272 
ptest post getone is Object { firstName: "AHA", changeName: person/this.changeName(name) } test_JSload.php:24:7 

나는 궁극적으로 ptest 변수 또는 CasperJS에서 person 클래스 중 하나를 검사하고 싶습니다. 나는이 스크립트를 CasperJS 실행할 때

test_JSload_casper.js

// run with: 
// ~/.nvm/versions/node/v4.0.0/lib/node_modules/casperjs/bin/casperjs test_JSload_casper.js 
// based on http://code-epicenter.com/how-to-login-to-amazon-using-casperjs-working-example/ 

var casper = require('casper').create({ 
    pageSettings: { 
    loadImages: false,//The script is much faster when this field is set to false 
    loadPlugins: false, 
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36' 
    } 
}); 

//First step is to open page 
casper.start().thenOpen("http://127.0.0.1:8080/test_JSload.php", function() { 
    console.log("website opened"); 
}); 

//Second step is to click to the button 
casper.then(function(){ 
    this.evaluate(function(){ 
    document.getElementById("getdatabtn").click(); 
    }); 
}); 

//Wait for JS to execute?!, then inspect 
casper.then(function(){ 
    console.log("After login..."); 
    console.log("AA " + JSON.stringify(person)); 
}); 

casper.run(); 
이 가 이

이 ... 그러나, 난 그냥 얻을 :

$ ~/.nvm/versions/node/v4.0.0/lib/node_modules/casperjs/bin/casperjs test_JSload_casper.js 
website opened 
After login... 

... 아무것도 지금까지,이 스크립트를 만든 그밖에. 마지막 줄인 console.log("AA " + JSON.stringify(person));은 부분적으로 실행되지 않습니다 (즉, "AA"가 인쇄되지 않으며 오류 메시지가 표시되지 않음).

따라서 Casper JS를 사용하여 이러한 리소스 (AJAX로드 된 JS 개체/클래스, 복수 실행/단계로드 가능)를 검사 할 수 있습니까? 그렇다면 어떻게해야합니까?

답변

1

클릭을 통해 트리거되는 Ajax 요청에는 사용자가 고칠 페이지에 영향을 줄 충분한 시간이 없을 수 있습니다. 많은 wait* 기능 중 하나를 사용하여 완료 될 때까지 기다려야합니다. Ajax 요청의 결과로 DOM이 변경된 경우 waitForSelector을 제안합니다.

관련된 문제는 페이지의 JavaScript가 깨졌습니다. ptest을 채우는 Ajax 요청은 비동기이기 때문에 응답이 도착하기 전에 ptest.changeName("Somename")이 실행되어 TypeError가 발생합니다. ptest.changeName(...)을 Ajax 요청의 콜백 success으로 이동할 수 있습니다. 페이지에서 콘솔 메시지를 참조하기 위해

, 당신은 'remote.message' event을 듣고있다 : 적어도 나는 person 클래스를 인쇄 관리로

casper.on("remote.message", function(msg){ 
    this.echo("remote> " + msg); 
}); 

casper.start(...)... 
+0

많은 감사합니다 @ArtjomB. -이 이벤트 메시지 수신기를 여러 개 추가하고 실행에 대한 자세한 로그를 가져 왔습니다 (게시 된 답변 참조). 궁극적으로, 나는 또한 "질문"인 "person"클래스를 보여줄 수 있었지만,'casperjs'가 해당 리소스가로드되었다고보고하지 않는다면 여전히 가능한 방법에 대해 당황 스럽다. 또한,보고되지 않은 치명적인 오류가 발생하고있는 것 같습니다. – sdbbs

0

가 나는 부분적인 대답으로이 게재됩니다 - 그 트릭은 casper.evaluate을 사용하여 원격 페이지에서와 같이 스크립트 (예 : console.log(person))를 실행하는 것입니다 (아래 참조).그러나, 거기에 여전히 나에게 분명 문제 (그리고 나는 기꺼이 것을 명확히 답 받아 들일 겁니다) :

  • person 클래스에만 ?gettwo 요청이 완료된 후 기존 될 해당 JS가 검색되었습니다한다을 ; 그러나 casperjs?getone에 대한 호출 만 수행했으며 ?gettwo ??은보고하지 않았습니다. 왜?
  • .then(...JSON.stringify(person) 또는 __utils__.echo('plop');을 사용하려고하면 치명적인 오류가있는 것처럼 스크립트 실행이 중단됩니다. 그러나 여러 메시지를 듣더라도 관련된 오류는보고되지 않습니다. 왜?

    // run with: 
    // ~/.nvm/versions/node/v4.0.0/lib/node_modules/casperjs/bin/casperjs test_JSload_casper.js 
    
    var casper = require('casper').create({ 
        verbose: true, 
        logLevel: 'debug', 
        userAgent: 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36', 
        pageSettings: { 
        loadImages: false,//The script is much faster when this field is set to false 
        loadPlugins: false 
        } 
    }); 
    
    
    casper.on('remote.message', function(message) { 
        this.echo('remote message caught: ' + message); 
    }); 
    
    casper.on('resource.received', function(resource) { 
        var status = resource.status; 
        casper.log('Resource received ' + resource.url + ' (' + status + ')'); 
    }); 
    
    casper.on("resource.error", function(resourceError) { 
        this.echo("Resource error: " + "Error code: "+resourceError.errorCode+" ErrorString: "+resourceError.errorString+" url: "+resourceError.url+" id: "+resourceError.id, "ERROR"); 
    }); 
    
    casper.on("page.error", function(msg, trace) { 
        this.echo("Page Error: " + msg, "ERROR"); 
    }); 
    
    // http://docs.casperjs.org/en/latest/events-filters.html#page-initialized 
    casper.on("page.initialized", function(page) { 
        // CasperJS doesn't provide `onResourceTimeout`, so it must be set through 
        // the PhantomJS means. This is only possible when the page is initialized 
        page.onResourceTimeout = function(request) { 
        console.log('Response Timeout (#' + request.id + '): ' + JSON.stringify(request)); 
        }; 
    }); 
    
    
    //Second step is to click to the button 
    casper.then(function(){ 
        this.evaluate(function(){ 
        document.getElementById("getdatabtn").click(); 
        }); 
        //~ this.wait(2000, function() { // fires, but ?gettwo never gets listed 
        //~ console.log("Done waiting"); 
        //~ }); 
    
        //~ this.waitForResource(/\?gettwo$/, function() { // does not ever fire: "Wait timeout of 5000ms expired, exiting." 
        //~ this.echo('a gettwo has been loaded.'); 
        //~ }); 
    }); 
    
    //Wait for JS to execute?!, then inspect 
    casper.then(function(){ 
        console.log("After login..."); 
    
        // Code inside of this function will run 
        // as if it was placed inside the target page. 
        casper.evaluate(function(term) { 
        //~ console.log("EEE", ptest); // Page Error: ReferenceError: Can't find variable: ptest 
        console.log("EEE", person); // does dump the class function 
        }); 
    
        __utils__.echo('plop'); // script BREAKS here.... 
        console.log("BB "); 
        console.log("AA " + JSON.stringify(person)); 
    }); 
    
    casper.run(); 
    

    이의 출력은 다음과 같습니다 :

    그것이 "EEE"메시지에서 볼 수 있듯이
    $ ~/.nvm/versions/node/v4.0.0/lib/node_modules/casperjs/bin/casperjs test_php_mink/test_JSload_casper.js 
    [info] [phantom] Starting... 
    [info] [phantom] Running suite: 4 steps 
    [debug] [phantom] opening url: http://127.0.0.1:8080/test_JSload.php, HTTP GET 
    [debug] [phantom] Navigation requested: url=http://127.0.0.1:8080/test_JSload.php, type=Other, willNavigate=true, isMainFrame=true 
    [debug] [phantom] Resource received http://127.0.0.1:8080/test_JSload.php (200) 
    [debug] [phantom] url changed to "http://127.0.0.1:8080/test_JSload.php" 
    [debug] [phantom] Resource received http://127.0.0.1:8080/test_JSload.php (200) 
    [debug] [phantom] Resource received http://code.jquery.com/jquery-1.12.4.min.js (200) 
    [debug] [phantom] Resource received http://code.jquery.com/jquery-1.12.4.min.js (200) 
    [debug] [phantom] Successfully injected Casper client-side utilities 
    [info] [phantom] Step anonymous 2/4 http://127.0.0.1:8080/test_JSload.php (HTTP 200) 
    website opened 
    [info] [phantom] Step anonymous 2/4: done in 312ms. 
    [info] [phantom] Step anonymous 3/4 http://127.0.0.1:8080/test_JSload.php (HTTP 200) 
    remote message caught: OnGetdata; loading ?getone via AJAX call 
    remote message caught: ptest pre ajax is [object Object] 
    Page Error: TypeError: undefined is not a function (evaluating 'ptest.changeName("Somename")') 
    [info] [phantom] Step anonymous 3/4: done in 337ms. 
    [debug] [phantom] Resource received http://127.0.0.1:8080/test_JSload.php?getone (200) 
    [debug] [phantom] Resource received http://127.0.0.1:8080/test_JSload.php?getone (200) 
    remote message caught: got getone data 
    remote message caught: ptest post getone is [object Object] 
    [info] [phantom] Step anonymous 4/4 http://127.0.0.1:8080/test_JSload.php (HTTP 200) 
    After login... 
    remote message caught: EEE function person(firstName) { 
        this.firstName = firstName; 
        this.changeName = function (name) { 
         this.firstName = name; 
        }; 
        } 
    [debug] [phantom] Navigation requested: url=about:blank, type=Other, willNavigate=true, isMainFrame=true 
    [debug] [phantom] url changed to "about:blank" 
    

    person 클래스

그렇지 않으면, 여기에 수정 test_JSload_casper.js 파일입니다 (함수를 정의한) http://127.0.0.1:8080/test_JSload.php?gettwo이로드 된 리소스로 표시되지 않더라도 올바르게보고됩니다.

+1

아마도 PhantomJS 2.x에서 리소스가보고되지 않는 것 같습니다. 어쨌든'__utils__'는'evaluate()'안에서만 사용할 수 있기 때문에 결국 스크립트가 중단됩니다. –

+0

많은 감사, @ArtjomB. - 그게 많이 설명해. Btw, 거기에'__utils __. echo()'가 없으면'JSON.stringify (person)'줄이 스크립트를 해독합니다. 왜 그런지 알고 있습니까? 이러한 오류가 발생할 경우 자세한 오류를 얻을 수 있습니까? – sdbbs

+1

'person'은 함수이므로 문자열화할 수 없습니다. 나는 내 대답을 약간 확장했기 때문에 이것이 왜'gettwo'가 호출되지 않는지에 대한 아이디어를 줄 것입니다. 로그를 다시보고 페이지 오류를 확인하십시오. –