Author Archives: Guillaume

Drag and drop external files with Selenium

Selenium does not allow dropping external files on an element. However it may be mandatory for your test if you want to cover every functionality. We will see how to make it work with Firefox 28+ and Chrome. I haven’t tested that on other browsers. We will see three work around:

  • Simulate a drop event without any file
  • Simulate a drop of a file from the file system (easy way but only for text file)
  • Simulate a drop of any file from the file system

Simulate a drop event without any file

This is a mostly a JavaScript workaround, the files and the drop event are created in JavaScript, that’s why the browser matters.

First a simple version where you don’t want file from your file system, this is enough in most situation:

public void dropFiles(List<String> names, WebElement target) throws IOException {
        
    final JavascriptExecutor exec = (JavascriptExecutor) BrowserDriver.getCurrentDriver();
    String inputId = "seleniumDragAndDropInput";
        
    // Create the FileList
    exec.executeScript(inputId + "_files = [];");
    for (String name: names) {
        exec.executeScript(inputId + "_files.push(new File([new Blob(['This is my content'], {type: 'text/plain'})], '" + name + "'));");
    }
        
    String targetId = target.getAttribute("id");
        
    // Add an id if the target doesn't have one
    if (targetId == null || targetId.isEmpty()) {
        targetId = "seleniumDragAndDropInput_target";
        exec.executeScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId);
    }
        
    // Add the item function the the FileList
    // Create the drop event and dispatch it on the target
    String initEventJS = inputId + "_files.item = function (i) {return this[i];};"
        + "var eve=document.createEvent(\"HTMLEvents\");"
        + "eve.initEvent(\"drop\", true, true);"
        + "eve.dataTransfer = {files:seleniumDragAndDropInput_files};"
        + "eve.preventDefault = function () {};"
        + "eve.type = \"drop\";"
        + "document.getElementById('" + targetId + "').dispatchEvent(eve);";
        
    exec.executeScript(initEventJS);

    if (targetId == "seleniumDragAndDropInput_target") {
        exec.executeScript("document.getElementById('seleniumDragAndDropInput_target').id = null");
    }
        
}

The File creation works only with Firefox 28+, with earlier version it says “operation is unsecure”.

Simulate a drop of a file from the file system (easy way but only for text file)

And now an other example where we are using file from the machine running the Selenium tests. However be careful because it is not really smart and file’s content needs to be without special characters or it will break the JavaScript. You should escape the content if you need more advanced content. I didn’t because I usually using the first solution and code my content. This is enough in most situation where a bit of plain text or xml are enough for my tests.

public void dropFiles(List<File> files, WebElement target) throws IOException {
        
    final JavascriptExecutor exec = (JavascriptExecutor) BrowserDriver.getCurrentDriver();
    String inputId = "seleniumDragAndDropInput";
        
    // Create the FileList
    exec.executeScript(inputId + "_files = [];");
    for (File file : files) {
        exec.executeScript(inputId + "_files.push(new File([new Blob(['" + readFile(file) + "'], {type: '" + Files.probeContentType(file.toPath()) + "'})], '" + file.getName() + "'));");
    }
        
    String targetId = target.getAttribute("id");
        
    // Add an id if the target doesn't have one
    if (targetId == null || targetId.isEmpty()) {
        targetId = "seleniumDragAndDropInput_target";
        exec.executeScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId);
    }
        
    // Add the item function the the FileList
    // Create the drop event and dispatch it on the target
    String initEventJS = inputId + "_files.item = function (i) {return this[i];};"
        + "var eve=document.createEvent(\"HTMLEvents\");"
           + "eve.initEvent(\"drop\", true, true);"
        + "eve.dataTransfer = {files:seleniumDragAndDropInput_files};"
        + "eve.preventDefault = function () {};"
        + "eve.type = \"drop\";"
        + "document.getElementById('" + targetId + "').dispatchEvent(eve);";
        
    exec.executeScript(initEventJS);

    if (targetId == "seleniumDragAndDropInput_target") {
        exec.executeScript("document.getElementById('seleniumDragAndDropInput_target').id = null");
    }
        
}

