Selenide, I think this is the beginning of a beautiful friendship

Selenide, I think this is the beginning of a beautiful friendship

Β·

20 min read

As I promised we will start coding in this section as soon as possible. In case you missed my previous article, I highly recommend reading it beforehand, as I have provided many reasons why you should give Selenide a try.

Setup

  • You will need the Java Development Kit. I suggest getting the latest Open JDK 17.
  • As an IDE I am using IntelliJ IDEA, but you can use anything you like. Besides IntelliJ, Eclipse and Visual Studio Code are the most popular ones.
  • For source code management I use Git, you can find the project on GitHub.
  • I usually use Maven for Java projects, but this is the perfect opportunity to learn something new, so I will use Gradle this time. In case I make any stupid mistake with Gradle, do not hesitate to tell me πŸ˜‰
  • As Java testing framework TestNG and JUnit are the most popular ones. I will go with TestNG but I will provide the required info for JUnit 5 as well. That's all you will need for the project.

Let's continue with creating a Gradle project and openening the build.gradle file. Let's add the dependencies:

dependencies {
    testImplementation 'org.testng:testng:7.5'
    implementation 'com.codeborne:selenide:6.2.1'
    implementation 'org.seleniumhq.selenium:selenium-java:4.1.1'
}

For JUnit:

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
    implementation 'com.codeborne:selenide:6.2.1'
    implementation 'org.seleniumhq.selenium:selenium-java:4.1.1'
}

Specify to use TestNG:

test {
    useTestNG()
}

for JUnit:

test {
    useJUnitPlatform()
}

We are ready to go. Only one question remains. Which site will we test?

Have you ever enrolled in a highly rated course to learn about test automation just to realize half of the pages which were used as examples in the course are not existing anymore or have been changed completely? Well, it happened to me. My choice is (almost) all developers' second favourite site (right after Google) Stackoverflow. My third favourite is Baeldung if you are interested 😊. I am pretty sure Stackoverflow won't disappear in the near future, but of course, I cannot guarantee it won't change its design.

It is time to write our first test. Yayyy. Let's start with something simple.

Open Stackoverflow

Using Selenide you do not have to use the WebDriver directly as it is automatically opening and closing the browser for us using Chrome by default. We can open the page with one single line without any extra configuration.

@Test
public void openPage() {
    open("https://stackoverflow.com/");
}

Just run the test and you will see Stackoverflow opening and then closing immediately. Whenever I develop and look for DOM elements, I prefer to open the same page in my browser in incognito mode so I can see exactly the same result I would see whenever I open it via Selenide. Let's do this now.

Stackowerflow homepage

The first thing I notice is that we have an accept cookie banner on this page. As in these days, we have something similar on every website, let's accept the cookie. But before that let's finish our first test. Every worthwhile test should check some conditions.

Checking visibility and enabled state of elements

Of course, we could select many conditions to test, but in this case, I will concentrate on demonstrating the different ways of Selenide condition checking. Let's verify we have a visible Login and a Sign up button. In order to do that, first, we have to find the element. Looking at the DOM in Chrome dev tools (or of course, you can use Firefox or other tools if you prefer that) we can see that the Login button is actually a link. It has no id, but it has a class login-link which seems unique. So I could use a simple CSS selector or even an id based selector. But is it really unique?

If you watch carefully, you can notice despite its name, the Sign up link has the same login-link class as the Login button, so I will have to select based on an index. For that purpose, I am using XPath (in general prefer CSS over XPath as it is faster).

Stackoverflow Sign Up link source code

You might think we should use the text to find the element as it is unique, but I do not recommend that as according to my experience texts are changing more often than ids and classes, not even talking about testing with different languages.

Let's write the selector:

$x("(//a[contains(@class, 'login-link')])[1]");

It is very simple, concise and straightforward. You can use $(String cssSelector), $$(String cssSelector) to find an element($) or elements($$) by CSS. Similarly, you can use $x(String xpath) and $$x(String xpath) to find elements using XPath. Of course, you can use the built-in Selenium By commands also, using $(By) and $$(By). Selenide even provides new selectors in addition to the normal Selenium selectors like byText, withTextand byAttribute.

In case you are not familiar with the basic Selenium selectors, I recommend again Rahul Shetty's Udemy Course on Selenium. You will have a good grasp of them after finishing the course. One additional resource which is quite good for beginners is CSS Dinner.

Now that we have the element which is a SelenideElement (subclass of WebElement) we can verify its visibility:

$x("(//a[contains(@class, 'login-link')])[1]").shouldBe(visible); It is easy to read this code. Actually writing it is also easy and fun. πŸ˜€ You could ask what happens in case the element is not immediately present in the DOM, or what if it is present but it needs some time to become visible? Selenide uses implicit waits both during finding elements and also during evaluating conditions. The default is 4 sec, but it can be configured. The should functions (should, shouldHave, shouldBe, ShouldNot, shouldNotHave, shouldNotBe) even have an overloaded version which also accepts a Duration to specify the timeout explicitly.

You can run your test from your favourite IDE, or you can run it from the command line using Gradle:

gradlew test

Simply change the "visible" to "enabled" to check the enabled state of an element:

$x("(//a[contains(@class, 'login-link')])[1]").shouldBe(enabled);

Based on the previous example it is quite easy to write the verification for the Sign Up link:

$x("(//a[contains(@class, 'login-link')])[2]").shouldBe(visible);
$x("(//a[contains(@class, 'login-link')])[2]").shouldBe(enabled);

Let's refactor

Before moving on, let's do some refactoring, so we can make the code cleaner and we can get one step closer to the Page Object Model about which I will write in a later article. Let's do 2 things. First, extract the Login and Sign Up elements as constants using meaningful names. In case you are worried about locating an element before the page even exists, then I have some good news for you. Selenium (so also Selenide) use lazy initialization which means the elements will only be located, whenever you call some methods on them. Second, we will use method chaining to get a more concise code. I really like this technique as you will see it in later articles. So here is the code after refactor:

public class HomepageTest {

    private final SelenideElement loginLink = $x("(//a[contains(@class, 'login-link')])[1]");
    private final SelenideElement signUpLink = $x("(//a[contains(@class, 'login-link')])[2]");

    @Test
    public void openPage() {
        open("https://stackoverflow.com/");
        loginLink.shouldBe(visible).shouldBe(enabled);
        signUpButton.shouldBe(visible).shouldBe(enabled);
    }
}

Finding elements based on text

As I promised, we will get to the cookie banner soon. Just one more thing before that. As I said it is not the best idea to locate elements based on texts, but sometimes you simply have no other options (of course you can find everything with absolute xpath expressions, but that is a horrible idea as it will break on the slightest change of the UI), or you have to check if elements have a certain text. This time we will stick to English but later I will write an article about internationalization.

Let's find the link with the text "About" and verify whether it is pointing to the right location.

We can choose from a couple of options here:

Finding using XPath

$x("//a[text()='About']");
$x("//a[contains(text(), 'bout')]");

You can check for exact matches or partial matches with XPath.

Finding using linkText or partialLinkText

$(By.linkText("About"));
$(By.partialLinkText("bout"));

You can find the element using the standard Selenium locators.

Find using byText and withText $(byText("About")) $(withText("bout"));; You can also find an element using Selenide locators. byText is similar to linkText as it finds an element using an exact match for the text, and withText is similar to partialLinkText as it checks whether the element's text contains the given text or not. But there is a huge advantage here for Selenide: it works with every kind of element, not just with links.

This is quite simple:

aboutLink.shouldHave(href("/company"));

I highly recommend checking the Conditions class's documentation, so you can get a good grasp on the different conditions offered by Selenide.

Closing the banner

Finally, we arrived at the last topic of today's article which is accepting the cookies. Let's create another test called acceptCookies. First, let's find the accept button:

Stackoweflow source code part for accept cookie button

Looking at the page source we can see it is a button that we have to click and it has a class js-accept-cookies which can identify the button. So we can easily find it by class name:

$(byClassName("js-accept-cookies"));

After finding the button we can click it by simply using the click() method on it as we could have already learnt it using Selenium.

acceptCookiesButton.click();

In case the test does not fail we can tell we were able to click the accept cookie button, but to be on the safe side let's verify whether the banner has really disappeared. The banner is a div having a class js-consent-banner. In order to verify it is not there anymore we can use the shouldNotBe method:

private final SelenideElement acceptCookieBanner = $("div.js-consent-banner");
.
.
acceptCookieBanner.shouldNotBe(visible);

or you can write:

acceptCookieBanner.shouldBe(hidden);

Actually should, shouldBe and shouldHave are synonyms similarly to their counterparts shouldNot, shouldNotBe, shouldNotHave. They are interchangeable and also there are many synonyms among the conditions, so basically it is up to you which you find more readable. These examples mean the same:

acceptCookieBanner.shouldBe(hidden);
acceptCookieBanner.shouldNotBe(visible);
acceptCookieBanner.should(disappear);
acceptCookieBanner.shouldNot(appear);

I prefer not using negation so I am going with shouldBe(hidden).

Finishing touches

Before we finish let's do 2 more refactors to reduce duplication and to make the code even simpler.

As we are testing the same homepage in these tests, we can move the page opening to a common part that executes before each test. In TestNG you can use the @BeforeMethod annotation for this, using JUnit 5 the @BeforeEach will be your solution. To get a good comparison of the usage of the two frameworks, check this article on Baeldung.

When verifying the Login and Sign Up link we used 2 chained shouldBe methods to verify whether the component is visible and enabled. Actually, you can merge them into one call, as the should methods can accept multiple conditions.

This is the final code:

public class HomepageTest {
    private final SelenideElement loginLink = $x("(//a[contains(@class, 'login-link')])[1]");
    private final SelenideElement signUpLink = $x("(//a[contains(@class, 'login-link')])[2]");
    private final SelenideElement aboutLink = $(byText("About"));
    private final SelenideElement acceptCookiesButton = $(byClassName("js-accept-cookies"));
    private final SelenideElement acceptCookieBanner = $("div.js-consent-banner");

    @BeforeMethod
    public void setup() {
        open("https://stackoverflow.com/");
    }

    @Test
    public void openPage() {
        loginLink.shouldBe(visible, enabled);
        signUpLink.shouldBe(visible, enabled);
        aboutLink.shouldHave(href("/company"));
    }

    @Test
    public void acceptCookies() {
        acceptCookiesButton.click();
        acceptCookieBanner.shouldBe(hidden);
    }
}

It looks neat, don't you think? 😊

And that's all. We have finished today's lesson. I hope you enjoyed it. Don't hesitate to share your thoughts about this article and suggest topics for upcoming ones. In the next post, I will develop tests for Stackoverflow's Questions page.

πŸ“š Before we finish, I give you an assignment. I used XPath to find the Sign up link. Write a CSS selector (not using the text of the link) to find the Sign up link! Please do not post your solution immediately, give some times to the others. So I ask you to post your solution on Monday❣️

Something good will happen to you today... ❀😊

  • Minnie: Miki, the movie is over. We should go home.
  • Miki: Not yet Minnie, not yet?
  • Minnie: Why? I have to pee.
  • Miki: Because since Marvel started to put teaser trailers after the cast list I always stay till the end.
  • Minnie: Do you think we will see a little teaser here?
  • Miki: We will see Minnie. We will see. 😊

Are you blogging on Hashnode? Yes? Cool. No? What are you waiting for? Hashnode is my number one blogging platform as a developer.

Please use my referral link to join Hashnode and become a Hlogger (Hashnode Blogger)!. I do not get anything for it as I already became a Hashnode Ambassador by referring 3 of my friends, but it would be awesome to see how many people I have inspired to start blogging. 😊

In case you want to understand why Hashnode is the best developer blogger platform, just read my My First Month on Hashnode - A Retrospection About Blogging on Hashnode Developer Journaling Platform by Miki Szeles harticle (Hashnode article)!

