WebComponentWrapper extends Component { @ClientCallable public void disconnected() { Optional<UI> uiOptional = getUI(); if (uiOptional.isPresent() && disconnectRegistration == null) { disconnect = System.currentTimeMillis(); disconnectRegistration = uiOptional.get().getInternals() .addHeartbeatListener(event -> { int disconnectTimeout = event.getSource().getSession() .getConfiguration().getWebComponentDisconnect(); int timeout = 1000 * disconnectTimeout; if (event.getSource().getInternals() .getLastHeartbeatTimestamp() - disconnect > timeout) { Element element = getElement(); element.getParent().removeVirtualChild(element); disconnectRegistration.remove(); } }); } } WebComponentWrapper(Element rootElement,
            WebComponentBinding<?> binding); protected  WebComponentWrapper(Element rootElement,
            WebComponentBinding<?> binding, List<Element> bootstrapElements); @ClientCallable void sync(String property, JsonValue newValue); @ClientCallable void reconnect(); @ClientCallable void disconnected();  }
@Test public void disconnectOnClient_componentIsCleaned() { Element element = new Element("tag"); WebComponentUI ui = constructWebComponentUI(element); constructWrapperAndGetBinding(new MyComponentExporter(), element, ui); UIInternals internals = ui.getInternals(); wrapper.disconnected(); internals.setLastHeartbeatTimestamp(System.currentTimeMillis()); Assert.assertTrue("Wrapper should still be connected on the server", wrapper.getParent().isPresent()); internals.setLastHeartbeatTimestamp(System.currentTimeMillis() + 1200); Assert.assertFalse( "Wrapper should have been disconnected also on the server", wrapper.getParent().isPresent()); }