Masquerade - Regression Testing Automation for CUBA

masquerade
testing

(Yuriy Artamonov) #1

I’m proud to announce our new Open Source tool! Masquerade - testing library for CUBA-based applications.

masquerade-announce

Masquerade is a set of libraries for automating user interface testing and ensuring regressions get caught. You can easily build tests that catch everything from UI changes to database quirks, maintain the test in any JVM language and run them manually or in your CI environment.

The library provides an ability to create UI tests for CUBA-based applications using masquerade-web module. Also, you can create REST-API tests with masquerade-connector module.

Essentially, masquerade is based on well-known libraries such as selenium and retrofit2 and brings a lot of features for testing of CUBA applications. It makes it easier to start writing UI tests without hustle.

If we look closely enough we will see that UI tests could be simple and expressive:

public class LoginWindowTest {
    @Test
    public void loginTest() {
        open("http://localhost:8080/app");

        LoginWindow loginWindow = Components.wire(LoginWindow.class);

        loginWindow.loginField
                .shouldBe(EDITABLE)
                .shouldBe(ENABLED);

        loginWindow.loginField.setValue("admin");
        loginWindow.passwordField.setValue("admin");
        loginWindow.rememberMeCheckBox.setChecked(true);

        loginWindow.loginSubmitButton
                .shouldBe(VISIBLE)
                .shouldBe(ENABLED)
                .shouldHave(caption("Submit"));

        loginWindow.loginSubmitButton.click();
    }
}

And no HTML magic required!

We are already using masquerade tool suite for the platform itself. Moreover, it is used in products and projects that we are building at Haulmont for almost a year now.

You can learn more about masquerade on Github and in the demo project.

If you have any questions feel free to ask them here on forum.

Find regressions before your users do!


(Ray Offiah) #2

Decent set of instructions. Got it working surprisingly quickly. Here’s what the test looks like when converted into Kotlin:

import com.haulmont.masquerade.Components
import org.junit.Test

import com.codeborne.selenide.Selenide.open
import com.haulmont.masquerade.Conditions.*

class LoginWindowTest {
    @Test
    fun loginTest() {

        doLogin()
    }

    private fun doLogin() {
        open("http://localhost:8080/app")

        val loginWindow = Components.wire(LoginWindow::class.java)

        loginWindow.loginField?.shouldBe(EDITABLE)?.shouldBe(ENABLED)

        loginWindow.loginField?.value = "admin"
        loginWindow.passwordField?.value = "admin"
        loginWindow.rememberMeCheckBox?.isChecked = true

        loginWindow.loginSubmitButton
                ?.shouldBe(VISIBLE)
                ?.shouldBe(ENABLED)
                ?.shouldHave(caption("Submit"))

        loginWindow.loginSubmitButton?.click()
    }
}

I probably should’ve left it as Java …


(Yuriy Artamonov) #3

I’d recommend introducing get methods for Composite fields and then rewrite code in more idiomatic way:

class KotlinLoginTest {

    @Test
    fun test() {
        open("http://localhost:8080/app")

        val loginWindow = Components.wire(LoginWindow::class.java)

        loginWindow.apply {
            loginField
                    .shouldBe(EDITABLE)
                    .shouldBe(ENABLED)

            loginField.value = "masquerade"
            passwordField.value = "rulezzz"

            rememberMeCheckBox.isChecked = true

            loginButton
                    .shouldBe(VISIBLE)
                    .shouldBe(ENABLED)
                    .shouldHave(caption("Submit"))

            loginButton.click()
        }
    }
}

(Ray Offiah) #4

Yeah, that looks better. I’ll give that a try.

Thanks.


(Ray Offiah) #5

How did you set up the composite fields?


(Ray Offiah) #6

Okay, managed to get it working by setting up the fields like this:

package com.willowparkmedia.peertest

import com.haulmont.masquerade.Components
import com.haulmont.masquerade.base.Composite
import com.haulmont.masquerade.components.*
import org.openqa.selenium.By

class LoginWindow : Composite<LoginWindow>() {

    val loginField: TextField = Components.wire(TextField::class.java, By.cssSelector(".c-login-username") )
    val passwordField: PasswordField = Components.wire(PasswordField::class.java, By.cssSelector(".c-login-password"))
    val rememberMeCheckBox: CheckBox = Components.wire(CheckBox::class.java, "rememberMeCheckBox")
    val loginSubmitButton: Button = Components.wire(Button::class.java, "loginFormLayout", "loginButton")

}

(Yuriy Artamonov) #7

TL;DR Use approach mentioned below: Masquerade - Regression Testing Automation for CUBA

Don’t do this. It is ugly and you lose many features of automatic injection.

Just define composite in the following form:

class LoginWindow : Composite<LoginWindow>() {
    @field: Wire
    private var _loginField: TextField? = null

    val loginField : TextField
        get() = this._loginField!!
}

(Ray Offiah) #8

Mmmm. I think we’re going to have to agree to disagree on that one.

Your solution needs two fields for each component, and one of those is still a nullable.

Mine is less lines and uses immutable objects which I prefer, though It does mean I need to set ids and/or classes on the components I need to reference.


(Yuriy Artamonov) #9

Unfortunately, it requires a lot of boilerplate instead of declarative syntax


(Ray Offiah) #10

And the private field has to share the name of the cuba id on the element for this to work, so I think the private var field has to be called loginField


(Yuriy Artamonov) #11

I’ve found the best approach! lateinit modifier!

class LoginWindow : Composite<LoginWindow>() {
    @field: Wire
    lateinit var loginField: TextField
}

(Ray Offiah) #12

Yes! That’s the one! I didn’t know about the lateinit!

Thanks for sticking with this.


(Fala70) #13

if I want test menu item of main app shouldBe(VISIBLE) . How can I do it ? I want test if showed an item menù when I login with differents users roles. If present I can using :slight_smile:

 _$(AppMenu.class).openItem("administration", "sec$User.browse");

but if menu administrator is hidden how can I test ?


(Yuriy Artamonov) #14

Hi,

There is no such feature for that yet, so welcome to the issue tracker: https://github.com/cuba-platform/masquerade/issues


(Fala70) #15

Can you provide a sample how use a table UI ? For example check existing columns and row cell navigation to check values


(Yuriy Artamonov) #16

Hi,

We have just added a small tutorial on Tables: https://github.com/cuba-platform/masquerade/wiki/How-to-work-with-tables


(Markus Ott) #17

Hi,

I’d like to know if there is also a recorder functionality available with this addon? This would be great for our testing guys as they don`t want to be bothered with coding ;-). Or is there an integration with the regular Selenium IDE?

Thank you.

Best regards,
Markus


(Yuriy Artamonov) #18

Hi,

The main focus of the library is coding, simple and convenient code for tests. That’s why we are not planning to implement a recorder or visual tool for now.


(Markus Ott) #19

Hi Yuriy,

alright, thank you for the quick reply.

Best regards,
Markus


(Yuriy Artamonov) #20

Just to clarify, the idea of visual tool for testing is great. Unfortunately, it requires a lot of resources. We will see if we can go in this direction in the future.