In case you are still not sure why you should start blogging, please read my harticle:
Start writing now! Seriously! is the first harticle in the series in which I share my learnings, which can be valuable for newcomers and advanced bloggers.

Github: https://github.com/mszeles/selenide-tutorial

My credo: The Mystery Of The Supposedly Red ❀ Emoji AKA The Story Of How I Became A Software Developer Detective To Debug The Internet Read my story, in case you would like to understand how I think and act as a developer and tester in the real world. You can get some insights about my humour, and I am also happy to tell you that, this is my article about which I am the proudest of now.

In case you do not want to miss my posts, just follow me here on Hashnode, on LinkedIn, on Twitter on Medium.com, on dev.to, on Hackernoon and even on Instagram. 😊

Contribute to the open-source Selenideium Element Inspector Chrome Extension, with which test automation teams can save hours daily by automatically generating all the relevant selectors for Selenide, Selenium, Cypress, Playwright, Squish and TestCafe.

Follow the Selenideium Element Inspector Twitter channel to get updated on the latest happenings regarding Selenideium, to get help, to share your experience and also to talk about any (test automation) related topic! 😊

Join the Selenide User Group on LinkedIn to connect with more than a hundred test automation engineers and learn and get help regarding the most astounding e2e test automation framework: Selenide.

Join the Selenideium Element Inspector Bounty Hunting Reward Program and earn β˜•s by contributing to this open-source project. πŸš€ This is the perfect opportunity to make the first step into open-source contributing, and also in case you would like to learn about JavaScript and Chrome extension development. 😊

I am building a friendly, supportive, knowledgeable community around Selenideium. I did not dare to contribute to any open source project for a very long time. I was afraid that the developer community would take my code and myself into parts. And to be honest, seeing the sad fact that there are rude and ignorant people in the dev community too, most probably that is what has had happened back then.

This is why I guarantee that Selenideium Element Inspector is the perfect project to start your open-source contribution; I will also make sure it will stay like that. No matter how genius you are, if you do not respect the community members, this project is not for you.

To show my gratitude and motivate you, I will invite you for β˜• for every contribution.

I will even give a shoutout to you both on Selenideium and on my personal Twitter accounts in case you contribute.

