1

I'm starting writing tests for my Pyramid views (using webtest), and coming from a Django background I'm having an hard time trying to understand how to test that certain variables have been passed to the template. For example let's consider this view:

@view_config(route_name='login_or_signup', renderer='login_or_signup.html')
def login_or_sign_up(request):
    if request.method == 'POST':
        try:
            do_business_logic()
            return HTTPFound(location=next)
        except Invalid as e:
            request.response.status_code = 400
            return dict(form_errors=e.asdict())
    return {}

How can I write a test that proves that if the form is incorrect, a form_errors dictionary is passed to the template? In Django I would use the context attribute, but in Pyramid/webtest I can't find nothing similar... It seems that template's data is not accessible via the response object. The only thing I found in order to access this data is via event listeners:

@subscriber(BeforeRender)
def print_template_context(event):
    for k, v in event.rendering_val.items():
        print(k, v)

But I think that is not feasible to use such approach, since:

  1. it's a global listener
  2. it has no access to the response object

So... I tried to extend the base Response class (in order to attach extra fields to it):

class TemplateResponse(Response):
    def __init__(self, template, template_context=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.template = template
        self.template_context = template_context or {}
        self.text = render(self.template, self.template_context, self.request)

and change the original view to:

   @view_config(route_name='login_or_signup')
    def login_or_sign_up(request):
        if request.method == 'POST':
            try:
                do_buisness_logic()
                return HTTPFound(location=next)
            except Invalid as e:
                return TemplateResponse(
                    'login_or_signup.html', 
                    dict(form_errors=e.asdict()), 
                    status=400
            )
        return TemplateResponse('login_or_signup.html')

But it's helpless, since webtest returns its own TestResponse object instead of my TemplateResponse... so how can I test data in templates?

daveoncode
  • 18,900
  • 15
  • 104
  • 159

1 Answers1

0

Despite I'm not totally satisfied, I currently solved using both webtest and default Pyramid test utils:

template_request = DummyRequest(path='/login-signup', post=data)
template_context = LoginSignupView(template_request).post()
response = self.app.post('/login-signup', data, status=HTTPBadRequest.code)
self.assertEqual(response.status_code, HTTPBadRequest.code)
self.assertIsInstance(template_context['form_errors'], dict)

the DummyRequest is passed directly to the View, which simply returns a dictionary containing template variables. Instead the actual "navigation" is delegated to the TestApp instance which is able to get back the actual html response that has been rendered.

daveoncode
  • 18,900
  • 15
  • 104
  • 159