[IMP] phantomjs testing add an easy phantom_js helper

self.phantom_js(<page_to_load>, <code_to_run>, <global_object_to_wait>, **options)

example:

self.phantom_js("/", "openerp.module.mytest()", "openerp.module.mytest");

console.log('ok') or console.log('error') should be used to signal success or
failure. Other console.log's will be passed to the test logger.

bzr revid: al@openerp.com-20140210004517-jc2cobc31qshxchm
This commit is contained in:
Antony Lesuisse 2014-02-10 01:45:17 +01:00
parent 8f29812b0f
commit 1f78dfb76d
4 changed files with 107 additions and 77 deletions

View File

@ -1,14 +1,13 @@
# -*- coding: utf-8 -*-
import os
import glob
import openerp
fname, _ = os.path.splitext(__file__)
class TestUi(openerp.tests.HttpCase):
def test(self):
for i in glob.glob('%s*.js' % fname):
self.phantomjs(i)
def test_js(self):
self.phantom_js('/',"console.log('ok')","console", login=None)
def test_jsfile(self):
self.phantom_jsfile(os.path.join(os.path.dirname(__file__), 'test_ui_hello.js'))
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,6 +0,0 @@
// Load helper
phantom.injectJs(phantom.args[0]);
pt = new PhantomTest();
pt.run("/", "console.log('ok')", "console");

View File

@ -112,7 +112,7 @@ class SingleTransactionCase(BaseCase):
cls.cr.close()
class HttpCase(SingleTransactionCase):
class HttpCase(TransactionCase):
""" Transactionnal HTTP TestCase with a phantomjs helper.
"""
@ -124,18 +124,16 @@ class HttpCase(SingleTransactionCase):
self.xmlrpc_db = xmlrpclib.ServerProxy(url_8 + 'db')
self.xmlrpc_object = xmlrpclib.ServerProxy(url_8 + 'object')
@classmethod
def setUpClass(cls):
super(HttpCase, cls).setUpClass()
cls.session_id = uuid.uuid4().hex
HTTP_SESSION[cls.session_id] = cls.cr
def setUp(self):
super(HttpCase, self).setUp()
self.session_id = uuid.uuid4().hex
HTTP_SESSION[self.session_id] = self.cr
@classmethod
def tearDownClass(cls):
del HTTP_SESSION[cls.session_id]
super(HttpCase, cls).tearDownClass()
def tearDown(self):
del HTTP_SESSION[self.session_id]
super(HttpCase, self).tearDown()
def phantomjs(self, jsfile, timeout=30, options=None):
def phantom_poll(self, phantom, timeout):
""" Phantomjs Test protocol.
Use console.log in phantomjs to output test results:
@ -146,8 +144,77 @@ class HttpCase(SingleTransactionCase):
Other lines are relayed to the test log.
"""
self.timeout = timeout
self.options = {
t0 = time.time()
buf = ''
while 1:
# timeout
if time.time() > t0 + timeout:
raise Exception("phantomjs test timeout (%ss)" % timeout)
# read a byte
ready, _, _ = select.select([phantom.stdout], [], [], 0.5)
if ready:
s = phantom.stdout.read(1)
if s:
buf += s
else:
break
# process lines
if '\n' in buf:
line, buf = buf.split('\n', 1)
_logger.info("phantomjs: %s", line)
if line == "ok":
_logger.info("phantomjs test successful")
return
if line == "error":
raise Exception("phantomjs test failed")
def phantom_run(self, cmd, timeout):
_logger.info('executing %s', cmd)
try:
phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
_logger.info("phantomjs not found, test %s skipped", jsfile)
try:
self.phantom_poll(phantom, timeout)
finally:
# kill phantomjs if phantom.exit() wasn't called in the test
if phantom.poll() is None:
phantom.terminate()
def phantom_jsfile(self, jsfile, timeout=30, **kw):
options = {
'timeout' : timeout,
'port': PORT,
'db': DB,
'session_id': self.session_id,
}
options.update(kw)
phantomtest = os.path.join(os.path.dirname(__file__), 'phantomtest.js')
# phantom.args[0] == phantomtest path
# phantom.args[1] == options
cmd = ['phantomjs', jsfile, phantomtest, json.dumps(options)]
self.phantom_run(cmd, timeout)
def phantom_js(self, url_path, code, ready="window", timeout=30, **kw):
""" Test js code running in the browser
- load page given by url_path
- wait for ready object to be available
- eval(code) inside the page
To signal success test do:
console.log('ok')
To signal failure do:
console.log('error')
If neither are done before timeout test fails.
"""
options = {
'url_path': url_path,
'code': code,
'ready': ready,
'timeout' : timeout,
'port': PORT,
'db': DB,
@ -155,49 +222,10 @@ class HttpCase(SingleTransactionCase):
'password': ADMIN_PASSWORD,
'session_id': self.session_id,
}
if options:
self.options.update(options)
options.update(kw)
phantomtest = os.path.join(os.path.dirname(__file__), 'phantomtest.js')
# phantom.args[0] == phantomtest path
# phantom.args[1] == options
cmd = ['phantomjs', jsfile, phantomtest, json.dumps(self.options)]
_logger.info('executing %s', cmd)
try:
phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
_logger.info("phantomjs not found, test %s skipped", jsfile)
try:
t0 = time.time()
buf = ''
while 1:
# timeout
if time.time() > t0 + self.timeout:
raise Exception("phantomjs test timeout (%ss)" % self.timeout)
# read a byte
ready, _, _ = select.select([phantom.stdout], [], [], 0.5)
if ready:
s = phantom.stdout.read(1)
if s:
buf += s
else:
break
# process lines
if '\n' in buf:
line, buf = buf.split('\n', 1)
_logger.info("phantomjs: %s", line)
if line == "ok":
_logger.info("phantomjs test successful")
return
if line == "error":
raise Exception("phantomjs test failed")
finally:
# kill phantomjs if phantom.exit() wasn't called in the test
if phantom.poll() is None:
phantom.terminate()
cmd = ['phantomjs', phantomtest, json.dumps(options)]
self.phantom_run(cmd, timeout)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -24,7 +24,11 @@ function waitFor (ready, callback, timeout, timeoutMessageCallback) {
function PhantomTest() {
var self = this;
this.options = JSON.parse(phantom.args[1]);
if(phantom.args.length === 1) {
this.options = JSON.parse(phantom.args[0]);
} else {
this.options = JSON.parse(phantom.args[1]);
}
this.inject = [];
this.timeout = this.options.timeout ? Math.round(parseFloat(this.options.timeout)*1000 - 5000) : 10000;
this.origin = 'http://localhost';
@ -80,6 +84,14 @@ function PhantomTest() {
// run test
// ----------------------------------------------------
this.run = function(url_path, code, ready) {
if(self.options.login) {
qp = [];
qp.push('db=' + self.options.db);
qp.push('login=' + self.options.login);
qp.push('key=' + self.options.password);
qp.push('redirect=' + encodeURIComponent(url_path));
var url_path = "/web/login?" + qp.join('&');
}
var url = self.origin + url_path;
self.page.open(url, function(status) {
if (status !== 'success') {
@ -104,15 +116,12 @@ function PhantomTest() {
}
});
};
this.run_admin = function(url_path, code, ready) {
qp = [];
qp.push('db=' + self.options.db);
qp.push('login=' + self.options.login);
qp.push('key=' + self.options.password);
qp.push('redirect=' + encodeURIComponent(url_path));
var url_path2 = "/web/login?" + qp.join('&');
return self.run(url_path2, code, ready);
};
}
// js mode or jsfile mode
if(phantom.args.length === 1) {
pt = new PhantomTest();
pt.run(pt.options.url_path, pt.options.code, pt.options.ready);
}
// vim:et: