Once I created a web testing framework, which is actually a wrapper for Selenium, for a company that works with JSF.
The problem with JSF is exactly the one pointed by Elias in the first item in the list: it generates dynamic ID's for many elements. This prevents the burning of Firefox's Selenium IDE to run in the same way.
For example, if you do not set an ID for any page element, JSF will take care of it. A button on a form, for example, can end up as the id meuFormulario:j_id45674
(this can change from one execution to another) and a field in a dataTable tabela:0:nomeCampo
(does not change but is difficult to work).
To work around these issues, the solution was to use CSS and XPath selectors using the name
attribute for form fields and other attributes for images.
Finally, the solution I found was to create such a framework that, among other things, provided some methods that encapsulated selectors for standard enterprise components.
For example, every include record had a button with a specific class attribute, for example, botao-incluir
. In other cases, the button contained a specific image. So I created a class that all test classes could extend or import statically and use more or less like this (in Java):
public class CadastroCliente extends TestBase {
@Test
public void cadastrarCliente() {
type(campo("nome"));
type(campo("idade"));
click(botaoIncluir());
aguardar();
}
}
In JSF, the nome
field, for example, could have the ID generated as formCad:panel10:nome
. Then the campo()
method would actually return a selector like this:
css=input[id$=':nome']
The above selector is a CSS selector that looks for a input
element on the page whose id ends with :nome
.
The type
and click
methods that are in the sample code are selenium wrappers that I made specially adapted for the system in question.
The advantage of abstracting the original Selenium methods is that there was often some specific behavior that required special treatment. In that case, I simply tuned the Wrapper class without having to play the tests.
The aguardar()
method, for example, can automatically make checks on validation errors, of course, if there is a pattern followed throughout the system.