I find myself repeating a lot of the same test actions in my ICE Code Editor test suite. This seems a fine opportunity to explore test helpers in Dart unit tests.
The one in particular that I find myself doing a lot is clicking on element, usually with particular content:
queryAll('button').
firstWhere((e)=> e.text=='☰').
click();
My first instinct is that the helpers should be a separate library that is imported into my test suite. The main reason is that I can import with an “as” prefix to make it patently obvious where the helper methods live. So, in my main ice_test.dart
main test file, I add the import statement:library ice_test; import 'package:unittest/unittest.dart'; // ... import 'helpers.dart' as helpers; import 'package:ice_code_editor/ice.dart'; main(){ // tests go here... }In
helpers.dart
, I start with a single click()
function:library ice_test_helpers; import 'dart:html'; void click(String selector, {text}) { if (text == null) return query(selector).click(); queryAll(selector). firstWhere((e)=> e.text==text). click(); }The click function requires a string selector that will be used to query for elements to click. If no text is specified—if the optional, named parameter
text
is null
—then I query for the first matching selector and click it. If the text
parameter is specified, then I query for all matching selectors, find the first that contains the supplied text
and click that. I continue to use the
firstWhere()
because it will throw an exception if no matching element is found. I may want to bundle that into a new exception that makes it more obvious what has gone wrong in the test, but I leave it for now.With that, I can change the test that verifies one of the ways to close a menu:
test("the menu button closes the projects dialog", (){
queryAll('button').
firstWhere((e)=> e.text=='☰').
click();
queryAll('li').
firstWhere((e)=> e.text=='Projects').
click();
queryAll('button').
firstWhere((e)=> e.text=='☰').
click();
expect(
queryAll('div').map((e)=> e.text).toList(),
isNot(contains(matches('Saved Projects')))
);
});
Instead, I can write that as: test("the menu button closes the projects dialog", (){
helpers.click('button', text: '☰');
helpers.click('li', text: 'Projects');
helpers.click('button', text: '☰');
expect(
queryAll('div').map((e)=> e.text).toList(),
isNot(contains(matches('Saved Projects')))
);
});
Holy clearer intent Batman! It is much easier to see that this test clicks the menu button, then the Projects menu item, then the menu button again. I might have omitted the “helpers” prefix from my import statement and thus been able to treat
click()
as a top-level function. I tend to think that the prefix will aid in long-term maintainability of the test suite as there will never be a question as to the source of the helper function. Day #757
No comments:
Post a Comment