In my application I don’t use @Route, Instead I register them programmatically in a VaadinServiceInitListener. How can that be adapted to Browserless?
Looks like I can override discoverRoutes() and return a Routes, but Routes.getRoutes() is just a Set, which I assume means it gets all the actual information from the @Route annotation, which I don’t have.
It really depends how you want to test the views. Do you want to do integration tests or unit tests? One way to use Browserless tests is pure unit testing, when you just instantiate your view with new operator and then use mock presenter with it. I.e. you do not even attempt to wire the actual backend to it. This works well, if you have proper MVP / MVC type architecture and no business logic entangled with view. I also know by history, that you have preferred Java EE / CDI stack. And unfortunately Weld CDI extension does not support proxied beans, so you could not inject service beans in the tests anyway. So thus my first idea specifically for you is to use pure unit test approach.
The goal is to do integration tests. Not sure I need to test Vaadin’s routing as such. I can create an instance of the View + an instance of the main layout and connect them myself.
I would have to do something similar for the hundreds of “Goto” menu entries and buttons that we have, but again, since everything is generated, and I don’t have hard-coded route names anywhere, I guess I don’t need to test Vaadin’s routing as such.
Still not sure what the best approach is for integration testing.
Given:
@Route(value="myView", layout=MainLayout.class)
public class MyView ...
Using navigate(MyView.class) means the MainLayout is recreated on each test as well.
I’d like to avoid that, since it is a bit costly, but it seems to work.
Same with RouteConfiguration.forApplicationScope().setRoute in @BeforeEach.
On the other hand, using new MyView() means my view isn’t fully wired up, so code that does UI.getCurrent().getCurrentView() will fail.
I have tried to see if I could wire it up to UI manually:
An option could be to define custom InstantiatorFactory for testing purposes which is kind of singleton and generates an Instantiator that returns always the same layout instance for every test run.
The browserless test class should then override lookupServices and return a reference to the factory class.
EDIT: Not the best idea, maybe, since each test will run with its own VaadinSession.
Doh, that was so obvious when you pointed it out…
BaseBrowserlessTest.initVaadinEnvironment is pretty clear in what it does, and opens the door for my kind of adaptation.
This reuses the UI, for good and bad, as I wanted.
When trying it out, I got an error on test #3 and thought there was a problem with this way of doing it:
java.lang.IllegalArgumentException: Navigation resulted in unexpected class com.ec.ptsmc.configuration.CompanyScreen instead of com.ec.ptsmc.configuration.PersonScreen
However, this was because the test of CompanyScreen had changed the data and blocked navigation with a “Do you want to save first” message…
I think this is something I want to capture, so that was an added benefit of reusing UI.
This was hard to debug. I tried to add @ExtendWith(TreeOnFailureExtension.class) but got no extra output.
I wrapped the navigate in my own try/catch and used printed out the same prettyPrint as TreeOnFailureExtension calls. However, I don’t see the “Do you want to save” anywhere in it.
The prettyPrint is pretty massive though, so even if the “Do you want to save” had been there, I don’t know if I would’ve seen it.
I had to go through the steps manually in the browser to find the issue.
Now that I know what it is, I assume I can program in a test for it and raise an understandable error
@marcoc_753 , based on your suggestions I now have an integration test suite of around 450 generated test-files like this that runs fast :
public class TestPersonScreen extends MyBrowserlessTest {
@Test
public void testAll() {
testScreen(PersonScreen.class);
}
}
Since our Screen classes have a standardized structure, testScreen can perform quite a few automated tests, so we get a lot of testing “for free”, but now that the structure is in place we can start to add hand-written tests as well.
Interesting, but doesn’t sound like it covers my case, or?
Sounds like it covers reusing setup for the tests in one test-class, while I also want to reuse setup across multiple test-classes.
Ie, I have
public class TestPersonScreen extends MyBrowserlessTest {
@Test
public void testAll() {
testScreen(PersonScreen.class);
}
// Manually written @Tests at a later stage
}
public class TestInstallationScreen extends MyBrowserlessTest {
@Test
public void testAll() {
testScreen(InstallationScreen.class);
}
// Manually written @Tests at a later stage
}
... + 448 other test-classes following the same pattern
Not that it matters. As long as it remains easy to override BrowserlessTesting to get the behavior I want, I’m happy.
Ah, OK. It looks like I misunderstood your use case.
Actually, reusing the same UI/VaadinSession for all tests is something I would probably not do since it can potentially cause false positives based on tests’ ordering.
But you know your project needs, and if you are happy with that solution, go with it