private String readFile( File file ) throws IOException {
    BufferedReader reader = new BufferedReader( new FileReader (file));
    String         line = null;
    StringBuilder  stringBuilder = new StringBuilder();
    String         ls = System.getProperty("line.separator");

    while( ( line = reader.readLine() ) != null ) {
        stringBuilder.append( line );
        stringBuilder.append( ls );
    }
    reader.close();
    return stringBuilder.toString();
}

Simulate a drop of any file from the file system

Here is a solution to actually drop any file from the file system. We have to use an input (type=file) and since we can not set its value via JavaScript (for security reason, or we could upload any file from our visitor 🙂 ), we need to set the value with Selenium with sendKeys. But in order for this to work, the input needs to be visible. That’s why I set the form with a position fixed. We need to delete it once done.

final JavascriptExecutor exec = (JavascriptExecutor) BrowserDriver.getCurrentDriver();

WebElement target = browseContainer.contentListGrid;

String targetId = target.getAttribute("id");

// Add an id if the target doesn't have one
if (targetId == null || targetId.isEmpty()) {
    targetId = "seleniumDragAndDropInput_target";
    exec.executeScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId);
}

exec.executeScript(
        "var f=dojo.create('form', {id: 'seleniumDragAndDropInput_form', style: {position: 'fixed', left: 0, top: 0, width:'100px', height: '100px'}}, dojo.body());"
        + "dojo.create('input', { type: 'file', id: 'seleniumDragAndDropInput' }, f);");

WebElement input = BrowserDriver.getCurrentDriver().findElement(By.id("seleniumDragAndDropInput"));
input.sendKeys(path);

exec.executeScript(
        "var files=dojo.byId(\"seleniumDragAndDropInput\").files;"
        + "var eve=document.createEvent(\"HTMLEvents\");"
        + "eve.initEvent(\"drop\", true, true);"
        + "eve.dataTransfer = {files:files};"
        + "eve.type = \"drop\";document.getElementById('" + targetId + "').dispatchEvent(eve);");

exec.executeScript("dojo.destroy('seleniumDragAndDropInput_form');");

if (targetId == "seleniumDragAndDropInput_target") {
    exec.executeScript("document.getElementById('seleniumDragAndDropInput_target').id = null");
}

You may need to change a bit if you are not using dojo and replace the byId, create and destroy but I an sure you have that with your favorite javascript framework.

Simulate a drop of multiple files from the file system

With Chrome, you could use almost the same code that the previous one. The only thing to do is to set the input as ‘multiple’ and split paths with a \n.

public static void dropFile(String[] paths, WebElement target) {
    
    StringBuffer b = new StringBuffer();
    for (int i = 0; i < paths.length; i++) {
        File f = new File(paths[i]);
        if (!f.isFile()) {
            Assert.fail(paths[i] + " is not a valid file path.");
        }
        b.append(f.getAbsolutePath());
        if (i < paths.length - 1) {
            b.append("\n");
        }
    }
    
    final JavascriptExecutor exec = (JavascriptExecutor) BrowserDriver.getCurrentDriver();
    
    String targetId = target.getAttribute("id");
    
    // Add an id if the target doesn't have one
    if (targetId == null || targetId.isEmpty()) {
        targetId = "seleniumDragAndDropInput_target";
        exec.executeScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId);
    }
    
        exec.executeScript(
                "var f=dojo.create('form', {id: 'seleniumDragAndDropInput_form', style: {position: 'fixed', left: 0, top: 0, width:'100px', height: '100px'}}, dojo.body());"
                + "dojo.create('input', { type: 'file', id: 'seleniumDragAndDropInput', multiple: 'multiple' }, f);");
    
    
        WebElement input = BrowserDriver.getCurrentDriver().findElement(By.id("seleniumDragAndDropInput"));
        input.sendKeys(b.toString());
    
        exec.executeScript(
                "var files=dojo.byId(\"seleniumDragAndDropInput\").files;"
                + "var eve=document.createEvent(\"HTMLEvents\");"
                + "eve.initEvent(\"drop\", true, true);"
                + "eve.dataTransfer = {files:files};"
                + "eve.type = \"drop\";document.getElementById('" + targetId + "').dispatchEvent(eve);");
    
    exec.executeScript("dojo.destroy('seleniumDragAndDropInput_form');");
    
    if (targetId == "seleniumDragAndDropInput_target") {
        exec.executeScript("document.getElementById('seleniumDragAndDropInput_target').id = null");
    }
    
    
}

