Testing IMCE Wysiwyg Integration in Drupal Using Behat and Mink
by Aaron Froehlich
Over the past few months we've been using Behat and Mink for acceptance testing on a large Drupal distribution we're building (further background reading here). Overall, the transition from our comfy rails testing tools like RSpec and capybara-webkit has gone pretty smoothly, and we look forward to more articles about what we've learned in the coming weeks.
Last week, however, I hit a roadblock when testing IMCE integration with the Wysiwyg module. When a user clicks on the "Browser Server" button, IMCE opens a new window, but the Mink context does not automatically shift to the new window. Luckily, Mink provides the solution for this exact problem with itssession->switchToWindow(name)
method (documentation). Unfortunately, CKEditor doesn't name the window when it opens, so it is impossible to target the window using the built-in method.
The problem presents an interesting dilemma. Patches are a good solution for bugs in modules/libraries, but leaving out an optional attribute isn't really a bug. Also, the minified javascript code makes it really hard to even write a patch that would work correctly when applied. Finally, it hardly makes sense to patch a file simply for the test suite.
To solve the dilemma, we simply needed to figure out where CKEditor was creating that window, and then utilize Behat's @BeforeSuite and @AfterSuite1 hooks to add a window name before the suite runs, and remove it after the tests finish running. In this case, we created a static method called strReplaceFile
private function strReplaceFile($file, $find, $replace) { $str = file_get_contents($file); $str = str_replace($find, $replace, $str); file_put_contents($file, $str); }
After isolating the correct window.open function in CKEditor.js (where they are indeed passing null as the window name), we were able to run our handy method to give the window a name:
self::strReplaceFile( 'sites/all/libraries/ckeditor/ckeditor.js', 'c=window.open("",null,d', 'c=window.open("","file_browser",d' );
On teardown, we simply reverse it:
self::strReplaceFile( 'sites/all/libraries/ckeditor/ckeditor.js', 'c=window.open("","file_browser",d', 'c=window.open("",null,d', );
Our handy use of str_replace now allows us to create step definitions like the following (using the selenium driver):
/** * @Given /^I choose the file "([^"]*)" in the "([^"]*)" folder$/ */ public function chooseTheFileInTheFolder($filename, $folder) { $this->getSession()->switchToWindow('file_browser'); $this->page->clickLink($folder); sleep(1); //Solves intermittent timeout issues $el = $this->page->find('xpath', '//span[text()="'. $filename .'"]'); $el->doubleClick(); $this->getSession()->switchToWindow(null); // Switches back to the main window }1Note that if the tests fail to complete for some reason, the ckeditor.js file will remain in it's edited state.