Behavorial Test For Custom Entity Using CasperJS

Chauncey Thorn, Senior Developer
#Testing | Posted

This blog post is a continuation of my "Developing A Drupal Entity" post. In my previous post I described the process of creating your own entity. This post will focus on writing a behavioral test for that entity using CasperJS.
What is CasperJS?CasperJS

is a program that makes it easy to simulate the navigation of a website: clicking around, submitting to forms, uploading of files and even screenshots. It is written in Javascript and runs on top of PhantomJS which is a headless browser.

Installing CasperJS

To install CasperJS, you can follow the installation instructions here.

Writing a test

This test will simulate logging into the Drupal environment, create a lawmaker entry and then making an edit to that entry.

First we create a new Casper instance. There are a number of option besides the two we've elected to use here.

  1. var casper = require('casper').create({
  2. verbose: false,
  3. logLevel: "debug"
  4. });

Our test script requires an environment paramater. i.e. --environment. To ensure that paramater is passed to the script we check for it and exit if it doesn't exists.

  1. if (!casper.cli.get('environment')) {
  2. casper.echo('Usage: $ casperjs lawmakers.js --environment=domain.tld').exit(-1);
  3. }

Casper has a built-in commandline support via the cli module. We're going to use it to get our --environment variable, which will be passed to our link variable.

  1. var environment = casper.cli.get('environment');
  2. var link = 'http://' + environment;

Now we start the test logging into the environment. We then assert the login form exists and begin to fill it out before submitting. Note the third param is true, this tells the fill function to submit the form.

  1. casper.start(link + '/user', function() {
  2. this.test.assertExists('#user-login');
  3. this.fill('form#user-login', {
  4. 'name': 'admin',
  5. 'pass': 'admin'
  6. }, true);
  7. });

If we got logged in we should see the class .profile so let's assert it exists.

  1. casper.then(function() {
  2. this.test.assertExists('.profile');
  3. });

Now that we're logged in, we're going to create a lawmaker entry. Note the usage of the fill function and the third param is now false, telling the fill function we're going to click the submit button later on.

  1. // Let open our lawmakers add form.
  2. casper.thenOpen(link + '/admin/content/lawmakers/add');
  3.  
  4. // Create a lawmaker via the admin form.
  5. casper.then(function() {
  6. this.test.comment('Creating lawmaker...');
  7. this.test.assertExists('#lawmakers-form');
  8. this.test.assertExists('form#lawmakers-form');
  9. this.fill('form#lawmakers-form', {
  10. 'username': 'Grey_Goose',
  11. 'title': 'Rep',
  12. 'firstname': 'Grey',
  13. 'middlename': 'J',
  14. 'lastname': 'Goose',
  15. 'name_suffix': 'GG',
  16. 'nickname': 'GreyGoose',
  17. 'party': 'D',
  18. 'state': 'NY',
  19. 'district': '5',
  20. 'in_office': '1',
  21. 'gender': 'M',
  22. 'phone': '202-225-2601',
  23. 'fax': '202-225-1589',
  24. 'website': 'http://ackerman.house.gov/',
  25. 'webform': 'http://www.house.gov/writerep',
  26. 'congress_office': '2111 Rayburn House Office Building',
  27. 'bioguide_id': 'A000022',
  28. 'votesmart_id': '26970',
  29. 'fec_id': 'H4NY07011',
  30. 'govtrack_id': '400003',
  31. 'crp_id': 'N00001143',
  32. 'eventful_id': '12234567789',
  33. 'sunlight_old_id': '987654321',
  34. 'twitter_id': 'repgaryackerman',
  35. 'congresspedia_url': 'http://www.opencongress.org/wiki/Gary_Ackerman',
  36. 'youtube_url': 'http://youtube.com/RepAckerman',
  37. 'official_rss': 'http://google.com',
  38. 'senate_class': 'http://google.com'
  39. }, false);
  40.  
  41. this.click('#edit-submit');
  42. });

See if we got an error by asserting the .message .error div doesn't exist.

  1. casper.then(function() {
  2. //this.test.assertHttpStatus(302);
  3. this.test.assertDoesntExist('.messages.error');
  4. });

