There should be a base testing class for testing webrid grids. We use the following in one of our projects:
import re
import urllib.parse
from blazeutils.spreadsheets import workbook_to_reader
import flask
import flask_login
from pyquery import PyQuery
import pytest
import sqlalchemy
def query_to_str(statement, bind=None):
"""This function is copied directly from sqlalchemybwc.lib.testing
returns a string of a sqlalchemy.orm.Query with parameters bound
WARNING: this is dangerous and ONLY for testing, executing the results
of this function can result in an SQL Injection attack.
"""
if isinstance(statement, sqlalchemy.orm.Query):
if bind is None:
bind = statement.session.get_bind()
statement = statement.statement
elif bind is None:
bind = statement.bind
if bind is None:
raise Exception('bind param (engine or connection object) required when using with an '
'unbound statement')
dialect = bind.dialect
compiler = statement._compiler(dialect)
class LiteralCompiler(compiler.__class__):
def visit_bindparam(
self, bindparam, within_columns_clause=False,
literal_binds=False, **kwargs
):
return super(LiteralCompiler, self).render_literal_bindparam(
bindparam, within_columns_clause=within_columns_clause,
literal_binds=literal_binds, **kwargs
)
compiler = LiteralCompiler(dialect, statement)
return 'TESTING ONLY BIND: ' + compiler.process(statement)
class GridBase(object):
grid_cls = None
filters = ()
sort_tests = ()
@classmethod
def setup_class(cls):
cls.user = User.testing_create()
if hasattr(cls, 'init'):
cls.init()
def assert_in_query(self, look_for, **kwargs):
pg = self.get_session_grid(**kwargs)
query_str = query_to_str(pg.build_query())
assert look_for in query_str, '"{0}" not found in: {1}'.format(look_for, query_str)
def assert_not_in_query(self, look_for, **kwargs):
pg = self.get_session_grid(**kwargs)
query_str = query_to_str(pg.build_query())
assert look_for not in query_str, '"{0}" found in: {1}'.format(look_for, query_str)
def assert_regex_in_query(self, look_for, **kwargs):
pg = self.get_session_grid(**kwargs)
query_str = query_to_str(pg.build_query())
if hasattr(look_for, 'search'):
assert look_for.search(query_str), \
'"{0}" not found in: {1}'.format(look_for.pattern, query_str)
else:
assert re.search(look_for, query_str), \
'"{0}" not found in: {1}'.format(look_for, query_str)
def get_session_grid(self, *args, **kwargs):
flask_login.login_user(kwargs.pop('user', self.user), force=True)
g = self.grid_cls(*args, **kwargs)
g.apply_qs_args()
return g
def get_pyq(self, grid=None, **kwargs):
pg = grid or self.get_session_grid(**kwargs)
html = pg.html()
return PyQuery('<html>{0}</html>'.format(html))
def get_sheet(self, grid=None, **kwargs):
pg = grid or self.get_session_grid(**kwargs)
xls = pg.xls()
return workbook_to_reader(xls).sheet_by_index(0)
def check_filter(self, name, op, value, expected):
qs_args = [('op({0})'.format(name), op)]
if isinstance(value, (list, tuple)):
for v in value:
qs_args.append(('v1({0})'.format(name), v))
else:
qs_args.append(('v1({0})'.format(name), value))
def sub_func(ex):
url = '/?' + urllib.parse.urlencode(qs_args)
with flask.current_app.test_request_context(url):
if isinstance(ex, re.compile('').__class__):
self.assert_regex_in_query(ex)
else:
self.assert_in_query(ex)
self.get_pyq() # ensures the query executes and the grid renders without error
def page_func():
url = '/?' + urllib.parse.urlencode([('onpage', 2), ('perpage', 1), *qs_args])
with flask.current_app.test_request_context(url):
pg = self.get_session_grid()
if pg.page_count > 1:
self.get_pyq()
if self.grid_cls.pager_on:
page_func()
return sub_func(expected)
def test_filters(self):
if callable(self.filters):
cases = self.filters()
else:
cases = self.filters
for name, op, value, expected in cases:
self.check_filter(name, op, value, expected)
def check_sort(self, k, ex, asc):
if not asc:
k = '-' + k
d = {'sort1': k}
def sub_func():
with flask.current_app.test_request_context('/?' + urllib.parse.urlencode(d)):
self.assert_in_query('ORDER BY %s%s' % (ex, '' if asc else ' DESC'))
self.get_pyq() # ensures the query executes and the grid renders without error
def page_func():
url = '/?' + urllib.parse.urlencode({'sort1': k, 'onpage': 2, 'perpage': 1})
with flask.current_app.test_request_context(url):
pg = self.get_session_grid()
if pg.page_count > 1:
self.get_pyq()
if self.grid_cls.pager_on:
page_func()
return sub_func()
@pytest.mark.parametrize('asc', [True, False])
def test_sort(self, asc):
for col, expect in self.sort_tests:
self.check_sort(col, expect, asc)
def assert_table(self, table, grid=None, **kwargs):
d = self.get_pyq(grid, **kwargs)
assert len(d.find('table.records thead th')) == len(table[0])
for idx, val in enumerate(table[0]):
assert d.find('table.records thead th').eq(idx).text() == val
assert len(d.find('table.records tbody tr')) == len(table[1:])
for row_idx, row in enumerate(table[1:]):
len(d.find('table.records tbody tr').eq(row_idx)('td')) == len(row)
for col_idx, val in enumerate(row):
read = d.find('table.records tbody tr').eq(row_idx)('td').eq(col_idx).text()
assert read == val, 'row {} col {} {} != {}'.format(row_idx, col_idx, read, val)
def expect_table_contents(self, expect, grid=None, **kwargs):
d = self.get_pyq(grid, **kwargs)
assert len(d.find('table.records tbody tr')) == len(expect)
for row_idx, row in enumerate(expect):
td = d.find('table.records tbody tr').eq(row_idx).find('td')
assert len(td) == len(row)
for col_idx, val in enumerate(row):
assert td.eq(col_idx).text() == val