Ошибка jQuery с использованием PhantomJS
В настоящее время я работаю над сценариями автоматизированного тестирования, для которых требуется браузер без головы (PhantomJS) и все возможные навигация и действия DOM (кроме загрузок). Так что PhantomJS должен соответствовать.
Однако я не могу использовать PhantomJS с javascript jQuery как следующие ошибки:
var page = require('webpage').create();
page.open('http://mywebsite.com/', function() {
function dothat() {
console.log('0 started');
$('#id').children().eq(0).click();
console.log('0 finished');
return main(1, 0);
}
}
dothat()
Здесь сценарии останавливают "0 запущено". Страница, которую я загружаю, использует jQuery, поэтому мне не нужно загружать ее обратно. Тем не менее, давайте попробуем с загрузкой.
var page = require('webpage').create();
page.open('http://mywebsite.com/', function() {
page.injectJs('jquery-2.2.1.min.js');
function dothat() {
console.log('0 started');
$('#id').children().eq(0).click();
console.log('0 finished');
return main(1, 0);
}
}
dothat()
Да, у меня есть файл локально в том же каталоге... И это показывает, что ошибка (очень быстро):
TypeError: undefined is not a constructor (evaluating 'jQuery.easing[jQuery.easing.def](t,e,n,i,a)')
Что вы предлагаете сделать, чтобы это исправить? Это внутренняя ошибка в PhantomJS, и поэтому я должен попробовать Firefox и Xvfb в Ubuntu, или это моя ошибка где-то? Сначала я хочу поменять код на полную версию, отличную от jQuery, но мне нужны отличные селекторы с классами и щелкнуть некоторые объекты...
Большое спасибо за указание мне решение!
РЕДАКТИРОВАТЬ 1: Я изменил это в соответствии с тем, что я понял из первого ответа. Теперь консоль ничего не печатает
var page = require('webpage').create();
page.onConsoleMessage = function(msg, lineNum, sourceId) {
console.log('CONSOLE: ' + msg + ' (from line #' + lineNum + ' in "' + sourceId + '")');
};
page.open('http://mywebsite.com/', function() {
page.injectJs('jquery-2.2.1.min.js');
var result = page.evaluate(function() {
function dothat() {
console.log('0 started');
$('#id').children().eq(0).click();
console.log('0 finished');
return main(1, 0);
}
function main(x, y) {
if (x === 0) {
return setTimeout(dothat(), y);
} else if (x === 1) {
return setTimeout(dothis(), y);
}
}
return main(0, 5000); //first launch
}
});
Я не уверен, что это было то, что вы указали, хотя.
РЕДАКТИРОВАТЬ 2: Это настоящий скрипт, который хочет зайти на google.com и войти как я. Однако скрипт не работает должным образом, см. Ниже.
var page = require('webpage').create();
page.onConsoleMessage = function(msg) {
console.log('CONSOLE: ' + msg);
};
page.open('https://google.com/', function() {
page.injectJs('jquery-2.2.1.min.js');
page.evaluate(function() {
function dofirst() {
$('#gb_70').click();
return main(1, 0);
}
function dosecond() {
document.getElementById('Email').value = 'myemail@gmail.com';
$('#next').click();
return main(2, 0);
}
function dothird() {
document.getElementById('Passwd').value = 'mypwd';
$('#signIn').click();
}
function main(i, j) {
if (i === 0) {
console.log('launching 0');
return setTimeout(dofirst(), j); // connections
}
else if (i === 1) {
console.log('launching 1');
return setTimeout(dosecond(), 5000);
}
else if (i === 2) {
console.log('launching 2');
return setTimeout(dothird(), 5000);
}
}
return main(0, 5000);
});
});
Как видите, main - это функция, которую я использую для задержки шагов. Однако код не работает и возвращает мне эту ошибку (или те):
TypeError: null is not an object (evaluating 'document.getElementById('Email').value = 'myemail@gmail.com'')
undefined:7 in dosecond
:22 in main
:4 in dofirst
:18 in main
:29
:30
Спасибо, что продолжаете пытаться помочь мне!
2 ответа
В PhantomJS всегда есть два контекста javascirpt, где существуют функции и переменные:
- PhantomJS контекст
- Контекст открытой страницы
Они не знают друг друга и не пересекаются!
PhantomJS не может получить доступ ни к целевым объектам страницы, ни к DOM, поэтому $('#id').children().eq(0).click();
не будет работать - в скрипте PhantomJS нет jQuery, нет элементов DOM. Они находятся во втором контексте, или, другими словами, sandbox
,
Чтобы сделать что-нибудь со страницей, вы должны отсортировать код телепортации. Это делается с помощью метода page.evaluate().
var page = require('webpage').create();
page.open('http://mywebsite.com/', function() {
page.injectJs('jquery-2.2.1.min.js');
var result = page.evaluate(function(){
// You can certainly use functions
// Be sure to declare them also
// inside of page.evaluate
function dothat() {
console.log('0 started');
$('#id').children().eq(0).click();
console.log('0 finished');
return main(1, 0);
}
// Important: don't forget to return result
// back to PhantomJS main context
return dothat();
});
});
Обратите внимание, что для получения консольных сообщений из изолированного контекста страницы вы должны подписаться на них с помощью обратного вызова page.onConsoleMessage:
page.onConsoleMessage = function(msg, lineNum, sourceId) {
console.log('CONSOLE: ' + msg + ' (from line #' + lineNum + ' in "' + sourceId + '")');
};
После РЕДАКТИРОВАТЬ 1: Моя ошибка, я потерял скобку, редактируя ваш пример (исправленный выше), что привело к синтаксической ошибке, факту, что PhantomJS v2.x не будет жаловаться, он просто будет молча зависать. Это то, что вы приняли за отсутствие консольных сообщений. Может быть полезно сначала проверить скрипт на наличие синтаксических ошибок в v1.9.8 или в некоторых IDE с подсветкой синтаксиса.
Ваш текущий код должен выглядеть следующим образом (отсутствующая скобка также исправлена):
var page = require('webpage').create();
page.onConsoleMessage = function(msg, lineNum, sourceId) {
console.log('CONSOLE: ' + msg + ' (from line #' + lineNum + ' in "' + sourceId + '")');
};
page.open('http://mywebsite.com/', function() {
page.injectJs('jquery-2.2.1.min.js');
var result = page.evaluate(function() {
function dothat() {
console.log('0 started');
$('#id').children().eq(0).click();
console.log('0 finished');
return main(1, 0);
}
function main(x, y) {
if (x === 0) {
return setTimeout(dothat(), y);
} else if (x === 1) {
return setTimeout(dothis(), y);
}
}
return main(0, 5000); //first launch
}); //
});
Примечание: будет жаловаться на несуществующую функцию dothis().
Разве вы не хотите сделать это наоборот?
function dothat() {
console.log('0 started');
$('#id').children().eq(0).click();
console.log('0 finished');
return main(1, 0);
}
var page = require('webpage').create();
page.open('http://mywebsite.com/', dothat)