RevAjaxMutator

Automated Program Repair Tool for Ajax Web Applications

We use Quizzy version 1.0

Under AGPL v.3 licence, source code of all mutated/faulty/repaired versions are available from: quizzy_src.zip

This usage scenario consists of two phases: before and after refactoring. Before refactoring, we use AjaxMutator to apply mutation analysis to Quizzy and improve their test case. In contrast, while refactoring, we make a common mistake which RevAjaxMutator automatically fixes.

A running example is here.

Now we focus on the following code snippet where Quizzy has two click event handlers on page elements identified by class names quizzy_quiz_lbl and quizzy_quiz_opt, as shown in Figure below. Once users click on these elements, Quizzy renders the corresponding description.

    //add a click event to the radio buttons' label
    $('.quizzy_quiz_lbl').click(function () {
      //the user clicked on one of the options
      //get the id
      var thisId = $(this).attr('id');
      
      //hack out the index and set selOpt to it
      var selQuiz = getSelQuiz(thisId); // modified for simplicity
      
      //make sure that the radio button is selected
      $('#quizzy_quiz_opt'+selQuiz).click();
    });
    
    //add another click event handler to the radio buttons
    $('.quizzy_quiz_opt').click(function() {
      //the user clicked on one of the options
      //get the id
      var thisId = $(this).attr('id');
      
      //hack out the index and set selOpt to it
      var selQuiz = getSelQuiz(thisId); // modified for simplicity
      
      //slide up all other descriptions while sliding down the correct one
      $('.quizzy_quiz_desc[id!=quizzy_quiz_desc'+selQuiz+']').slideUp(slideSpeed, function() {
        $('#quizzy_quiz_desc' + selQuiz).slideDown(slideSpeed);
      });
    });

For this functionality, we initially implement the following test cases by using JUnit and Selenium frameworks; an @Test represents a test case for JUnit. The clickRadioButton test case runs for clicking the radio button driver.findElement(By.id("quizzy_quiz_opt0")) and confirming whether the rendered description driver.findElement(By.id("quizzy_quiz_desc0")).getText().trim() conforms to the expected output "Several quizzes are available; min/max score range is 0-100.". As a difference between these test cases, the ckickRadioButtonLabel test case runs for clicking the label driver.findElement(By.id("quizzy_quiz_lbl0")). Both these test cases covers all statements in this code snippet, passing on this initial version of Quizzy.

  @Test
  public void clickRadioButton() {
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("quizzy_quiz_opt0")));
    driver.findElement(By.id("quizzy_quiz_opt0")).click();;
    Assert.assertEquals("Several quizzes are available; min/max score range is 0-100.",
        driver.findElement(By.id("quizzy_quiz_desc0")).getText().trim());
  }
  
  @Test
  public void ckickRadioButtonLabel() {
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("quizzy_quiz_lbl0")));
    driver.findElement(By.id("quizzy_quiz_lbl0")).click();
    Assert.assertEquals("Several quizzes are available; min/max score range is 0-100.",
        driver.findElement(By.id("quizzy_quiz_desc0")).getText().trim());
  }

A running example is here.

Herein we apply mutation analysis to this version version. For simplicity, we provide one of the mutations created by AjaxMutator below. This mutation (i.e., injected fault) means that Quizzy invokes the callback function for the .quizzy_quiz_opt element even if users click on the .quizzy_quiz_lbl element. The figure below shows an erroneous behavior due to this injected fault.

@@ -48,11 +48,7 @@
-   $('.quizzy_quiz_lbl').click(function () {
-     //the user clicked on one of the options
-     //get the id
-     var thisId = $(this).attr('id');
-     
-     //hack out the index and set selOpt to it
-     var selQuiz = getSelQuiz(thisId);
-     
-     //make sure that the radio button is selected
-     $('#quizzy_quiz_opt'+selQuiz).click();
-   });
+   $('.quizzy_quiz_lbl').click(function() {
+  var thisId = $(this).attr('id');
+  var selQuiz = getSelQuiz(thisId);
+  $('.quizzy_quiz_desc[id!=quizzy_quiz_desc' + selQuiz + ']').slideUp(slideSpeed, function() {
+  $('#quizzy_quiz_desc' + selQuiz).slideDown(slideSpeed);
+});
+});

Although coverage of this initial test cases on the code snippet is 100%, they do not detect this injected fault. Therefore, we improve the ckickRadioButtonLabel test case by adding the assertion statement below (containing the improvement comment-out) which detects the injected fault. Finally, we obtain the improved test cases whose fault-detecting capability is higher that that of the initial test cases.

  @Test
  public void clickRadioButton() {
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("quizzy_quiz_opt0")));
    driver.findElement(By.id("quizzy_quiz_opt0")).click();;
    Assert.assertEquals("Several quizzes are available; min/max score range is 0-100.",
        driver.findElement(By.id("quizzy_quiz_desc0")).getText().trim());
  }
  
  @Test
  public void ckickRadioButtonLabel() {
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("quizzy_quiz_lbl0")));
    driver.findElement(By.id("quizzy_quiz_lbl0")).click();
    Assert.assertEquals("Several quizzes are available; min/max score range is 0-100.",
        driver.findElement(By.id("quizzy_quiz_desc0")).getText().trim());
    Assert.assertTrue(driver.findElement(By.id("quizzy_quiz_opt0")).isSelected());          // Improved
  }

A running example is here.

We then do refactoring; separately implementing callback functions for the radio-button and label elements. While this refactoring, we consider to use input completion (e.g., that provided by Sublime-text) and make make the following mistake of attaching a faulty callback function clickQuizzyQuizOpt at the label element, whereas a correct function is clickQuizzyLbl. It then causes the same failure as that caused by mutation testing so the improved test case can detect the made mistake.

    //add a click event to the radio buttons' label
    $('.quizzy_quiz_lbl').click(clickQuizzyQuizOpt);          // Fault

    //add another click event handler to the radio buttons
    $('.quizzy_quiz_opt').click(lickQuizzyQuizOpt);

    function clickQuizzyQuizOpt() {...}
    function clickQuizzyQuizLbl() {...}
    

A running example is here.

For the faulty version of Quizzy, we ran RevAjaxMutator. It then generated the following patch and all the test cases pass for the patched Quizzy. Thus, RevAjaxMutator is expected to automatically generate and validate Ajax applications might containing Ajax-related faults that AjaxMutator injects as common faults.

@@ -48 +48 @@
-   $('.quizzy_quiz_lbl').click(clickQuizzyQuizOpt);
+   $('.quizzy_quiz_lbl').click(clickQuizzyQuizLbl);