However, it does not work with Firefox because it does not accept multiple files in one input separated by \n. That’s why we need to use several inputs and then gather files from all inputs in a FileList to be used in the event. Here is the code.

public static void dropFile(String[] paths, WebElement target) {
    
    for (int i = 0; i < paths.length; i++) {
        File f = new File(paths[i]);
        if (!f.isFile()) {
            Assert.fail(paths[i] + " is not a valid file path.");
        }
        paths[i] = f.getAbsolutePath();
    }
    
    
    final JavascriptExecutor exec = (JavascriptExecutor) BrowserDriver.getCurrentDriver();
    
    String targetId = target.getAttribute("id");
    
    // Add an id if the target doesn't have one
    if (targetId == null || targetId.isEmpty()) {
        targetId = "seleniumDragAndDropInput_target";
        exec.executeScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId);
    }
    
    // Using one input with multiple file separated by \n does not work with Firefox
    // We need to use several input
    StringBuffer createInputs = new StringBuffer();
    // Create form
    createInputs.append("var f=dojo.create('form', {id: 'seleniumDragAndDropInput_form', style: {position: 'fixed', left: 0, top: 0, width:'100px', height: '100px'}}, dojo.body());");
    // Create inputs
    for (int i = 0; i < paths.length; i++) {
        createInputs.append("dojo.create('input', { type: 'file', id: 'seleniumDragAndDropInput" + i + "'}, f);");
    }
    
    exec.executeScript(createInputs.toString());
    
    // Then set file for each input
    
    for (int i = 0; i < paths.length; i++) {
        WebElement input = BrowserDriver.getCurrentDriver().findElement(By.id("seleniumDragAndDropInput" + i));
        input.sendKeys(paths[i]);
    }
    
    // Write code to gather all inputs files in one array;
    StringBuffer gatherInputs = new StringBuffer();
    gatherInputs.append("var seleniumDragAndDropFiles = [];");
    // Need to add the item method to stick to FileList API
    gatherInputs.append("seleniumDragAndDropFiles.item = function (i) { return seleniumDragAndDropFiles[i]};");
    for (int i = 0; i < paths.length; i++) {
        gatherInputs.append("seleniumDragAndDropFiles.push(dojo.byId(\"seleniumDragAndDropInput" + i + "\").files[0]);");
    }
    
    // Init event with our file
    exec.executeScript(
            gatherInputs.toString()
            + "var eve=document.createEvent(\"HTMLEvents\");"
            + "eve.initEvent(\"drop\", true, true);"
            + "eve.dataTransfer = {files:seleniumDragAndDropFiles};"
            + "eve.type = \"drop\";document.getElementById('" + targetId + "').dispatchEvent(eve);");
    
    exec.executeScript("dojo.destroy('seleniumDragAndDropInput_form');");
    
    if (targetId == "seleniumDragAndDropInput_target") {
        exec.executeScript("document.getElementById('seleniumDragAndDropInput_target').id = null");
    }
    
    
}

 

How to access your plug-in’s ressources

There are times where you need to know the URL of a ressource within your plug-in. An example is when you want to embedded an applet and add it to your page, or get the link to an image. In order to do that, you can use the following code:

Request.getPluginResourceUrl("PluginName", "myFolderWithingWebContentFolder/path");

An example if you want to embedded an applet:

var appletHTML = '<applet alt="MyApplet" name="MyApplet" width="1px" height="1px" code="my.package.MyClass.class" codebase="'
    + Request.getPluginResourceUrl('PluginName', 'applets')
    + '" archive="MyApplet.jar" mayscript="true">';
appletHTML = appletHTML + '</applet>';
appletDiv = document.createElement("div");
appletDiv.innerHTML = appletHTML;
applet = appletDiv.firstChild;
document.body.appendChild(applet);

That can be convenient .

Create your first Object Store

After a CPIT installation, you will still have to create an Object Store in order to have a fully functional platform. Luckily, when using the CPIT installer, IBM already provides the database and datasources for one more Object Store, They also pre-set the database connection in the Administrative Console for Content Engine (ACCE). So the procedure is really easy, we only have to create the Object Store using the pre-set database connection.

Here are the procedure in pictures:
Continue reading

Start and stop a FileNet CPIT platform

I was reading a few posts on ecmplace today and I saw that some persons are struggling with starting and stopping the FileNet platform after they got their CPIT installation done. So here are two scripts to start and stop all components. They start in order (and stop in reverse order) the following components:

  1. The DBMS DB2
  2. The LDAP Tivoli Directory Server (admin server then instance)
  3. The Application Server WebSphere Application Server (hosting the Platform Engine and possibly IBM Content Navigator or any client application)

To start the platform (I include the iptables config but if you saved it once for all you don’t need those lines):

#!/bin/bash
iptables -I INPUT 4 -i eth0 -p tcp --dport 9080 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -I INPUT 4 -i eth0 -p tcp --dport 9043 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -I INPUT 4 -i eth0 -p tcp --dport 2809 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -I INPUT 4 -i eth0 -p tcp --dport 9100 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -I INPUT 4 -i eth0 -p tcp --dport 9403 -m state --state NEW,ESTABLISHED -j ACCEPT
# DB2
su - dsrdbm01 -c db2start
# TDS admin server
/opt/ibm/ldap/V6.3/sbin/idsdiradm -I dsrdbm01
# TDS instance
/opt/ibm/ldap/V6.3/sbin/ibmslapd -n -I dsrdbm01
# WAS
/opt/ibm/WebSphere/AppServer/bin/startServer.sh server1

To stop the platform:

#!/bin/bash
# WAS
/opt/ibm/WebSphere/AppServer/bin/stopServer.sh server1 -username P8Admin -password PASSWORD
# TDS instance
/opt/ibm/ldap/V6.3/sbin/ibmslapd -I dsrdbm01 -k
# TDS admin server
/opt/ibm/ldap/V6.3/sbin/idsdiradm -I dsrdbm01 -k
# DB2
su - dsrdbm01 -c db2stop

Hopefully it will help someone.

Java 7 enforces bytecode verification

I had some issues lately when migrating to Java 7. As you may know if you read this blog, I’ve been playing these past few weeks with test framework and more precisely PowerMock. I also had to mess with the bytecode a bit myself because some libraries from ICN have dependencies missing and can not be hot recompiled by PowerMock (rebuilding the byte code during Runtime).

Well what I did with the bytecode didn’t work with Java 7. After some researches, I discovered than the byte code verification has been enforced with Java 7, to avoid injection of malicious code via bytecode modification. This is good for production, but in test when we like to mess with bytecode to allow us some tricks, that’s not really helpful. Anyway after a while I discovered the option to disabled this bytecode verification. Of course I wouldn’t recommend using that in production, but it can be useful for test.

For IBM JDK, I didn’t find yet a way to fall back to the old verification engine, so for now I just disable it. Add this to your JVM arguments when running test.