Selenideium Element Inspector Bounty Hunting Reward Program.png

  • Minnie: Pst, Miki. Are you here?
  • Miki: Sure, I am always staying here till the end of the cast list since Marvel starting to put teaser trailers at the end of its superheroes movies. Minnie: Me too.
  • Mictor: Teaser trailers are such an art. And mustard of course.
  • Manaly: According to British Scientistisch only 20% of movie lowers see those Marvel teaser trailers. Minnie: Really?
  • Manaly: No, I was just joking around.
  • Miki: I am the funny guy here.
  • Nikolai: Yeah, sure Miki. You are the funny guy here. Sure.
  • Nikolai: Teaser trailers are for pu*sies!
  • Miki: Yeah, sure Nikolai, sure.
  • Minnie: So what should be our teaser trailer?
  • Miki: In the last few days I started to work on my greatest contribution to the open-source community?
  • Minnie: Oh. Really. That is why you had no time to talk to me.
  • Nikolai: He never has time to talk with us.
  • Miki: Except 0/24.
  • Minnie: So is this project belonging to your Humanity Theorem with which you came up a few years ago.
  • Nikolai: You miserable failed with The Humanity Theorem, as it was Flawed.
  • Miki: Yes you are right, Nikolai. But since then you Minnie, Uncle Nikolaus, Mictor, Manaly and Good Old Mother Grammarly Premium are here so we make not just our harticles technicalish, but also we will revisit The Humanity Therom.
  • Minnie: So what is the goal of The Humanity Project? Why did you create it?
  • Miki: Funny story. I was looking for my favourite code snippet for my harticle called My All-Time Top 3 Favourite (IT) Recruiter AKA Dear Fellow Developers, Dear (IT) Recruiters! I Would Like to Ask a Favour From You AKA The Perfect Matchish (IT) Opportunities AKA The Big Refactor.
  • Minnie: Wow. That is a lot of AKA.
  • Nikolai: No people will click on it.
  • Mictor: Such masterpiece.
  • Manaly: We will see, Nikolai. We will have the whole analytics thanks to Google Analytics and Bit.ly.
  • Minnie: So what is The Humanity Project about?
  • Miki: It is about the Miracle of Life.
  • Minnie: That sounds fantastic, but can you please explain it?
  • Miki: Sure. I do believe this will be the greatest open-source project in the world.
  • Nikolai: You are cooky. I like it so much.
  • Miki: Let me continue. I would like to build the greatest Humanisch Intelligence in the world.
  • Minnie: Sound interesting. Go on.
  • Miki: I do believe this will be the first-to-go open source project in the world.
  • Minnie: Based on what do you think that?
  • Miki: As this will be the first open-source project to which kids can contribute as soon as they can talk.
  • Minnie: What? Really?
  • Miki: Yeah.
  • Minnie: How?
  • Miki: The Humanity Project is a life simulation.
  • Minnie: Really. I am so interested.
  • Miki: And it is not just a life simulation, but all single person in the world can implement his/her/itself via a Java class.
  • Minnie: What????
  • Miki: As I said. Kinds (and adults too) can create their own implementation.
  • Minnie: I see what is it good for?
  • Miki: First of all to learn programming in a fun and easy way.
  • Minnie: What else?
  • Miki: I believe it will be the first-to-go project to learn clean code.
  • Minnie: Sounds ambitious. Why do you think that?
  • Miki: As I have put my 15+ years of software development knowledge in it.
  • Nikolai: British scientistich have proven there is no relationship between years spent with software development and experience.
  • Miki: Sure Nikolai.
  • Minnie: I have no doubts about your expertise, but I still think it won't be enough to be the first-to-go open s-source project in the world.
  • Miki: Yeah, I think so, but as it is an open-source project the whole humanity can contribute to it. Minnie: Fair enough.
  • Minnie: Still clear this will be not enough.
  • Miki: Yeah, but I have a jolly joker in my hands.
  • Minnie: Really? What is it?
  • Miki: My code is full of comments.
  • Mikolai: Nobody reads comments.
  • Miki: That is true, but this time it will be different.
  • Minnie: Why do you think that?
  • Miki: Because they are not simple comments but it is a conversation with my technicalish creative writing team which means Minnie, Nikolai, Uncle Nikolaus, Mictor and Manaly.
  • Minnie: Wow. What about the Good Old Mother Grammarly Premium?
  • Miki: Well, she is not there?
  • Minnie: Why?
  • Miki: As she cannot work in IntelliJ IDEA.
  • Minnie: Ouch. Where is the link to the feature request Miki?
  • Miki: Here it is. Please upvote. πŸ‘
  • Minnie: So what else you can offer?
  • Miki: I do believe this will be the first-to-go open-source project to learn frontend development via Angular (not AngularJS), backend development via Spring, REST APIs, End to End Test Automation, API test automation, Performance testing, Data Analysis and also Security.
  • Minnie: Wow that is quite ambitious. Why do you think that?
  • I have written everything in the project's readme.MD.
  • Miki: Well the project is still private and has no commits yet and also the readme.MD is not ready yet, but this is the right time to publish it, as I will finish the readme today anyway. Click here, and continue the discussion!.
  • Nikolai: No one will comment there, as people do not like to start conversations. It is a well-known fact proven by British Scientistisch.
  • Miki: They will.
  • Minnie, Nikolai: Why are you so confident?
  • Miki: Because they won't be the one who starts the conversation?
  • Minnie: Who will be then?
  • My technicalish create writing team you Minnie, Nikolai, Uncle Nikolaus, Mictor and Manality and of course me.

  • Minnie: What if this is still not enough?

  • Miki: I will also give a shoutout to all contributors both on The Humanity Project Twitter channel, and also on my personal Twitter account.
  • Nikolai: The humanity project has no Twitter channel.
  • Miki: You are right, but Minnie is just creating it. Just wait a few seconds.
  • Minnie: I am ready, here is the link to the Humanity Project Twitter channel:
  • Minnie: What if this is still not enough?
  • Nikolai: We should trick them by asking for money in exchange for their contribution. That trick always works like in Mark Twain's Tom Sawyer.
  • Miki: Well that is a great idea. Not because we need the money for living, and not because The Humanity Project is a zero-cost worldwide project, but because I promise I will invest all those money in humans, I will invest the money in the contributors, who contribute to Humanity with their work.

