-
Notifications
You must be signed in to change notification settings - Fork 214
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] JUnit5 integration #1369
Comments
Looking at junit-playwright it appears that it currently closes Playwright after each test which is too aggressive, we'll need to align that with the requirements above. |
I don't think we can enforce this. It would be up to the end user how they configure it. I think all we can do is handle both situations (which is what junit-playwright currently does). However, we can make it so the same If I understand the requirements correctly the lifecycles should be:
Is my understanding correct? |
I didn't mean enforcing it, but rather provide implementation that only supports the execution model where tests from the same class are not expected to run in parallel. If someone intentionally tries to circumvent this, they are on their own. We can throw or print a warning in some obvious cases where we detect this.
We can also support second mode with parallelism at method level but I'd hold off from it for now to keep things simple.
We cannot do this as it would mean concurrent access to the same Playwright/Browser instance from more than one thread which is not supported by Playwright java.
Yes
It can be just thread local and reused by all tests running on that thread which can include multiple classes.
We can start with this for simplicity. Later it can be optimized to reuse the browser between more classes running on the same thread and requiring same browser configuration. E.g. if there are 3 test classes that require Chromium headless with default parameters, there is no need to close the browser between them. But if say one of the 3 classes contains tests that need to run in headed mode, we'll need to close browser and launch a new one for tests in that class. |
@yury-s I've started working on this and I think it will be fairly easy to support Your idea of using ThreadLocal makes things much simpler. When running with
Do you have a suggestion of what this should look like? |
At first glance, something like @UseBrowserFactory(CustomBrowserFactory.class)
@UseContextFactory(CustomContextFactory.class) public class CustomBrowserFactory implements BrowserFactory {
@Override
public Browser newBrowser(Playwright playwright) {
return playwright.chromium().launch(new BrowserType.LaunchOptions().setChannel("msedge"));
}
} public class CustomContextFactory implements ContextFactory {
@Override
public Browser newContext(Browser browser) {
return browser.newContext(new Browser.NewContextOptions().setViewportSize(1600, 1200).setLocale("ar‑AR"));
}
} And if no annotation is specified, use default ones. The default could create just chromium and a context with default parameters. We discussed this offline and feel like it'd be better than introducing another option for the browser/context configs when there are existing classes for that. WDYT? |
I like it. Do you think it would be worth it to make 1 interface called Also, I came across one downside of supporting concurrent access: |
I feel like it'd be easier to keep them separate but it's hard to tell without seeing it. We can toy with that and change to the one that we like more.
That's a good catch. This is only a problem if you want to run each test in parallel with the others. In that case, we can take same approach as in node.js and pretend that each of the tests runs in its own JVM process and run BeforeAll/AfterAll on each thread before/after corresponding tests. Doe that make sense? This is another argument in favor not running tests from same class in parallel, in that case we don't have the problem. Behavior would still differ from node.js where we rerun beforeAll (in a new test worker process) if any of the tests in the file fail. |
We'll need to talk about this some more because I'm not sure I understand. I'm not managing threads myself and letting JUnit handle all of that. Maybe there is a way to do this without having the BeforeAll/AfterAll repeat before each test. For now I won't worry about it.
Definitely understand. I guess I'm being a bit selfish here because I use full parallel a lot so I don't have to worry about splitting up test files just to get a faster run. I don't think we will make the 1.38 release. I think 1.39 would be doable assuming everything goes smoothly in reviews. |
Yeah, this needs more thought. I'll bring it up with the team next week, maybe someone has a better idea.
No rush here, 1.39 is totally fine. It's more important we do it right and don't repeat the regrets from other language ports. |
@yury-s is it necessary to call
but what's the downside? |
@yury-s question: Currently in playwright-java, is a user allowed to create multiple browsers with the same Playwright process? For example will this work with the sync api of playwright-java? Playwright playwright = Playwright.create();
Browser chrome = playwright.chromium.launch();
Browser firefox = playwright.firefox.launch();
// use both browsers one at a time. Or should they close one and then launch the other? |
If you are going to close playwright right away then technically it is not necessary. But at the very least as a good code practice let's keep
It is perfectly fine to create multiple browsers with the same playwright instance, this is no different than node.js. It is very difficult though to use such browsers simultaneously in java with synchronous API, in node.js promises enable users naturally mix calls to different browsers.
No. They can coexist without any issues. |
@yury-s, if a user requests a |
@yury-s, since @UseBrowserFactory
@UseBrowserContextFactory //use default for all tests except ones defined at method level
public class FooTests {
void test1(BrowserContext browserContext) {
// test will use the BrowserContext defined at the class level.
}
@UseBrowserContextFactory(CustomBrowserContextFactory.class)
void test2(BrowserContext browserContext) {
// test will use the BrowserContext defined at the method level
}
} |
I'd start with class level configuration only, we can support method level annotations later. In the default setup all tests in the same class use the same configuration which means that all Playwright/Browser/Context/Page factories are the same. Also I'd imply default Playwright/Browser factories if they are not specified explicitly and only UseBrowserContext annotation is present. |
@yury-s couple points of clarification here:
@Use //use all default factories
@Use(browserFactory = FirefoxBrowserFactory.class) // use custom browser but default browser context
@Use(browserContextFactory = CustomBrowserContextFactory.class) // use default browser but custom browser context
@Use(browserFactory = FirefoxBrowserFactory.class, browserContextFactory = CustomBrowserContextFactory.class) // use custom everything |
I like this. We just need a playwright-specific name for the annotation, something like |
@uchagani Let's hold off migration of the tests to the new fixtures for now. We just reviewed the APIs with the team and think that if we don't support config annotations right away, it may be difficult to get clients to use it in the future. We'd like to explore the idea of config annotations and see if it would make sense to introduce them from the very beginning. The main motivation is that in order to provide good ergonomics for things like tracing, we need a better control over the options and how browsers/contexts created. I understand that the back and forth movement may cause frustration, but we'd rather do a few iterations before the APIs are released to figure out which is the best for the clients. Hope you understand. |
@yury-s I understand. Can you please provide some requirements around what you would want for the config annotations? |
We were thinking about something like Config class in this change, which would combine playwright/context/browser/apirequest options as well as things like We'd love to also include The change hacks it on top of the existing factories but if we want to support tracing out of the box we'll likely need full control over the lifecycle of browser/context/page and what parameters are passed to their constructors. This will likely rule out extensibility with factories as they may try to pass conflicting options. I hope this clarifies things a bit. |
@yury-s a few questions and comments regarding the changes:
what is the typo? Do you mean it should be
The event you recommended is for custom launchers and we're not creating that. I'm not sure if there is a way to know when a thread is finished since I did a quick test and threads are reused (as you said). I do have an idea of how we can keep all playwright instances open until all tests are finished but this will be after the entire test run is complete (which is what I think you meant when you recommended that launcher event). I'll get started on that.
I believe you did this already in #1472 ? |
Yes. @jfgreffier already fixed it in #1486
Good point about launchers. Closing playwrights after all tests finish sounds good too, let's try that.
Yes. I thought about generating constants with the device names, but not sure yet. |
@yury-s, I think we may be able to make use of JUnit 5's Test Templates https://www.baeldung.com/junit5-test-templates. Maybe in a follow up release I can help with this too. |
@yury-s should this top-level option apply to both the BrowserContextOptions and the RequestOptions since they both have a |
If it fits our use cases then why not.
Yes, I'd apply it to both. For more granular control the user could still set context specific options. |
I'm not sure everything will be ready for 1.42 but here are docs and codegen PR microsoft/playwright#29406 docs |
We discussed wether we should try and release junit support for java in 1.42 or postpone it and decided to release it as an experiment. We debated if it would mean putting the classes under We still need to add some javadocs to |
Codegen for JUnit Fixes microsoft/playwright-java#1039 Following JUnit5 integration microsoft/playwright-java#1369
@jfgreffier I've just merged the codegen PR. For the docs, let's introduce a new page for JUnit integration and have a prominent marker at the top of it that it is experimental for now. This way we can keep all existing docs as is and add links to the new JUnit guide to let more adventurous people try it while leaving us some leeway to change the API if needed. |
@jfgreffier thanks for writing the doc for playwright.dev, very god one, I approved the PR. @uchagani @jfgreffier do you want to take a stab at adding javadocs to the fixture classes? If not, I'll work on it in a week. I'd also like to try and switch some of our tests to the fixtures to get a sense of the API, but otherwise I think javadocs is the only remaining bit before we can release it. We are planning to release 1.42 java port in a week, including the junit integration. |
I probably won't have time to get to the javadocs but have already started converting some of the existing tests over to using Fixtures. as I get a logical grouping done, i'll submit PRs for them. |
I'll skip the javadocs |
Documentation for JUnit integration aka JUnit fixtures microsoft/playwright-java#1369
Experimental junit fixtures have been released in 1.42.0, great job folks! Closing this issue, let's use separate ones for further improvements. |
To provide decent support of JUnit in codegen (as requested in #1039), we need to first implement basic Playwright fixtures similar to other languages. This came up in the discussion of #1366 and whether/how we can integrate https://github.com/uchagani/junit-playwright into Playwright. Below are some of the requirements we'll have for such integration and some comments regarding how it compares to the existing junit-playwright.
The execution model should be similar to the default execution model of Node.js Playwright. I.e. it should be possible to
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = same_thread
junit.jupiter.execution.parallel.mode.classes.default = concurrent
Builtin fixtures should create Playwright, Browser, BrowserContext and Page. Their lifetimes should match those in Node.js version, i.e.
Browser & playwright lifetimes should be bound to the thread & browser configuration. Playwright instance most likely should be thread local and can be reused by all tests running on that thread. We should try to reuse the same browser instance for running more tests that require the browser launch options. Currently, playwright internal test suite creates new browser per test class which seems to be good enough.
To keep things simple in the beginning we'd like to replace PlaywrightBrowserConfig with a configurable BrowserFactory, so that we don't have to think about config format and let the user create custom browser themselves. Eventually, we'll likely want to load the config from a json/xml/.properties file. We'll likely need to experiment with a few approaches here, to strike a balance.
The text was updated successfully, but these errors were encountered: