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

Need help using Karibu-Testing with Vaadin and CDI #70

Open
skiedrowski opened this issue Apr 15, 2021 · 1 comment
Open

Need help using Karibu-Testing with Vaadin and CDI #70

skiedrowski opened this issue Apr 15, 2021 · 1 comment
Labels
help wanted Extra attention is needed

Comments

@skiedrowski
Copy link

I am trying to set up Karibu-Testing 1.2.12 with a Vaadin 14.5.2/CDI project. Using the hints given in #60, I was able to create an initial setup, but I am now stuck with the error
No org.apache.deltaspike.core.api.provider.BeanManagerProvider in place! Please ensure that you configured the CDI implementation of your choice properly. If your setup is correct, please clear all caches and compiled artifacts.
which can be traced back to AbstractCdiInstantiiator#getOrCreate calling BeanProvider.injectFields(instance);.

Who is supposed to provide the BeanManager? Vaadin-CDI addon or my project?
The weld-junit5 dependency seems to provide weld-se-core/weld-core-impl, so there is a CDI container available. Do I need to configure it somewhere?
What else am I supposed to configure?


What I did so far:

  1. add testImplementation dependencies for
com.github.mvysny.kaributesting:karibu-testing-v10:${Ver.karibu_testing}
org.jboss.weld:weld-junit5:${Ver.weld_junit5} 
io.smallrye:smallrye-config-1.3:${Ver.smallrye_config} //microprofile-config
org.glassfish.jersey.ext.microprofile:jersey-mp-rest-client:${Ver.mp_rest_client_impl} //microprofile-rest-client
  1. provide an empty beans.xml in src/test/resources/META-INF/(not sure whether required in this context).

  2. implement JUnit 5 Test Class with Weld
    http://weld.cdi-spec.org/news/2017/12/19/weld-meets-junit5/

@ExtendWith(WeldJunit5Extension.class)
class InitialKaribuTest {
    private static Routes routes;

    @WeldSetup
    public WeldInitiator weld = WeldInitiator.of(WeldInitiator.createWeld()
        .addExtensions(ConfigExtension.class)        //required for microprofile-config
        .addExtensions(RestClientExtension.class)         //required for microprofile-rest-client
        .beanClasses(/*... list of my test dependencies ...*/)
    );

    @BeforeAll
    public static void createRoutes() {
        routes = new Routes().autoDiscoverViews("com.mypackage");
    }

    @BeforeEach
    public void setupVaadin() {
        MockVaadin.setup(MockedUI::new, new WeldMockVaadinServlet(routes, weld));
    }

    @Test
    void testLogin() {
        final LoginScreen loginScreen = (LoginScreen) UI.getCurrent().getChildren().findFirst().get();
        assertEquals(2, loginScreen.getChildren().count());

        _get(TextField.class, spec->spec.withCaption("Username")).setValue("user");
        _get(PasswordField.class, spec->spec.withCaption("Password")).setValue("pwd");
        _click(_get(Button.class, spec -> spec.withCaption("Log in")));
    }
}
  1. provide WeldMockVaadinServlet (taken from Route not found issue #60):
public class WeldMockVaadinServlet extends MockVaadinServlet {
    private final Routes routes;
    private WeldInitiator _weld;

    public WeldMockVaadinServlet(final Routes routes, final WeldInitiator weld) {
        super(routes);
        this.routes = routes; //compiler complains that routes of superclass is private although it is explicitly public
        _weld = weld;
    }

    @Override
    protected VaadinServletService createServletService(@NotNull final DeploymentConfiguration deploymentConfiguration) {
        final CdiMockService service = new CdiMockService(_weld, this, deploymentConfiguration);
        try {
            service.init();
        } catch (final ServiceException e) {
            throw new RuntimeException(e); //TODO
        }
        routes.register(service.getContext());
        return service;
    }
}
  1. provide CdiMockService is also taken from Route not found issue #60
public class CdiMockService extends MockService {
    private final WeldInitiator _weld;

    public CdiMockService(final WeldInitiator weld, @NotNull final VaadinServlet servlet,
                          @NotNull final DeploymentConfiguration deploymentConfiguration) {
        super(servlet, deploymentConfiguration, MockedUI::new);
        _weld = weld;
        //TODO is that needed? What should the SessionListener do? addSessionInitListener(new SessionListener());
    }

    @Override
    protected Instantiator createInstantiator() throws ServiceException {
        final BeanManager beanManager = _weld.getBeanManager();
        return new KaribuVaadinCDIInstantiator(this, beanManager);
    }
}
  1. provide KaribuVaadinCDIInstantiator. Route not found issue #60 also does not include this class so here is my attempt, inheriting from Vaadin AbstractCdiInstantiator
public class KaribuVaadinCDIInstantiator extends AbstractCdiInstantiator {
    private final BeanManager beanManager;

    public KaribuVaadinCDIInstantiator(final CdiMockService cdiMockService, final BeanManager beanManager) {
        init(cdiMockService);
        this.beanManager = beanManager;
    }

    @Override
    public Class<? extends VaadinService> getServiceClass() {
        return CdiMockService.class;
    }

    @Override
    public BeanManager getBeanManager() {
        return beanManager;
    }

    @Override
    public <T extends Component> T createComponent(final Class<T> componentClass) {
        final Unmanaged<T> unmanagedClass = new Unmanaged<T>(componentClass);
        final Unmanaged.UnmanagedInstance<T> instance = unmanagedClass.newInstance();
        instance.produce().inject().postConstruct();
        return instance.get();
    }
}
  1. Route not found issue #60 does not include the SessionListener, do I need to provide one? What should it do?
@mvysny mvysny added the help wanted Extra attention is needed label May 10, 2021
@mvysny
Copy link
Owner

mvysny commented May 10, 2021

I'm sorry but I haven't been using CDI for a long time. There's https://github.com/mvysny/vaadin-quarkus-skeleton-starter which uses Quarkus CDI implementation which is then able to look up the BeanManager, but only if the test is annotated with @QuarkusTest.

The Quarkus Extension uses CDI.current().getBeanManager(); as can be seen at https://github.com/urosporo/vaadin-quarkus-extension-parent/blob/main/vaadin-quarkus-extension/src/main/java/com/urosporo/quarkus/vaadin/cdi/BeanProvider.java . I think the best way is to figure out how to make Weld configure CDI to return the bean manager via CDI.current().getBeanManager();. Perhaps there's some testing support for Weld which does that, and you can start from there and just introduce Karibu-Testing.

Another way would be to not to use DI, IMHO it's an anti-pattern anyway: https://mvysny.github.io/code-locality-and-ability-to-navigate/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants