Jesper Rønn-Jensen Jesper Rønn-Jensen - 7 months ago 16
Javascript Question

jasmine text verification: How to normalize text?

I have a page with text in different HTML elements and I want a quick way of verifying the text.

Using jasmine and jasmine-query to load HTML and test DOM.

For example, I want to verify text in this HTML

<table id="users">
<thead>
<tr>
<td>user</td>
<td>permissions</td>
<td>last seen</td>
</tr>
</thead>
<tbody>
<tr>
<td>Darren</td>
<td>testuser,customer</td>
<td>today</td>
</tr>
<tr>
<td>Hillary</td>
<td>administrator</td>
<td>yesterday</td>
</tr>
</tbody>
</table>


And let's say I want to verify each row in my table contains the correct text.
Jasmine test file:

it('should find correct text in table', function () {
expect( $('#users').find('tbody tr').first() ).toContainText('Darren testuser,customer today');
expect( $('#users').find('tbody tr').last() ).toContainText('Hillary administrator yesterday');

});


I will get this failure:

Testexample:: should find correct text in table: failed
Expected '<tr>
<td>Darren</td>
<td>testuser,customer</td>
<td>today</td>
</tr>' to contain text 'Darren testuser,customer today'. (1)
Expected '<tr>
<td>Hillary</td>
<td>administrator</td>
<td>yesterday</td>
</tr>' to contain text 'Hillary administrator yesterday'. (2)
1 spec in 0.283s.
>> 2 failures


The other experiment was to use jQuery.text() to extract, then I still have an error because of all the whitespace:

it('should find correct text in table with jQuery.text()', function () {
expect( $('#users').find('tbody tr').first().text() ).toContain('Darren testuser,customer today');
expect( $('#users').find('tbody tr').last().text() ).toContain('Hillary administrator yesterday');

});


Gives this failure:

Testexample:: should find correct text in table with jQuery.text(): failed
Expected '
Darren
testuser,customer
today
' to contain 'Darren testuser,customer today'. (1)
Expected '
Hillary
administrator
yesterday
' to contain 'Hillary administrator yesterday'. (2)
1 spec in 0.291s.
>> 2 failures


Capybara (for ruby) has a way to normalize text so that I can always see a reasonable text representation of my HTML. How would I normalize whitespace in an easy way so that I can make verifications like this?

(I don't expect answers like 'you should not test across html elements'... since this is the premise for the question. Actually I like making assertions across several elements: It's readable, short, and give a quick view if stuff is working. Also really necessary when I am testing from outside-in)

Answer

Thanks to Tobias' answer I ended up improving on that and wrote my own custom matcher. Now I can write:

        expect( $('#users').find('tbody tr').first() ).toHaveNormalizedText('Darren testuser,customer today');

Matcher code -- added in the beforeEach() block of my describe() scenario:

        this.addMatchers({
            toHaveNormalizedText: function(expected) {
                var actualText = $.trim(this.actual.text()).replace(/\s+/g, ' ');
                var result = actualText === expected;
                if( result) return result;
                //rest is only if it fails
                var notText = this.isNot ? " not" : "";
                var charcodes = [];
                for(var i=0; i<actualText.length; i++){
                    charcodes.push(actualText.charCodeAt(i));
                    if(i>23) break;
                }
                this.message = function () {return 'Expected "' + actualText + notText + '" to match "'+expected+'"\n\nFirst 25 charcodes:\n'+charcodes;};
                return result;
            }
        });

A few notes about this. Here is the actual replacement:

$.trim(this.actual.text()).replace(/\s+/g, ' ');

$.trim() was important for my html structure which did include whitespace in the beginning of the text() string.

this.message = function () {return 'Expected "' + actualText + notText + '" to match "'+expected+'"\n\nFirst 25 charcodes:\n'+charcodes;};

this.message is jasmine's custom error message. This string outputs strings like this on error:

failed
  Expected "Darren testuser,customer todaiiy" to match "Darren testuser,customer today"

First 25 charcodes:
68,97,114,114,101,110,32,116,101,115,116,117,115,101,114,44,99,117,115,116,111,109,101,114,32 (1)

I decided to add the charcodes because at one point I had a problem with charcodes 10 (newline) and 32 (spaces).