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)
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).