Since we're testing the functionality of our custom entity, we want to ensure we can edit an entry. Here we assert the .lawmakers-name is the title. firstname lastname. Then we want to click on the "Edit" link using clickLabel so we can go back and make an edit for additional testing.

  1. casper.then(function() {
  2. this.test.comment('Checking for the lawmaker's name...');
  3. this.test.assertExists('.lawmakers-name');
  4. this.test.assertSelectorHasText('.lawmakers-name','Rep. Grey Goose');
  5. this.clickLabel('Edit');
  6. });

Here we're going to make a simple edit... our previous title was "Rep". Note the usage of assertSelectorHasText in the previous block of code. For this edit we're going to use the fill function and use the click function to click the submit button.

  1. // Edit the entity.
  2. casper.then(function() {
  3. this.test.comment('Editing the newly created lawmaker...');
  4. this.test.assertExists('#lawmakers-form');
  5. this.test.assertExists('form#lawmakers-form');
  6. this.fill('form#lawmakers-form', {
  7. 'title': 'Sen',
  8. }, false);
  9.  
  10. this.click('#edit-submit');
  11. });

The final part of our test will check the edit we made. If you recall our initial entry "title" was "Rep" and we changed it to "Sen" as a result we want to test for that change.

  1. // Validate the edit.
  2. casper.then(function() {
  3. this.test.comment('Verifying lawmaker's landing page...');
  4. this.test.assertHttpStatus(302);
  5. this.test.assertExists('.lawmakers-name');
  6. this.test.assertSelectorHasText('.lawmakers-name','Sen. Grey Goose');
  7. this.test.assertSelectorHasText('.party','D NY 5');
  8. this.test.assertSelectorHasText('.congress_office','2111 Rayburn House Office Building');
  9. this.test.assertSelectorHasText('.phone','tel: 202-225-2601');
  10. this.test.assertSelectorHasText('.fax','fax: 202-225-1589');
  11. this.test.assertExists('.website a', 'Website URL exists');
  12. this.test.assertExists('.twitter a', 'Twitter URL exists');
  13. this.test.assertExists('.youtube a', 'Youtube URL exists');
  14. });

Here we are going to use the run function to execute our test. Note if you don't add this function your test script won't run. It will just sit there...

  1. casper.run(function() {
  2. this.test.renderResults(true, 0, this.cli.get('save') || false);
  3. this.exit();
  4. });

Here is the entire script all together:

  1. var casper = require('casper').create({
  2. verbose: false,
  3. logLevel: "debug"
  4. });
  5.  
  6. if (!casper.cli.get('environment')) {
  7. casper.echo('Usage: $ casperjs lawmakers.js --environment=domain.tld').exit(-1);
  8. }
  9.  
  10. var environment = casper.cli.get('environment');
  11. var link = 'http://' + environment;
  12.  
  13. casper.start(link + '/user', function() {
  14. this.test.assertExists('#user-login');
  15. this.fill('form#user-login', {
  16. 'name': 'admin',
  17. 'pass': 'admin'
  18. }, true);
  19. });
  20.  
  21. casper.then(function() {
  22. this.test.assertExists('.profile');
  23. });
  24.  
  25. casper.thenOpen(link + '/admin/content/lawmakers/add');
  26.  
  27. // Create a lawmaker via the admin form.
  28. casper.then(function() {
  29. this.test.comment('Creating lawmaker...');
  30. this.test.assertExists('#lawmakers-form');
  31. this.test.assertExists('form#lawmakers-form');
  32. this.fill('form#lawmakers-form', {
  33. 'username': 'Grey_Goose',
  34. 'title': 'Rep',
  35. 'firstname': 'Grey',
  36. 'middlename': 'J',
  37. 'lastname': 'Goose',
  38. 'name_suffix': 'GG',
  39. 'nickname': 'GreyGoose',
  40. 'party': 'D',
  41. 'state': 'NY',
  42. 'district': '5',
  43. 'in_office': '1',
  44. 'gender': 'M',
  45. 'phone': '202-225-2601',
  46. 'fax': '202-225-1589',
  47. 'website': 'http://ackerman.house.gov/',
  48. 'webform': 'http://www.house.gov/writerep',
  49. 'congress_office': '2111 Rayburn House Office Building',
  50. 'bioguide_id': 'A000022',
  51. 'votesmart_id': '26970',
  52. 'fec_id': 'H4NY07011',
  53. 'govtrack_id': '400003',
  54. 'crp_id': 'N00001143',
  55. 'eventful_id': '12234567789',
  56. 'sunlight_old_id': '987654321',
  57. 'twitter_id': 'repgaryackerman',
  58. 'congresspedia_url': 'http://www.opencongress.org/wiki/Gary_Ackerman',
  59. 'youtube_url': 'http://youtube.com/RepAckerman',
  60. 'official_rss': 'http://google.com',
  61. 'senate_class': 'http://google.com'
  62. }, false);
  63.  
  64. this.click('#edit-submit');
  65. });
  66.  
  67. // See if we got an error.
  68. casper.then(function() {
  69. //this.test.assertHttpStatus(302);
  70. this.test.assertDoesntExist('.messages.error');
  71. });
  72.  
  73. casper.then(function() {
  74. this.test.comment('Checking for the lawmaker's name...');
  75. this.test.assertExists('.lawmakers-name');
  76. this.test.assertSelectorHasText('.lawmakers-name','Rep. Grey Goose');
  77. this.clickLabel('Edit');
  78. });
  79.  
  80. // Edit the entity.
  81. casper.then(function() {
  82. this.test.comment('Editing the newly created lawmaker...');
  83. this.test.assertExists('#lawmakers-form');
  84. this.test.assertExists('form#lawmakers-form');
  85. this.fill('form#lawmakers-form', {
  86. 'title': 'Sen',
  87. }, false);
  88.  
  89. this.click('#edit-submit');
  90. });
  91.  
  92. // Validate the edit.
  93. casper.then(function() {
  94. this.test.comment('Verifying lawmaker's landing page...');
  95. this.test.assertHttpStatus(302);
  96. this.test.assertExists('.lawmakers-name');
  97. this.test.assertSelectorHasText('.lawmakers-name','Sen. Grey Goose');
  98. this.test.assertSelectorHasText('.party','D NY 5');
  99. this.test.assertSelectorHasText('.congress_office','2111 Rayburn House Office Building');
  100. this.test.assertSelectorHasText('.phone','tel: 202-225-2601');
  101. this.test.assertSelectorHasText('.fax','fax: 202-225-1589');
  102. this.test.assertExists('.website a', 'Website URL exists');
  103. this.test.assertExists('.twitter a', 'Twitter URL exists');
  104. this.test.assertExists('.youtube a', 'Youtube URL exists');
  105. });
  106.  
  107. casper.run(function() {
  108. this.test.renderResults(true, 0, this.cli.get('save') || false);
  109. this.exit();
  110. });

Running tests

$ casperjs lawmakers.js --environment=domain.tld

Here is the output of the test we've written above:

results of casper test

Now, If you haven't had a chance to use CasperJS I recommend that you get started. I've tried to provide a practical example of it's usage. Check out Joe Turgeon's blog post about the business case for automated testing.

 

Chauncey Thorn

Chauncey Thorn

Senior Developer