-
Notifications
You must be signed in to change notification settings - Fork 209
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] Kotlin support / extensions #1293
Comments
Can it be achieved without providing full-fledged Kotlin API? |
Yes, because Kotlin is forward and backward compatible with Java, you can include only a set of Kotlin modules within a Java project. Although, because Kotlin is designed to be so compatible, any Kotlin API can be consumed by Java/Scala/Groovy code, eg: Here for demonstration purposes we use Kotlin features such as declaration site variance, inheritance via delegation, and extension functions. Then this code is easily interfaced with from Java without any friction at all. // utils.kotlin
// unmodifiable collection types, null safe types, declaration site variance, inheritance via delegation
class Foo<T>(val data: MutableList<out T>): List<T> by data
// extension function
fun Locator.doSomething(value: String) { } // Bar.java
public class Bar {
List<Integer> myList;
Locator myLocator;
void something() {
Foo<Integer> foo = new Foo<Integer>(myList);
System.out.println(foo.get(1));
doSomething(myLocator, "hello");
}
} |
This code has to be compiled with Kotlin going forward and trying to feed it into javac will fail, which essentially means switching Playwright to Kotlin or am I missing something? |
I wonder if it wouldn't be better to publish a bunch of Kotlin extension functions as a separate module. Where I would see most benefit by providing options as extension function literals, e.g. instead of playwright.chromium().launch(BrowserType.LaunchOptions().setHeadless(false).setSlowMo(500.0)) you could write playwright.chromium().launch {
headless = false
slowMo = 500.0
} I guess with a little bit of classpath scanning and something like KotlinPoet you may even be able to generate such extensions functions from the existing API. |
Well, in a gradle project, you can take an existing java project, remove the |
Something like KotlinPoet would be nicest, but here's a "typed builder" way to get most of what it sounds like you are looking for. This uses is a new function "options()" which works for any playwright Option argument: Usage of "options() builder"val browser = playwright.chromium().launch(options {
// note that command completion of option variables works here
headless = false
args = listOf("--allow-file-access-from-files")
})
OptionsBuilder.ktinline fun <reified T> options(noinline init: T.() -> Unit): T? {
if (init == NOOP) {
return null
}
val options = T::class.java.getDeclaredConstructor().newInstance()
options.init()
return options
}
object NOOP : (Any) -> Unit {
override fun invoke(p1: Any) {
throw RuntimeException("This line should never be reached under normal use")
}
} I use the NOOP for creating extension functions with an optional argument for the "Options" object builder) like the following (though there might be a cleaner way to deal with the no-op situation): fun Locator.shouldBeVisible(init: IsVisibleOptions.() -> Unit = NOOP) = assertThat(this).isVisible(options(init))
//Usage:
@Test
fun `show shouldBeVisible example`() {
//given
val page = ...
//when
page.navigate("https://www.google.com")
//then
// (with no options passed in to shouldBeVisible() )
page.getByRole(BUTTON, options { name = "I'm Feeling Lucky" }).shouldBeVisible()
// or (with options passed in to shouldBeVisible() )
page.getByRole(BUTTON, options { name = "I'm Feeling Lucky" }).shouldBeVisible { timeout = 2000.0 }
// or (introducing another extension function, which would likely live in some supporting file)
fun Page.getButtonByName(buttonName: String) = getByRole(BUTTON, options { name = buttonName })
page.getButtonByName("I'm Feeling Lucky").shouldBeVisible()
}
|
Kotlin is a very popular JVM language, and playwright could expose some Kotlin extensions that augment the existing API.
A small example would be
infix
/operator
functions foror
andand
:Because Kotlin is backwards compatible with Java, it's a possibility that this entire library could be converted to Kotlin, and there would be no disruption to end users using Java (or Scala, or Groovy etc).
The text was updated successfully, but these errors were encountered: