docs: Document how the browserless test environment differs from a running application - #6076
mcollovati wants to merge 2 commits into
Conversation
…application Adds an Environment Differences page covering the browserless test lifecycle, why session-scoped beans cannot be injected into a test class field, and why authentication established during a test needs a second navigation. Also documents that a location string passed to `navigate()` can carry a query string and a fragment, and adds a note to the Spring Security page about signing in after the environment is created. Related to vaadin/browserless-test#201
Preview DeploymentThis PR has been deployed for preview. URL: https://docs-preview-pr-6076.fly.dev Changed pagesAdded content is highlighted in green; removed content is marked in red on each page.
Built from 4593504 |
| } | ||
| ---- | ||
|
|
||
| Injecting [classname]`ObjectProvider<Cart>` or annotating the field with [annotationname]`@Lazy` works as well, because both defer resolution until the bean is first used. |
There was a problem hiding this comment.
Would this be an easier to use method to suggest as the default, instead of injecting ApplicationContext?
There was a problem hiding this comment.
Yes, agreed — it is now the default in the example, with @Lazy and ApplicationContext.getBean(...) mentioned after it as equivalents. @VaadinSessionScope has no proxyMode, so the only thing that matters is that the lookup happens inside the test method rather than at field injection time, and ObjectProvider says that with the least ceremony.
|
|
||
| .Reloading Isn't Enough | ||
| [NOTE] | ||
| [methodname]`reload()` isn't a substitute for navigating again. It re-renders the current location, and when access control has redirected to the login view, that location is the login view. |
There was a problem hiding this comment.
Is this how it should work or a limitation?
There was a problem hiding this comment.
How it should work. MockPage.reload() closes the UI, recording internals.activeViewLocation, and MockVaadin.createUI navigates the new UI back to that location — which is exactly what pressing F5 does in a browser. Since access control redirected the earlier navigation to the login view, that recorded location is the login view. The note now says it mirrors a browser reload, instead of reading like a shortcoming.
| @WithMockUser(username = "admin", roles = "ADMIN", | ||
| setupBefore = TestExecutionEvent.TEST_EXECUTION) | ||
| void adminSignsIn_adminViewShown() { | ||
| // The initial navigation ran while the user was still anonymous. |
There was a problem hiding this comment.
By just looking at the code example, it's not clear what this refers to as there is no "initial navigation" anywhere
There was a problem hiding this comment.
Reworded to say what happened instead of naming it: "Setup navigated to the root route while the user was still anonymous, and access control redirected that navigation to the login view."
|
|
||
|
|
||
| [#authentication-applied-during-a-test] | ||
| == Authentication Applied During a Test |
There was a problem hiding this comment.
If you only have a quick look at this page, you might very well think this is how you should to authentication in a test. Could it maybe start by showing the correct way and only after that explain why you would want another approach and how you deal with things if you pick that approach?
There was a problem hiding this comment.
Restructured that way: the section now opens with a plain @WithMockUser and a test that just navigates, and only then covers a sign-in performed during the test, why the view does not follow it, and the re-navigation. The "prefer doing it before the test method" paragraph that used to close the section is gone, since that is now the opening.
|
|
||
| All navigation methods return the instantiated view, so that its fields can be used directly for testing. | ||
|
|
||
| A location string can also [since:com.vaadin:vaadin@V25.3]#carry a query string, a fragment, or both#. They are split off from the path the same way the browser address bar does it, so the query parameters reach the view through the navigation event: |
There was a problem hiding this comment.
This should just be another bullet point in the list above
There was a problem hiding this comment.
Done — it is a fourth bullet now, in the same shape as the other three, with the split-up and fragment-only details as its continuation.
| navigate("orders/1?tab=history&page=2", OrderView.class); | ||
| ---- | ||
|
|
||
| Query parameters can be passed as a separate [classname]`QueryParameters` object through [methodname]`UI.getCurrent().navigate(String, QueryParameters)`. Providing them both ways at once is rejected, because the query string in the location would be dropped. |
There was a problem hiding this comment.
Isn't this the wrong way to do it as then it would simulate a server side navigation instead? Could just drop this if you can use navigate with parameters
There was a problem hiding this comment.
You are right, and it is dropped. There is no navigate(String, QueryParameters) on the test base class, so that line went through UI directly, which skips the target view validation the navigate() methods do. The location string carries the query parameters since vaadin/browserless-test#204, so nothing is lost by removing it.
| page-title: How the Vaadin browserless test environment differs | ||
| description: What the browserless environment creates, in which order, and which application behavior therefore needs a different approach in a test. | ||
| meta-description: Learn the browserless test lifecycle in Vaadin, and how it affects session-scoped beans and authentication applied during a test. | ||
| order: 12 |
There was a problem hiding this comment.
This page seems way to high up, it is more of an advanced topic that should be closed to the end
There was a problem hiding this comment.
Moved to order: 80, so it sits after the framework-specific pages and before Optimizing Tests and Migration.
Move the page to the end of the browserless section, since it is an advanced topic rather than something to read right after Getting Started. Lead the authentication section with the approach that works without a second navigation, and only then describe a sign-in performed during the test. Make the example's comment say what the setup navigation did, since the code around it never mentions one. Say that Page.reload() recreating the UI at the active location is what a browser reload does, not a limitation. Suggest ObjectProvider as the default way to reach a session scoped bean, and keep @lazy and ApplicationContext.getBean as alternatives. In Getting Started, fold navigation with a query string into the list of navigate() forms, and drop the UI.getCurrent().navigate(String, QueryParameters) variant: it bypasses the target view validation the navigate() methods perform, and the location string already carries the query parameters.
Follow-up to vaadin/browserless-test#201, which reported four ways a browserless test behaves differently from a running application. Two of them were bugs and are fixed in the framework; two are consequences of the test lifecycle and were never documented. This covers all of it on the docs side.
New page: Environment Differences
articles/flow/testing/browserless/environment-differences.adoc, placed right after Getting Started.@VaadinSessionScopebean can't be autowired into a test class field, because the field is injected before a session exists. Worth noting that it fails every test in the class, not only the ones using the bean. Resolve it from the test method withgetBean(...),ObjectProvider, or@Lazy.reload()is not a substitute, since it re-renders the location access control already redirected to.Getting Started
The Navigating to Views section listed only the path and parameter forms. A location string can carry a query string and a fragment as of vaadin/browserless-test#204, and that was never documented.
Spring Security
The page states that authentication details are available before the UI is created and the default route is navigated to. Added the boundary: that holds when the authentication is in place before the test method starts.
Draft for review of scope and placement. The behavior described was verified against the current
browserless-testmain.