Getting Cypress JS to interact with CKEditor

Because .type() doesn’t submit when selecting the textarea.

CKEditor
CkEditor iframe with custom toolbar

While writing a few Cypress.io tests I ran into a problem of manipulating text in a CKEditor window.

Without diving completely into how CKEditor implements the editable iframe, my first thought was to use the native textarea field and skip adding content to the WYSIWYG all together.

Using the native type() function

// The underlying `textarea`

cy.get("#html_body")
.type("<p>HTML body</p>");
Cypress native type command
Cypress error, can’t type in hidden inputs

Cypress doesn’t like typing into hidden input element elements.

Adding the force:true config doesn’t fare much better. With Javascript turned on, CKEditor overwrites the textarea on submit and that value is lost. 😒

Cypress interacting with an iFrame

Next stop is to search “cypress type in ckeditor” which leads to the issue Cannot target elements inside of an iframe #136.

Reading through the working examples lead to something like this:

// Find the `contenteditable` element within the iframe and type

cy.get("#html_body")
  .then(function ($iframe) {
    const $body = $iframe.contents().find("body");

    cy.wrap($body[0])
      .type("<p>HTML body</p>");
  });
Cypress doesn't error
Doesn’t error, but also doesn’t submit

This does find the DOM element and says that it was typed, but it doesn’t actually result in the words being visible in the CKEditor or submitted with the form. 😢

Interacting with JS page objects

Last ditch effort is to break outside of Cypress and set the data in CKEditor natively then try to make the same call from within the Cypress test.

CKEditor has setData() and getData() functions for getting contents in and out of the editor window.

// Set the contents of the CKEditor natively on the page

CKEDITOR.instances["html_body"].setData("<p>HTML body</p>");

Now to call that from within Cypress, led to a search for “cypress get page JS objects” and then to this issue: How can I execute a JavaScript command #897 and the .window() function.

Success!

// Call out to the page window and use the CKEDITOR object

cy.window()
  .then(win => {
    win.CKEDITOR.instances["html_body"].setData("<p>HTML body</p>");
  });
Setting the content of CKEditor with Javascript
Setting the content of CKEditor with Javascript

Turning the solution into a reusable command

// Define the command

Cypress.Commands.add("type_ckeditor", (element, content) => {
  cy.window()
    .then(win => {
      win.CKEDITOR.instances[element].setData(content);
    });
});

// Use the command

cy.type_ckeditor("html_body", "<p>HTML body</p>");

With this approach it is possible to use any of the CKEDITOR.editor object functions.

Favorite snipit of code today

Signing up for unigo.com today I found my favorite piece of javascript. There is a checkbox for:

When checking the box you get this pop up:

Then you think to yourself, WTF? Didn’t my checking the box verify my agreement?

Here is the code that made it all possible:

Hope you enjoyed my code snipit of the day.

Progressive Enhancement

Building for the lowest common denominator and then expanding upward. It sounds like a simple concept but most wed developers just can’t seem to grasp it. Not believing accessibility matters or being so inexperienced that building sites seems to just be a hack fest to make the “design” work in all browsers is the single largest issue with web design now a days.

One example off the top of my head is mtv.com which did a total redesign in flash and had all these crazy bells and whistles, integrated video, movement, etc. Well two months later guess what happened, they redesigned again this time into a fully xhtml compliant site which didn’t have all the movement but was 100x easier to use and you could actually get to it with a cell phone and actually search for text on the page.

Two simple things I always look for when going to sites, first since I don’t have a lot of time to read through pages for information I use the firefox built in find as you type and if it cannot jump right to the word i am looking for ill go someplace else.

The second I don’t use as much but I am sure other people do, phone browser support. I am not talking about iPhone safari support because that is not really developing for the lowest common denominator. I use either a WAP browser of Opera on my phone while out and about if I need to look up information quickly. If I cannot get to your page and get to the information I need I will leave your site and probably never return.

We have a CMS that we built at Wayne State and sometimes page updates need to happen right then. We built it for the lowest common denominator just for that reason. We can get to it on any WAP browser and update any page in the CMS as if we were on a full computer. Without it we would have to rush to a computer just to use some fancy ajax interface, it would be pretty but would it really be worth all the hassle? I think not.

Anthem:
Speed > Features
Simple > Complex
Enhancement > Degradation

jQuery vs Prototype – Document Load: jQuery wins

Recently I started using jQuery instead of Prototype for my web applications. When I first started using a javascript library I picked Prototype because to be honest jQuery intimidated me, there was a lot of mystery about it. Well I took another look at it a few days ago and I was floored, boy I was missing out. jQuery byte for byte in my opinion kicks prototypes butt.

Take for example attaching a function to the document load and adding an onclick action to a link.

Pototype:

// Initially set everything up
init = function (){
// If there is an expand dom element
if ($('expand')){
Event.observe($('expand'), 'click', ExpandMenu, false);
}
} // Attach the onload function
Event.observe(window, 'load', init, false);

jQuery:

// Initially set everything up
$(document).ready(function(){
// On click event
$("#expand").click(function(){
// Function actions here
});
});

It may not seem like a great deal of code reduction but scanning the code from top down (say if you were a developer brought in to fix a bug) shows how more fluid jQuery is in terms of execution flow. Prototype jumps all over the place…

  1. First define the initializer function
  2. Next find the element on the page
  3. Set an observer on it and direct it yet another function
  4. Last but not least attach the initializer to the document load

It seems that is the exact opposite order of its execution, jQuery on the other hand…

  1. Create a function and attach it to the document ready state
  2. Create a function and attach it to a dom element on click
  3. Done.

First round goes to: jQuery