Dear Fellow Human! I would like to kindly ask you if you are a non-for-profit contributor, then please support The Humanity Project with some β˜•s to make sure we can convert coffee to code! I will give all the money to the contributors of The Humanity Project. Please click below to support the open-source Humanity Project by buying a β˜•!


Dear for profit organization! I would like to kindly as you in case you would like to kindly ask you to support The Humanity Project, which means supporting Humanity for the cause of creating a better world for our children.

Please contact me via email at human@thehumanityproject.live email address to discuss the details!

Minnie: I have doubts, but what if people start talking about The Humanity Project? How we will know about it?
Miki: I have started a discussion on GitHub.
Dear Fellow Human! We would like to kindly ask you, to click the button above and ask any question you want, we will answer all of them. We would also like to kindly ask you, to introduce yourself, provide your GitHub profile and tell us what kind of contributions we can expect from you. Thanks in advance.

  • Minnie: I think this time we did it. We have started something really good.
  • Miki: I do believe that, Minnie. I feel it from all my heart.
  • Minnie: Miki, basically you have created Tinder for the seekers of job opportunities, love, friendship, sport partner, teacher, open-source contributors and you also started something with which we can prove the Humanity Theorem.
  • Miki: Well, sort of.
  • Minnie: I know you are better at catchy titles, but please let me try this time!
  • Miki: Sure. Go on.
  • Minnie: So the name should be Tinder Reloaded.
  • Miki: I love the phrase reloaded, but I think Tinder would be pretty upset about it, they might even sue us.
  • Minnie: Really? Then it is your turn.
  • Miki: Just give me 15 minutes of cigarette break.
  • Minnie: Really? We will lose our readers by then!
  • Miki: You are right, I already have the name since yesterday. Here it is:


    Tinderisch Powered By Humaisch Intelligence!


  • Minnie: I love it. The AI buzzword is so fetishized nowadays, we should make the HI buzzword instead!

  • Miki, Minnie, Nikolai, Uncle Nikolaus, Mictor, Manality, MikolAI and Good Old Mother Grammarly Premium, MikolAI:


    HI Humanity!


  • Nikolai: No comment. Who is MikolAI anyway?
  • Miki: You will get to know it soon, Nikolai. They will get to know him soon.
  • Minnie: Unbelievable, but we are ready to publish. Just one more step.
  • Miki: What is it?
  • Minnie: We should ask our grammar expert Good Old Mother Grammarly, to correct the mistakes.
  • Miki: Not this time, Minnie. Not this time.
  • Minnie: Why?
  • Miki: Because we are also humans.
  • Nikolai: And? Nobody cares about that.
  • Miki: I do care about that, and I am pretty sure most humans of the world also care about that.
  • Nikolai: So why do we not correct the mistakes?
  • Miki: But we are humans too. We make mistakes, that is what makes us human.
  • Minnie: I think soo.
  • MikolAI: I would like to be a HI.
  • Mictor: Where is my mustard? I want my mustard. I need it to create the Humanity Project cover image.

  • Miki, Minnie, Nikolai, Uncle Nikolaus, Mictor, Manality, MikolAI and Good Old Mother Grammarly Premium, MikolAI:

    ** Dear fellow Humans! Something good will happen to you today! πŸŒπŸŒπŸŒŽπŸš€β€πŸͺπŸŒŒπŸ‘ΆπŸ˜Š

Did you find this article valuable?

Support Miki Szeles by becoming a sponsor. Any amount is appreciated!

Β