Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature idea: should() for JavaScript executions #1750

Open
flange-ipb opened this issue Mar 7, 2022 · 3 comments
Open

Feature idea: should() for JavaScript executions #1750

flange-ipb opened this issue Mar 7, 2022 · 3 comments

Comments

@flange-ipb
Copy link

flange-ipb commented Mar 7, 2022

Hi again!
Well, I fell in love with should() and Conditions in combination with soft assertions and almost got rid of all asserts in my project. The only situation in which I still need a JUnit assert is when I need to check results of a JavaScript execution, so my idea would be something like this:

executeJavaScript(jsCode, args).shouldBe(condition)

where condition could be something like equals(otherObject) (invoke Object.equals()) or even the text-related conditions like Condition.text("something").
What do you think?

@asolntsev
Copy link
Member

@flange-ipb Yes, probably it's a great idea. I like the power of JavaScript - it allows to do many things that are not possible with pure webdriver.

Can you please bring some example of jsCode?
I want to understand concrete cases better.

@flange-ipb
Copy link
Author

Hi @asolntsev!
I had a second thought on my specific problem and noted that the data I require is also written to a hidden input element. Nevertheless, this feature is interesting and I'm happy to share my ideas.

The concrete use case:
I'm writing a page object abstraction for a JSF custom component, which embeds a JavaScript chemical structure editor. Here is an example of what the component renders (including the hidden input field and a callback that fills it onchange, which is required for JSF's postback) and here is the JS facate for one of the editors (I wanted to assert on what getMolecule() returns). My page object implementation can be found here: The moleculeShouldBe() method now asserts on the imput element - my initial thought was to assert on the outcome of getMolecule(). The common data format these editors use are Molfiles (flat file with positions of atoms and bonds in between them).
Now, a test of the application could be the following: Input a molecule (invoking setMolecule() on a chemical structure editor component; letting Selenide click the molecule in the editor would be too complicated), store it in the database, do a search, select a result and compare the Molfile from the result with the initial one. The Molfiles are not necessarily equal by string comparison, which is why I already started implementing a custom Condition (MolfileMatchesCondition).

Back to Selenide!
A few other examples:
long result = executeJavaScript("return 1+1;");: assert that result is 2
Map<String,Object> result = executeJavaScript("return {abc:\"def\"};");: assert that the value for result's key "abc" is "def"

API ideas:
The type returned by Selenium's executeScript() is rather loosely defined and Selenide casts it to a generic type, which is resolved by the left side of the assignment in the examples above. That means the execution result and the condition has to be typed too. This makes it somewhat different to the SelenideElement and Condition APIs.
A method signature could be something like this:

JavaScriptExecutionResult<T> executeJavaScript(...)

where JavaScriptExecutionResult<T> offers methods like

JavaScriptExecutionResult<T> shouldBe(JavaScriptExecutionResultCondition<T> condition)

Selenide could offer a few basic conditions for the relevant types, e.g.

  • JavaScriptExecutionResultCondition<Long> longValue(long expected)
  • JavaScriptExecutionResultCondition<String> text(String expected)
  • JavaScriptExecutionResultCondition<Boolean> trueValue
  • for Map<String,Object>: conditions on JSON???

Coping with the situation when executeScript() returns a WebElement (e.g. via returning a jQuery selection) might also be interesting, because you could go back to the existing Condition API, maybe by wrapping a Condition into a JavaScriptExecutionResultCondition<SelenideElement> object.

Notes:

  • I guess it's not a good idea to break the existing method signature of executeJavaScript() by returning a different type.
  • I'm not really good in inventing short and precise class names. ;)

@asolntsev
Copy link
Member

@flange-ipb Thank you for sharing idea! It's a valuable contribution. :)

The question arises, how is the first option better than the second?

  1. executeJavaScript("return 1+1;").shouldHave(longValue(2))
  2. assertThat(executeJavascript("return 1+1;")).isEqualTo(2) // using AssertJ or JUnit or TestNG standard assertions

Usually Selenide should* methods are better than standard assertions because

  1. They can wait if needed
  2. They take a screenshot if assertion fails

But is it needed to wait and take screenshot in case of JS checks?
I don't know... Probably.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants