VaadinAppShellInitializer implements ClassLoaderAwareServletContainerInitializer,
        // implementing ServletContextListener is needed for the @WebListener
        // annotation.
        ServletContextListener, Serializable { @Override public void process(Set<Class<?>> classes, ServletContext context) throws ServletException { Collection<? extends ServletRegistration> registrations = context .getServletRegistrations().values(); if (registrations.isEmpty()) { return; } DeploymentConfiguration config = StubServletConfig .createDeploymentConfiguration(context, registrations.iterator().next(), VaadinServlet.class); init(classes, context, config); }  @Override void process(Set<Class<?>> classes, ServletContext context); @SuppressWarnings("unchecked") static void init(Set<Class<?>> classes, ServletContext context,
            DeploymentConfiguration config); @SuppressWarnings("unchecked") static List<Class<? extends Annotation>> getValidAnnotations(); static List<Class<?>> getValidSupers(); @Override void contextInitialized(ServletContextEvent sce); @Override void contextDestroyed(ServletContextEvent sce);  }
@Test public void should_not_modifyDocument_when_noAnnotatedAppShell() throws Exception { classes.add(MyAppShellWithoutAnnotations.class); initializer.process(classes, servletContext); AppShellRegistry.getInstance(context).modifyIndexHtml(document, createVaadinRequest("/")); assertEquals(0, document.head().children().size()); assertEquals(0, document.body().children().size()); }
@Test public void should_not_modifyPushConfiguration_when_noAnnotatedAppShell() throws Exception { classes.add(MyAppShellWithoutAnnotations.class); initializer.process(classes, servletContext); AppShellRegistry.getInstance(context) .modifyPushConfiguration(pushConfiguration); initializer.process(Collections.emptySet(), servletContext); }
@Test public void should_not_throw_when_noClassesFound_null() throws Exception { initializer.process(null, servletContext); }
@Test public void should_haveMetasAndBodySize_when_annotatedAppShell() throws Exception { classes.add(MyAppShellWithMultipleAnnotations.class); initializer.process(classes, servletContext); AppShellRegistry.getInstance(context).modifyIndexHtml(document, createVaadinRequest("/")); List<Element> elements = document.head().children(); assertEquals(7, elements.size()); assertEquals("text/css", elements.get(5).attr("type")); assertEquals("body,#outlet{width:my-width;height:my-height;}", elements.get(5).childNode(0).toString()); }
@Test public void should_haveInline_when_annotatedAppShell() throws Exception { classes.add(MyAppShellWithMultipleAnnotations.class); initializer.process(classes, servletContext); AppShellRegistry.getInstance(context).modifyIndexHtml(document, createVaadinRequest("/")); List<Element> headElements = document.head().children(); assertEquals(7, headElements.size()); assertEquals("text/css", headElements.get(0).attr("type")); assertEquals("style", headElements.get(0).tagName()); assertTrue(headElements.get(0).outerHtml().contains("#preloadedDiv")); assertEquals("foo", headElements.get(1).attr("name")); assertEquals("lorem", headElements.get(2).attr("name")); assertEquals("viewport", headElements.get(3).attr("name")); assertEquals("title", headElements.get(4).tagName()); assertEquals("my-title", headElements.get(4).childNode(0).toString()); assertEquals("text/css", headElements.get(5).attr("type")); assertEquals("style", headElements.get(5).tagName()); assertTrue(headElements.get(5).outerHtml().contains("width:my-width")); assertTrue( headElements.get(5).outerHtml().contains("height:my-height")); assertEquals("text/javascript", headElements.get(6).attr("type")); assertEquals("script", headElements.get(6).tagName()); assertTrue(headElements.get(6).outerHtml() .contains("might not yet be accessible")); List<Element> bodyElements = document.body().children(); assertEquals(1, bodyElements.size()); assertEquals("text/javascript", bodyElements.get(0).attr("type")); assertEquals("script", bodyElements.get(0).tagName()); assertTrue(bodyElements.get(0).outerHtml() .contains("window.messages.push")); }
@Test public void should_modifyPushConfiguration_when_annotatedAppShell() throws Exception { classes.add(MyAppShellWithMultipleAnnotations.class); initializer.process(classes, servletContext); AppShellRegistry.getInstance(context) .modifyPushConfiguration(pushConfiguration); Mockito.verify(pushConfiguration).setPushMode(PushMode.MANUAL); Mockito.verify(pushConfiguration).setTransport(Transport.WEBSOCKET); }
@Test public void should_throw_when_offendingClass() throws Exception { exception.expect(InvalidApplicationConfigurationException.class); exception.expectMessage(containsString( "Found app shell configuration annotations in non")); exception.expectMessage(containsString( "- @Meta, @Inline, @Viewport, @BodySize, @Push" + " from")); classes.add(MyAppShellWithoutAnnotations.class); classes.add(OffendingClass.class); initializer.process(classes, servletContext); }
@Test public void should_throw_when_multipleAppShell() throws Exception { exception.expect(InvalidApplicationConfigurationException.class); exception .expectMessage(containsString("Unable to find a single class")); classes.add(MyAppShellWithoutAnnotations.class); classes.add(MyAppShellWithMultipleAnnotations.class); initializer.process(classes, servletContext); }
@Test public void should_throw_when_offendingClassWithConfigurator() throws Exception { exception.expect(InvalidApplicationConfigurationException.class); exception.expectMessage(containsString( "The `PageConfigurator` interface is deprecated since Vaadin 15 and has no effect.")); exception.expectMessage( containsString(MyAppShellWithoutAnnotations.class.getName())); exception.expectMessage(containsString( "- " + OffendingClassWithConfigurator.class.getName())); classes.add(MyAppShellWithoutAnnotations.class); classes.add(OffendingClassWithConfigurator.class); initializer.process(classes, servletContext); }
@Test public void should_not_throw_when_classWithPageConfigurator() throws Exception { classes.add(OffendingClassWithConfigurator.class); initializer.process(classes, servletContext); }
@Test public void should_not_throw_when_appShellAnnotationsAreAllowed_and_offendingClass() throws Exception { initParams.put(Constants.ALLOW_APPSHELL_ANNOTATIONS, Boolean.TRUE.toString()); classes.add(OffendingClass.class); initializer.process(classes, servletContext); AppShellRegistry.getInstance(context).modifyIndexHtml(document, createVaadinRequest("/")); List<Element> elements = document.head().children(); assertEquals(0, elements.size()); }
@Test public void should_link_to_PWA_article() throws Exception { initParams.put(Constants.ALLOW_APPSHELL_ANNOTATIONS, Boolean.TRUE.toString()); ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class); classes.add(OffendingPwaClass.class); initializer.process(classes, servletContext); Mockito.verify(logger, Mockito.times(1)).error(arg.capture()); assertTrue(arg.getValue() .contains("We changed the way you configure PWAs")); }
@Test public void should_not_link_to_PWA_article() throws Exception { initParams.put(Constants.ALLOW_APPSHELL_ANNOTATIONS, Boolean.TRUE.toString()); ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class); classes.add(OffendingNonPwaClass.class); initializer.process(classes, servletContext); Mockito.verify(logger, Mockito.times(1)).error(arg.capture()); assertFalse(arg.getValue() .contains("We changed the way you configure PWAs")); assertTrue(arg.getValue().contains("@Viewport")); }