Checking flash messages in flask application nose tests
Asked Answered
P

3

6

On different input values posted to a url of my flask application, it flashes different messages, e.g. 'no data entered', 'invalid input', 'no record found', '3 records found'.

Can someone guide how can I write a nose test to check if the proper flash message is displayed? I guess the flash messages first goto the session ... how can we check session variables in nose-tests?

Thanks

Peppard answered 8/4, 2015 at 7:34 Comment(0)
N
6

The method of testing flashes with session['_flashes'] didn't work for me, because session object simply doesn't have '_flashes' attribute in my case:

with client.session_transaction() as session:
    flash_message = dict(session['_flashes']).get('warning')

KeyError: '_flashes'

It might be because most recent version of flask and other packages I use with Python 3.6.4 may work differently, I honestly don't know...

What worked for me is a simple and straightforward:

def test_flash(self):
    # attempt login with wrong credentials
    response = self.client.post('/authenticate/', data={
        'email': '[email protected]',
        'password': '1234'
    }, follow_redirects=True)
    self.assertTrue(re.search('Invalid username or password',
                    response.get_data(as_text=True)))

In my case the flash message was 'Invalid user name or password'.

I think it's also easier to read. Hope it helps those who encountered a similar issue

Norvol answered 18/2, 2018 at 19:12 Comment(0)
P
5

Here's a sample test that asserts an expected flash message is present. It is based on the method described here:

def test_should_flash_warning_message_when_no_record_found(self):
    # Arrange
    client = app.test_client()

    # Assume
    url = '/records/'
    expected_flash_message = 'no record found'

    # Act
    response = client.get(url)
    with client.session_transaction() as session:
        flash_message = dict(session['_flashes']).get('warning')

    # Assert
    self.assertEqual(response.status_code, 200, response.data)
    self.assertIsNotNone(flash_message, session['_flashes'])
    self.assertEqual(flash_message, expected_flash_message)

Note: session['_flashes'] will be a list of tuples. Something like this:

[(u'warning', u'no records'), (u'foo', u'Another flash message.')]
Photolithography answered 25/3, 2016 at 15:47 Comment(0)
V
0

The answer by @klenwell didn't work for me and I wanted something more robust than what @leo did.

I created a utility function to extract the flashed messages from the response.

All my templates have a bootstrap modal for showing flashed messages:

{% with messages = get_flashed_messages() %}
  {% if messages %}
    <div id="flash-dlg" class="modal fade" tabindex="-1" role="dialog">
        ...
          <div class="modal-body">
            {% for message in messages %}
            <p>{{ message }}</p>
            {% endfor %}
          </div>
        ...
    </div>
  {% endif %}
{% endwith %}

My utility function receives the response and returns the list of flashed messages:

def get_flash(rsp):
    h = lxml.html.fromstring(rsp.data)
    pars = h.xpath('.//div[@id="flash-dlg"]//div[@class="modal-body"]/p')
    texts = [p.text for p in pars]
    return texts

I use lxml but this could easily be adapted to BeautifulSoup and other methods of presented flashed messages.

This makes it easy to precisely check what was flashed.

Vibrate answered 20/1, 2022 at 23:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.