-Xverify:none

For SUN JDK, there is an option to fall back to the old verification engine. Alternatively you can also disable the verification the same way that we do for IBM JDK. Here is the option:

-XX:-UseSplitVerifier

Continue reading

Get started with Selenium

Last post of a three posts series about testing, after Unit Testing and Integration Testing, let’s talk about UI testing.

Introduction

Selenium is a Browser driver, basically it does what you would do if you were manually testing, i.e. clicking, looking for elements, selecting, scrolling…, except it does it alone, and can do it for hours without a break, every night…

How it works is quite simple, you are targeting DOM elements (or node, or WebElement, or any name you would like to call them) with selectors, and then you can do various operations on those like a user would do: wait for them to be present, to be visible, to be clickable, click on them, drag and drop something, enter information in a text field, …

Keep in mind that Selenium does the same thing that you would do. So if an element is not visible on the page and you would scroll to catch it before clicking, you have to do the same with Selenium, or it will throw an exception saying the element is not clickable because it is out of the view, which makes sense.

This article is an introduction to Selenium, if you want more applied examples for ICN and Dojo, you can read this post, but I would recommend you to read this one first to get familiar with Selenium.

Get started with Selenium

Continue reading

How to install IBM CMIS

In its version 1.0, IBM CMIS was shipped as a separate application. But now, where can you get it and how can you install IBM CMIS? If you are looking for it in the Software Catalog from IBM, you won’t find it. And that’s normal because it is now part of IBM Content Navigator.

We’ll see how to install CMIS. You can follow this procedure when you install ICN, upgrade ICN, or even if you have already installed it, just re-open the configuration tool. The procedure start when you are starting the IBM Content Navigator Configuration and Deployment Tool. If you are installing/upgrading ICN, it will start by itself. If you have ICN already installed, you can launch this tool by running:
Continue reading

Recover a deleted Object Store on a P8 Platform

If like me, you are a really clumsy person, you may delete the entire Object Store on a stupid mistake. Don’t laugh, it happened to me. I was working with the FEM and I clicked without reading twice :). From the FileNet knowledge center, this is supposed to be an irreversible action. The truth is it’s not, thanks god because i could have been in real trouble! So if you don’t have snapshot of the platform before, or your backup is hard to restore, or you will loose to much data since the last backup, here is another solution.

This is a really nice trick to recover a deleted object store really easily. It can save you a lot of troubles too. It is really well explained in the link, but here is the procedure summarized.

Actually the deletion of an object store is an update like every other updates, therefore it can be undone by updating the FNGCD table of the GCD database, which store the last 100 updates. You just have to set he last_epoch_id of the line with the id 0, to the the value of the update before the deletion.

I have to thank so much my colleague for finding and then sharing this trick with me!

Test your ICN plug-in’s UI with Selenium

Lately I’ve been writing about test, and to finish this series of post, after unit tests and integration tests, I would like to talk about UI test. UI is not easy to test, because it requires a lot of user interactions. This is really important though, because UI tests make sure the final result, i.e. what the user sees, is what we want him to see. And as we all know, users remember mostly the UI defects 🙂

Update: I actually wrote an introduction on how to use Selenium, this post is meant more to give example of uses of Selenium applied to ICN and indirectly Dojo.

Not long ago, to test web application, we were writing test cases and you or any other unlucky tester was validating all of them one by one, and it was taking ages. Thanks god, there is nowadays better solutions, meaning lazy automatic solution. I will introduce in this post how to use a Web Browser automation tool to test ICN and your plug-in. We will use Selenium, which I think is a great tool. This will be applied to ICN, you can find plenty of Selenium tutorials on the web anyway, We will see how to automate basic action, like login, logout, create a folder, a document, file a document, accept message dialog. Then it will be up to you to adapt all this to your plug-ins.

Here is a quick video to give you an idea of what can be done with Selenium and ICN.

Continue reading