From ffef3a6f45a98a4e176b498822b31700ad4d770c Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 4 Oct 2019 16:01:55 +0300 Subject: [PATCH] Check fallback chunk data and load fallback chunk if dependency is in the data (#6590) Fixes #6590 --- .../flow/plugin/maven/BuildFrontendMojo.java | 2 +- .../component/internal/ComponentMetaData.java | 7 - .../flow/component/internal/UIInternals.java | 90 ++++++++++- .../com/vaadin/flow/component/page/Page.java | 1 - .../flow/server/frontend/NodeTasks.java | 48 +++--- .../frontend/TaskCreatePackageJson.java | 1 + .../server/frontend/TaskUpdateImports.java | 51 +++--- .../server/frontend/TaskUpdatePackages.java | 12 +- .../server/startup/DevModeInitializer.java | 73 +-------- .../src/main/resources/webpack.generated.js | 2 +- .../component/HtmlImportJsModuleTest.java | 14 +- .../AbstractNodeUpdatePackagesTest.java | 1 + .../frontend/NodeUpdateImportsTest.java | 12 +- .../startup/DevModeInitializerTest.java | 64 ++------ flow-tests/test-npm-only-features/pom.xml | 1 + .../pom-devmode.xml | 1 + .../pom-prod-fallback.xml | 146 ++++++++++++++++++ .../pom-production.xml | 1 + .../ByteCodeScanningView.java | 15 -- .../RemoveFallbackChunkInfo.java | 71 +++++++++ ...adin.flow.server.VaadinServiceInitListener | 1 + .../bytecodescanning/ByteCodeScanningIT.java | 30 ++-- .../FallbackByteCodeScanningIT.java | 45 ++++++ .../bytecodescanning/FullCPScanningIT.java | 44 ++++++ .../StartupPerformanceIT.java | 41 +++-- 25 files changed, 501 insertions(+), 273 deletions(-) create mode 100644 flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-prod-fallback.xml create mode 100644 flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/RemoveFallbackChunkInfo.java create mode 100644 flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/resources/META-INF/services/com.vaadin.flow.server.VaadinServiceInitListener create mode 100644 flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/FallbackByteCodeScanningIT.java create mode 100644 flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/FullCPScanningIT.java diff --git a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildFrontendMojo.java b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildFrontendMojo.java index 13a29732b80..a12e5e8ef5c 100644 --- a/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildFrontendMojo.java +++ b/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildFrontendMojo.java @@ -183,7 +183,7 @@ private void runNodeUpdater() throws ExecutionFailedException { .enableImportsUpdate(true) .withEmbeddableWebComponents( generateEmbeddableWebComponents) - .build().execute(); + .withTokenFile(getTokenFile()).build().execute(); } private void runWebpack() { diff --git a/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentMetaData.java b/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentMetaData.java index 57cff9961c2..f619c5a9b2a 100644 --- a/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentMetaData.java +++ b/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentMetaData.java @@ -23,7 +23,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @@ -44,7 +43,6 @@ import com.vaadin.flow.internal.AnnotationReader; import com.vaadin.flow.internal.ReflectTools; import com.vaadin.flow.server.VaadinService; -import com.vaadin.flow.server.startup.DevModeInitializer.VisitedClasses; import com.vaadin.flow.shared.ApplicationConstants; import com.vaadin.flow.shared.ui.LoadMode; import com.vaadin.flow.shared.util.SharedUtil; @@ -179,11 +177,6 @@ private static Logger getLogger() { */ private static DependencyInfo findDependencies(VaadinService service, Class componentClass) { - Optional.ofNullable( - service.getContext().getAttribute(VisitedClasses.class)) - .ifPresent(visitedClasses -> visitedClasses - .ensureAllDependenciesVisited(componentClass)); - DependencyInfo dependencyInfo = new DependencyInfo(); findDependencies(service, componentClass, dependencyInfo, diff --git a/flow-server/src/main/java/com/vaadin/flow/component/internal/UIInternals.java b/flow-server/src/main/java/com/vaadin/flow/component/internal/UIInternals.java index d1f4f337c84..defd6606f2c 100644 --- a/flow-server/src/main/java/com/vaadin/flow/component/internal/UIInternals.java +++ b/flow-server/src/main/java/com/vaadin/flow/component/internal/UIInternals.java @@ -23,6 +23,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -35,8 +37,10 @@ import com.vaadin.flow.component.ComponentUtil; import com.vaadin.flow.component.HasElement; import com.vaadin.flow.component.UI; +import com.vaadin.flow.component.dependency.CssImport; import com.vaadin.flow.component.dependency.HtmlImport; import com.vaadin.flow.component.dependency.JavaScript; +import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.dependency.StyleSheet; import com.vaadin.flow.component.internal.ComponentMetaData.DependencyInfo; import com.vaadin.flow.component.internal.ComponentMetaData.HtmlImportDependency; @@ -66,10 +70,13 @@ import com.vaadin.flow.router.internal.AfterNavigationHandler; import com.vaadin.flow.router.internal.BeforeEnterHandler; import com.vaadin.flow.router.internal.BeforeLeaveHandler; +import com.vaadin.flow.server.VaadinContext; import com.vaadin.flow.server.VaadinService; import com.vaadin.flow.server.VaadinSession; import com.vaadin.flow.server.WebBrowser; import com.vaadin.flow.server.communication.PushConnection; +import com.vaadin.flow.server.frontend.FallbackChunk; +import com.vaadin.flow.server.frontend.FallbackChunk.CssImportData; import com.vaadin.flow.shared.Registration; import com.vaadin.flow.shared.communication.PushMode; import com.vaadin.flow.theme.AbstractTheme; @@ -200,6 +207,8 @@ public List getParameters() { private ExtendedClientDetails extendedClientDetails = null; + private boolean isFallbackChunkLoaded; + /** * Creates a new instance for the given UI. * @@ -848,18 +857,85 @@ public void addComponentDependencies( js -> page.addJavaScript(js.value(), js.loadMode())); } else { // In npm mode, add external JavaScripts directly to the page. - dependencies.getJavaScripts().stream() - .filter(js -> UrlUtil.isExternal(js.value())) - .forEach(js -> page.addJavaScript(js.value(), - js.loadMode())); - dependencies.getJsModules().stream() - .filter(js -> UrlUtil.isExternal(js.value())) - .forEach(js -> page.addJsModule(js.value(), js.loadMode())); + addExternalDependencies(dependencies); + addFallbackDependencies(dependencies); + } dependencies.getStyleSheets().forEach(styleSheet -> page .addStyleSheet(styleSheet.value(), styleSheet.loadMode())); } + private void addFallbackDependencies(DependencyInfo dependency) { + if (isFallbackChunkLoaded) { + return; + } + VaadinContext context = ui.getSession().getService().getContext(); + FallbackChunk chunk = context.getAttribute(FallbackChunk.class); + if (chunk == null) { + if (getLogger().isDebugEnabled()) { + getLogger().debug( + "Fallback chunk is not available, skipping fallback dependencies load"); + } + return; + } + + Set modules = chunk.getModules(); + Set cssImportsData = chunk.getCssImports(); + if (modules.isEmpty() && cssImportsData.isEmpty()) { + getLogger().debug( + "Fallback chunk is empty, skipping fallback dependencies load"); + return; + } + + List cssImports = dependency.getCssImports(); + List javaScripts = dependency.getJavaScripts(); + List jsModules = dependency.getJsModules(); + + if (jsModules.stream().map(JsModule::value) + .anyMatch(modules::contains)) { + loadFallbackChunk(); + return; + } + + if (javaScripts.stream().map(JavaScript::value) + .anyMatch(modules::contains)) { + loadFallbackChunk(); + return; + } + + if (cssImports.stream().map(this::buildData) + .anyMatch(cssImportsData::contains)) { + loadFallbackChunk(); + return; + } + } + + private CssImportData buildData(CssImport imprt) { + Function converter = str -> str.isEmpty() ? null : str; + return new CssImportData(converter.apply(imprt.value()), + converter.apply(imprt.id()), converter.apply(imprt.include()), + converter.apply(imprt.themeFor())); + } + + private void loadFallbackChunk() { + if (isFallbackChunkLoaded) { + return; + } + ui.getPage() + .addDynamicImport("return window.Vaadin.Flow.loadFallback();"); + isFallbackChunkLoaded = true; + } + + private void addExternalDependencies(DependencyInfo dependency) { + Page page = ui.getPage(); + dependency.getJavaScripts().stream() + .filter(js -> UrlUtil.isExternal(js.value())) + .forEach(js -> page.addJavaScript(js.value(), js.loadMode())); + dependency.getJsModules().stream() + .filter(js -> UrlUtil.isExternal(js.value())) + .forEach(js -> page.addJsModule(js.value(), js.loadMode())); + } + private void addHtmlImport(HtmlImportDependency dependency, Page page) { // The HTML dependency parser does not consider themes so it can // cache raw information (e.g. vaadin-button/src/vaadin-button.html diff --git a/flow-server/src/main/java/com/vaadin/flow/component/page/Page.java b/flow-server/src/main/java/com/vaadin/flow/component/page/Page.java index ead14ae2d36..997e39943dc 100644 --- a/flow-server/src/main/java/com/vaadin/flow/component/page/Page.java +++ b/flow-server/src/main/java/com/vaadin/flow/component/page/Page.java @@ -367,7 +367,6 @@ public void addHtmlImport(String url, LoadMode loadMode) { * * * @see #addHtmlImport(String) - * * @param expression * the JavaScript expression which return a Promise */ diff --git a/flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeTasks.java b/flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeTasks.java index da8b6320489..55ffd60dc26 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeTasks.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/frontend/NodeTasks.java @@ -77,12 +77,12 @@ public static class Builder implements Serializable { private File frontendResourcesDirectory = null; - private Set visitedClasses = null; - private boolean useByteCodeScanner = false; private JsonObject tokenFileData; + private File tokenFile; + /** * Directory for for npm and folders and files. */ @@ -278,20 +278,6 @@ public Builder createMissingPackageJson(boolean create) { return this; } - /** - * Sets a set to which the names of classes visited when finding - * dependencies will be collected. - * - * @param visitedClasses - * a set to collect class name to, or null to - * not collect visited classes - * @return the builder, for chaining - */ - public Builder collectVisitedClasses(Set visitedClasses) { - this.visitedClasses = visitedClasses; - return this; - } - /** * Set local frontend files to be copied from given folder. * @@ -330,6 +316,18 @@ public Builder populateTokenFileData(JsonObject object) { tokenFileData = object; return this; } + + /** + * Sets the token file (flow-build-info.json) path. + * + * @param tokenFile + * token file path + * @return the builder, for chaining + */ + public Builder withTokenFile(File tokenFile) { + this.tokenFile = tokenFile; + return this; + } } private final Collection commands = new ArrayList<>(); @@ -390,17 +388,13 @@ private NodeTasks(Builder builder) { } if (builder.enableImportsUpdate) { - commands.add(new TaskUpdateImports(classFinder, - frontendDependencies, - finder -> getFallbackScanner(builder, finder), - builder.npmFolder, builder.generatedFolder, - builder.frontendDirectory, builder.webpackOutputDirectory, - builder.tokenFileData)); - - if (builder.visitedClasses != null) { - builder.visitedClasses - .addAll(frontendDependencies.getClasses()); - } + commands.add( + new TaskUpdateImports(classFinder, frontendDependencies, + finder -> getFallbackScanner(builder, finder), + builder.npmFolder, builder.generatedFolder, + builder.frontendDirectory, builder.tokenFile, + builder.tokenFileData)); + } } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskCreatePackageJson.java b/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskCreatePackageJson.java index 8ce78acc472..430694c7d80 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskCreatePackageJson.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskCreatePackageJson.java @@ -21,6 +21,7 @@ import elemental.json.Json; import elemental.json.JsonObject; + import static com.vaadin.flow.server.frontend.TaskUpdatePackages.APP_PACKAGE_HASH; /** diff --git a/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateImports.java b/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateImports.java index 1065e07fd1c..35b3d46b6fa 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateImports.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdateImports.java @@ -49,7 +49,6 @@ import elemental.json.impl.JsonUtil; import static com.vaadin.flow.server.frontend.FrontendUtils.IMPORTS_NAME; -import static com.vaadin.flow.server.frontend.FrontendUtils.TOKEN_FILE; /** * An updater that it's run when the servlet context is initialised in dev-mode @@ -73,7 +72,7 @@ public class TaskUpdateImports extends NodeUpdater { private final File frontendDirectory; private final FrontendDependenciesScanner fallbackScanner; private final ClassFinder finder; - private final File webpackOutputDirectory; + private final File tokenFile; private final JsonObject tokenFileData; private class UpdateMainImportsFile extends AbstractUpdateImports { @@ -278,16 +277,16 @@ File getGeneratedFallbackFile() { * folder where flow generated files will be placed. * @param frontendDirectory * a directory with project's frontend files - * @param webpackOutputDirectory - * the directory to set for webpack to output its build results. + * @param tokenFile + * the token (flow-build-info.json) path, may be {@code null} */ TaskUpdateImports(ClassFinder finder, FrontendDependenciesScanner frontendDepScanner, SerializableFunction fallBackScannerProvider, File npmFolder, File generatedPath, File frontendDirectory, - File webpackOutputDirectory) { + File tokenFile) { this(finder, frontendDepScanner, fallBackScannerProvider, npmFolder, - generatedPath, frontendDirectory, webpackOutputDirectory, null); + generatedPath, frontendDirectory, tokenFile, null); } /** @@ -305,8 +304,8 @@ File getGeneratedFallbackFile() { * folder where flow generated files will be placed. * @param frontendDirectory * a directory with project's frontend files - * @param webpackOutputDirectory - * the directory to set for webpack to output its build results. + * @param tokenFile + * the token (flow-build-info.json) path, may be {@code null} * @param tokenFileData * object to fill with token file data, may be {@code null} */ @@ -314,12 +313,12 @@ File getGeneratedFallbackFile() { FrontendDependenciesScanner frontendDepScanner, SerializableFunction fallBackScannerProvider, File npmFolder, File generatedPath, File frontendDirectory, - File webpackOutputDirectory, JsonObject tokenFileData) { + File tokenFile, JsonObject tokenFileData) { super(finder, frontendDepScanner, npmFolder, generatedPath); this.frontendDirectory = frontendDirectory; fallbackScanner = fallBackScannerProvider.apply(finder); this.finder = finder; - this.webpackOutputDirectory = webpackOutputDirectory; + this.tokenFile = tokenFile; this.tokenFileData = tokenFileData; } @@ -368,31 +367,28 @@ private AbstractTheme getTheme() { } private void updateBuildFile(AbstractUpdateImports updater) { - File tokenFile = getTokenFile(); - if (!tokenFile.exists()) { - log().warn("Missing token file. New token file will be created."); + boolean tokenFileExists = tokenFile != null && tokenFile.exists(); + if (!tokenFileExists) { + log().warn( + "Token file is not available. Fallback chunk data won't be written."); } try { - JsonObject buildInfo; - if (tokenFile.exists()) { + if (tokenFileExists) { String json = FileUtils.readFileToString(tokenFile, StandardCharsets.UTF_8); - buildInfo = JsonUtil.parse(json); - } else { - FileUtils.forceMkdirParent(tokenFile); - buildInfo = Json.createObject(); - } - - populateFallbackData(buildInfo, updater); - if (tokenFileData != null) { - populateFallbackData(tokenFileData, updater); + JsonObject buildInfo = json.isEmpty() ? Json.createObject() + : JsonUtil.parse(json); + populateFallbackData(buildInfo, updater); + FileUtils.write(tokenFile, JsonUtil.stringify(buildInfo, 2), + StandardCharsets.UTF_8); } - FileUtils.write(tokenFile, JsonUtil.stringify(buildInfo, 2), - StandardCharsets.UTF_8); } catch (IOException e) { log().warn("Unable to read token file", e); } + if (tokenFileData != null) { + populateFallbackData(tokenFileData, updater); + } } private void populateFallbackData(JsonObject object, @@ -453,7 +449,4 @@ private JsonObject makeCssJson(CssData data) { return object; } - private File getTokenFile() { - return new File(webpackOutputDirectory, TOKEN_FILE); - } } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdatePackages.java b/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdatePackages.java index 0953a2995f6..06999cf23d2 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdatePackages.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/frontend/TaskUpdatePackages.java @@ -120,17 +120,17 @@ public void execute() { * updated the main package with new dependencies. * * @param packageJson - * application package json + * application package json * @return true if hash has changed * @throws IOException - * thrown from write exception + * thrown from write exception */ - private boolean checkPackageHash(JsonObject packageJson) throws IOException { + private boolean checkPackageHash(JsonObject packageJson) + throws IOException { String content = ""; // If we have dependencies generate hash on ordered content. if (packageJson.hasKey("dependencies")) { - JsonObject dependencies = packageJson - .getObject("dependencies"); + JsonObject dependencies = packageJson.getObject("dependencies"); content = Stream.of(dependencies.keys()) .map(key -> String.format("\"%s\": \"%s\"", key, dependencies.get(key).asString())) @@ -279,7 +279,7 @@ private String getShrinkWrapVersion(JsonObject packageJson) } private String getHash(String content) { - if(content.isEmpty()) { + if (content.isEmpty()) { return content; } try { diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java index f30281cc6c7..dff72e8df04 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java @@ -146,73 +146,6 @@ private static Set calculateApplicableClassNames() { } } - /** - * The classes that were visited when determining which frontend resources - * are actually used. - */ - public static class VisitedClasses implements Serializable { - private final Set visitedClassNames; - - /** - * Creates a new instance based on a set of class names. - * - * @param visitedClassNames - * the set of visited class names, not null - */ - public VisitedClasses(Set visitedClassNames) { - assert visitedClassNames != null; - this.visitedClassNames = visitedClassNames; - } - - /** - * Checks whether all dependency annotations of the provided class have - * been visited. - * - * @param dependencyClass - * the class to check - * @return true if all dependencies of the class have been - * visited, false otherwise - */ - public boolean allDependenciesVisited(Class dependencyClass) { - if (visitedClassNames.contains(dependencyClass.getName())) { - return true; - } - - /* - * Not being visited is only a problem if the class has own - * dependency annotations or the parent class has problems. - */ - if (dependencyClass - .getDeclaredAnnotationsByType(JsModule.class).length != 0) { - return false; - } - - Class superclass = dependencyClass.getSuperclass(); - if (superclass == null) { - return true; - } else { - return allDependenciesVisited(superclass); - } - } - - /** - * Ensures that all {@code clazz} dependencies are visited. - * - * @see #allDependenciesVisited(Class) - * - * @param clazz - * the class to check - */ - public void ensureAllDependenciesVisited(Class clazz) { - if (!allDependenciesVisited(clazz)) { - DevModeInitializer.log().warn( - "Frontend dependencies have not been analyzed for {}." - + " To make the component's frontend dependencies work, you must ensure the component class is directly referenced through an application entry point such as a class annotated with @Route.", - clazz.getName()); - } - } - } - private static final Pattern JAR_FILE_REGEX = Pattern .compile(".*file:(.+\\.jar).*"); @@ -322,7 +255,6 @@ public static void initDevModeHandler(Set> classes, builder.createMissingPackageJson(true); } - Set visitedClassNames = new HashSet<>(); Set frontendLocations = getFrontendLocationsFromClassloader( DevModeInitializer.class.getClassLoader()); @@ -342,8 +274,7 @@ public static void initDevModeHandler(Set> classes, Constants.LOCAL_FRONTEND_RESOURCES_PATH)) .enableImportsUpdate(true).runNpmInstall(true) .withEmbeddableWebComponents(true) - .populateTokenFileData(tokenFileData) - .collectVisitedClasses(visitedClassNames).build().execute(); + .populateTokenFileData(tokenFileData).build().execute(); FallbackChunk chunk = FrontendUtils .readFallbackChunk(tokenFileData); @@ -357,8 +288,6 @@ public static void initDevModeHandler(Set> classes, throw new ServletException(exception); } - vaadinContext.setAttribute(new VisitedClasses(visitedClassNames)); - try { DevModeHandler.start(config, builder.npmFolder); } catch (IllegalStateException exception) { diff --git a/flow-server/src/main/resources/webpack.generated.js b/flow-server/src/main/resources/webpack.generated.js index e4425efbce3..1c99f79a978 100644 --- a/flow-server/src/main/resources/webpack.generated.js +++ b/flow-server/src/main/resources/webpack.generated.js @@ -83,7 +83,7 @@ module.exports = { output: { filename: `${build}/vaadin-[name]-[contenthash].cache.js`, path: mavenOutputFolderForFlowBundledFiles, - publicPath: '/VAADIN/', + publicPath: 'VAADIN/', }, resolve: { diff --git a/flow-server/src/test/java/com/vaadin/flow/component/HtmlImportJsModuleTest.java b/flow-server/src/test/java/com/vaadin/flow/component/HtmlImportJsModuleTest.java index fada016c092..cb3d14214a6 100644 --- a/flow-server/src/test/java/com/vaadin/flow/component/HtmlImportJsModuleTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/component/HtmlImportJsModuleTest.java @@ -39,7 +39,6 @@ import com.vaadin.flow.server.VaadinContext; import com.vaadin.flow.server.VaadinService; import com.vaadin.flow.server.VaadinSession; -import com.vaadin.flow.server.startup.DevModeInitializer; import com.vaadin.flow.shared.ui.LoadMode; public class HtmlImportJsModuleTest { @@ -48,7 +47,6 @@ public class HtmlImportJsModuleTest { private DeploymentConfiguration configuration; private UI ui; private Page page; - private DevModeInitializer.VisitedClasses visitedClasses; @Before public void setupMocks() { @@ -59,14 +57,6 @@ public void setupMocks() { VaadinContext context = Mockito.mock(VaadinContext.class); Mockito.when(service.getContext()).thenReturn(context); - Mockito.when( - context.getAttribute(DevModeInitializer.VisitedClasses.class)) - .thenReturn(visitedClasses); - Mockito.doAnswer( - invocationOnMock -> visitedClasses = (DevModeInitializer.VisitedClasses) invocationOnMock - .getArguments()[0]) - .when(context).setAttribute( - Mockito.any(DevModeInitializer.VisitedClasses.class)); Mockito.when(session.getService()).thenReturn(service); Mockito.when(session.getConfiguration()).thenReturn(configuration); @@ -76,6 +66,10 @@ public void setupMocks() { ui = Mockito.mock(UI.class); page = Mockito.mock(Page.class); + Mockito.when(ui.getSession()).thenReturn(session); + Mockito.when(service.getContext()) + .thenReturn(Mockito.mock(VaadinContext.class)); + Element element = Mockito.mock(Element.class); StateNode node = Mockito.mock(StateNode.class); diff --git a/flow-server/src/test/java/com/vaadin/flow/server/frontend/AbstractNodeUpdatePackagesTest.java b/flow-server/src/test/java/com/vaadin/flow/server/frontend/AbstractNodeUpdatePackagesTest.java index 586a8d068e1..2b0f80254cb 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/frontend/AbstractNodeUpdatePackagesTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/frontend/AbstractNodeUpdatePackagesTest.java @@ -39,6 +39,7 @@ import elemental.json.Json; import elemental.json.JsonObject; import elemental.json.JsonValue; + import static com.vaadin.flow.server.Constants.PACKAGE_JSON; import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_GENERATED_DIR; import static com.vaadin.flow.server.frontend.TaskUpdatePackages.APP_PACKAGE_HASH; diff --git a/flow-server/src/test/java/com/vaadin/flow/server/frontend/NodeUpdateImportsTest.java b/flow-server/src/test/java/com/vaadin/flow/server/frontend/NodeUpdateImportsTest.java index 3255a8c024f..09fbf392b8f 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/frontend/NodeUpdateImportsTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/frontend/NodeUpdateImportsTest.java @@ -66,7 +66,6 @@ public class NodeUpdateImportsTest extends NodeUpdateTestUtil { private File nodeModulesPath; private TaskUpdateImports updater; private File tmpRoot; - private File webpackDir; private File tokenFile; private Logger logger = Mockito.mock(Logger.class); @@ -81,8 +80,10 @@ public void setup() throws Exception { importsFile = new File(generatedPath, IMPORTS_NAME); fallBackImportsFile = new File(generatedPath, FrontendUtils.FALLBACK_IMPORTS_NAME); - webpackDir = temporaryFolder.newFolder(); + File webpackDir = temporaryFolder.newFolder(); tokenFile = new File(webpackDir, "config/flow-build-info.json"); + FileUtils.forceMkdirParent(tokenFile); + tokenFile.createNewFile(); assertTrue(nodeModulesPath.mkdirs()); createExpectedImports(frontendDirectory, nodeModulesPath); @@ -110,7 +111,7 @@ public void extraComponentsInCP_componentsAreNotDiscoveredByMainScannerWrittenBy classFinder, true), finder -> new FrontendDependenciesScannerFactory() .createScanner(true, finder, true), - tmpRoot, generatedPath, frontendDirectory, webpackDir, + tmpRoot, generatedPath, frontendDirectory, tokenFile, fallBackData) { @Override Logger log() { @@ -209,7 +210,6 @@ Logger log() { // ============== check token file with fallback chunk data ============ - assertTrue(tokenFile.exists()); String tokenContent = FileUtils.readFileToString(tokenFile, Charset.defaultCharset()); JsonObject object = Json.parse(tokenContent); @@ -230,7 +230,7 @@ public void emptyByteCodeScannerData_themeIsDiscovered_fallbackIsGenerated() classFinder, true), finder -> new FrontendDependenciesScannerFactory() .createScanner(true, finder, true), - tmpRoot, generatedPath, frontendDirectory, webpackDir, null) { + tmpRoot, generatedPath, frontendDirectory, tokenFile, null) { @Override Logger log() { return logger; @@ -299,7 +299,7 @@ public void noFallBackSCanner_fallbackIsNotGenerated() throws IOException { new FrontendDependenciesScannerFactory().createScanner(false, classFinder, true), finder -> null, tmpRoot, generatedPath, frontendDirectory, - webpackDir, null) { + tokenFile, null) { @Override Logger log() { return logger; diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java index 7cc218f903c..6d5b4344774 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java @@ -1,11 +1,11 @@ package com.vaadin.flow.server.startup; import javax.servlet.ServletException; + import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.EventListener; import java.util.HashSet; @@ -24,13 +24,12 @@ import com.vaadin.flow.router.Route; import com.vaadin.flow.server.Constants; import com.vaadin.flow.server.DevModeHandler; -import com.vaadin.flow.server.startup.DevModeInitializer.VisitedClasses; +import com.vaadin.flow.server.frontend.FallbackChunk; import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_COMPATIBILITY_MODE; import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_PRODUCTION_MODE; import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_REUSE_DEV_SERVER; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -45,7 +44,7 @@ public static class Visited { public static class NotVisitedWithoutDeps { } - @JsModule("foo") + @JsModule("bar") public static class NotVisitedWithDeps { } @@ -170,49 +169,23 @@ public void listener_should_stopDevModeHandler_onDestroy() assertNull(DevModeHandler.getDevModeHandler()); } - @Test - public void visitedDependencies() { - VisitedClasses visited = new VisitedClasses(new HashSet<>(Arrays - .asList(Object.class.getName(), Visited.class.getName()))); - - assertTrue("Dependencies are ok for a visited class", - visited.allDependenciesVisited(Visited.class)); - - assertTrue( - "Dependencies are ok for an unvisited class without dependencies", - visited.allDependenciesVisited(NotVisitedWithoutDeps.class)); - assertFalse( - "Dependnecies are not ok for an unvisited class with dependencies", - visited.allDependenciesVisited(NotVisitedWithDeps.class)); - - assertTrue( - "Dependencies are ok for an unvisited class without dependencies if super class is ok", - visited.allDependenciesVisited(VisitedSubclass.class)); - assertTrue( - "Dependencies are ok for an unvisited class without dependencies if super class is ok", - visited.allDependenciesVisited(WithoutDepsSubclass.class)); - assertFalse( - "Dependencies are not ok for an unvisited class without dependencies if super class is not ok", - visited.allDependenciesVisited(WithDepsSubclass.class)); - } - @Test public void shouldUseByteCodeScannerIfPropertySet() throws Exception { - System.setProperty(Constants.SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE, "true"); + System.setProperty(Constants.SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE, + "true"); DevModeInitializer devModeInitializer = new DevModeInitializer(); final Set> classes = new HashSet<>(); classes.add(NotVisitedWithDeps.class); classes.add(Visited.class); classes.add(RoutedWithReferenceToVisited.class); devModeInitializer.onStartup(classes, servletContext); - ArgumentCaptor arg = ArgumentCaptor - .forClass(VisitedClasses.class); - Mockito.verify(servletContext, Mockito.atLeastOnce()) - .setAttribute(Mockito.eq(VisitedClasses.class.getName()), arg.capture()); - VisitedClasses visitedClasses = arg.getValue(); - Assert.assertTrue(visitedClasses.allDependenciesVisited(RoutedWithReferenceToVisited.class)); - Assert.assertTrue(visitedClasses.allDependenciesVisited(Visited.class)); - Assert.assertFalse(visitedClasses.allDependenciesVisited(NotVisitedWithDeps.class)); + ArgumentCaptor arg = ArgumentCaptor + .forClass(FallbackChunk.class); + Mockito.verify(servletContext, Mockito.atLeastOnce()).setAttribute( + Mockito.eq(FallbackChunk.class.getName()), arg.capture()); + FallbackChunk fallbackChunk = arg.getValue(); + Assert.assertFalse(fallbackChunk.getModules().contains("foo")); + Assert.assertTrue(fallbackChunk.getModules().contains("bar")); } @Test @@ -223,14 +196,9 @@ public void shouldUseFullPathScannerByDefault() throws Exception { classes.add(Visited.class); classes.add(RoutedWithReferenceToVisited.class); devModeInitializer.onStartup(classes, servletContext); - ArgumentCaptor arg = ArgumentCaptor - .forClass(VisitedClasses.class); - Mockito.verify(servletContext, Mockito.atLeastOnce()) - .setAttribute(Mockito.eq(VisitedClasses.class.getName()), arg.capture()); - VisitedClasses visitedClasses = arg.getValue(); - Assert.assertTrue(visitedClasses.allDependenciesVisited(RoutedWithReferenceToVisited.class)); - Assert.assertTrue(visitedClasses.allDependenciesVisited(Visited.class)); - Assert.assertTrue(visitedClasses.allDependenciesVisited(NotVisitedWithDeps.class)); + Mockito.verify(servletContext, Mockito.times(0)).setAttribute( + Mockito.eq(FallbackChunk.class.getName()), + Mockito.any(FallbackChunk.class)); } private void loadingJars_allFilesExist(String resourcesFolder) @@ -238,7 +206,7 @@ private void loadingJars_allFilesExist(String resourcesFolder) // Create jar urls for test URL jar = new URL("jar:" + this.getClass().getResource("/").toString() - .replace("target/test-classes/", "") + .replace("target/test-classes/", "") + "src/test/resources/with%20space/jar-with-frontend-resources.jar!/META-INF/resources/frontend"); List urls = new ArrayList<>(); urls.add(jar); diff --git a/flow-tests/test-npm-only-features/pom.xml b/flow-tests/test-npm-only-features/pom.xml index c44b7067eb9..abf5cefb15e 100644 --- a/flow-tests/test-npm-only-features/pom.xml +++ b/flow-tests/test-npm-only-features/pom.xml @@ -35,6 +35,7 @@ test-npm-custom-frontend-directory test-npm-bytecode-scanning/pom-devmode.xml test-npm-bytecode-scanning/pom-production.xml + test-npm-bytecode-scanning/pom-prod-fallback.xml test-npm-performance-regression diff --git a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-devmode.xml b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-devmode.xml index d3bc3b5db88..706be3d601f 100644 --- a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-devmode.xml +++ b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-devmode.xml @@ -31,6 +31,7 @@ war true + ByteCodeScanningIT,FallbackByteCodeScanningIT diff --git a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-prod-fallback.xml b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-prod-fallback.xml new file mode 100644 index 00000000000..d1c453c0c0a --- /dev/null +++ b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-prod-fallback.xml @@ -0,0 +1,146 @@ + + + + + + flow-test-npm-only-features + com.vaadin + 2.1-SNAPSHOT + + 4.0.0 + + flow-test-npm-bytecode-scanning-fallback-production + + Flow test fallback chunk in production mode + war + + true + true + FullCPScanningIT,ByteCodeScanningIT + + + + + com.vaadin + flow-html-components-testbench + ${project.version} + test + + + + com.vaadin + flow-test-common + ${project.version} + + + + com.vaadin + flow-server-production-mode + ${project.version} + + + + + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty.version} + + + + start-jetty + pre-integration-test + + start + + + + stop-jetty + post-integration-test + + stop + + + + + + + com.vaadin + flow-maven-plugin + ${project.version} + + + + prepare-frontend + build-frontend + + compile + + + + + + + + + local-run + + + !test.use.hub + + + + + + com.lazerycode.selenium + driver-binary-downloader-maven-plugin + + + ${driver.binary.downloader.maven.plugin.version} + + + true + + + ${project.rootdir}/driver + + + ${project.rootdir}/driver_zips + + + ${project.rootdir}/drivers.xml + + + + + pre-integration-test + + selenium + + + + + + + + + diff --git a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-production.xml b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-production.xml index 81dddbda533..7d358f46ffe 100644 --- a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-production.xml +++ b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/pom-production.xml @@ -32,6 +32,7 @@ true true + FullCPScanningIT,FallbackByteCodeScanningIT diff --git a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/ByteCodeScanningView.java b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/ByteCodeScanningView.java index a9788b57597..3b5258c6919 100644 --- a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/ByteCodeScanningView.java +++ b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/ByteCodeScanningView.java @@ -17,9 +17,7 @@ import com.vaadin.flow.component.Component; import com.vaadin.flow.component.html.Div; -import com.vaadin.flow.component.html.Label; import com.vaadin.flow.router.Route; -import com.vaadin.flow.server.VaadinService; @Route("com.vaadin.flow.testnpmonlyfeatures.bytecodescanning.ByteCodeScanningView") public class ByteCodeScanningView extends Div { @@ -28,19 +26,6 @@ public class ByteCodeScanningView extends Div { public static final String COMPONENT_ID = "myButton"; public ByteCodeScanningView() throws Exception { - /* - * Add a label so that the IT can read the current mode. - */ - boolean production = VaadinService.getCurrent() - .getDeploymentConfiguration().isProductionMode(); - Label modeLabel = new Label(Boolean.toString(production)); - modeLabel.setId(MODE_LABEL_ID); - add(modeLabel); - - /* - * Create component using reflection, so that use will not be detected - * by the bytecode scanner. - */ Class clazz = Class.forName( "com.vaadin.flow.testnpmonlyfeatures.bytecodescanning.MyButton"); Component button = (Component) clazz.newInstance(); diff --git a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/RemoveFallbackChunkInfo.java b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/RemoveFallbackChunkInfo.java new file mode 100644 index 00000000000..80cf17aea40 --- /dev/null +++ b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/RemoveFallbackChunkInfo.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.testnpmonlyfeatures.bytecodescanning; + +import javax.servlet.http.HttpServletRequest; + +import com.vaadin.flow.server.ServiceInitEvent; +import com.vaadin.flow.server.VaadinRequest; +import com.vaadin.flow.server.VaadinResponse; +import com.vaadin.flow.server.VaadinServiceInitListener; +import com.vaadin.flow.server.VaadinServletRequest; +import com.vaadin.flow.server.VaadinSession; +import com.vaadin.flow.server.frontend.FallbackChunk; + +/** + * This is a hacky code since it removes {@link FallbackChunk} instance + * per request. + *

+ * Once being removed the {@link FallbackChunk} instance can'be restored for the + * whole application. So one (arbitrary) request changes the behavior of the + * whole application (singleton). This is generally a terrible way of doing + * things but in this specific test case it doesn't cause issues + * currently with the tests (only one in fact) that we have. The + * situation might change in the future. + *

+ * This hack works only if all tests uses "drop-fallback" query parameter + * or don't use it. + */ +public class RemoveFallbackChunkInfo implements VaadinServiceInitListener { + + @Override + public void serviceInit(ServiceInitEvent event) { + event.addRequestHandler(this::handleRequest); + } + + boolean handleRequest(VaadinSession session, VaadinRequest request, + VaadinResponse response) { + VaadinServletRequest servletRequest = (VaadinServletRequest) request; + HttpServletRequest httpRequest = servletRequest.getHttpServletRequest(); + String query = httpRequest.getQueryString(); + if ("drop-fallback".equals(query)) { + // self check + FallbackChunk chunk = session.getService().getContext() + .getAttribute(FallbackChunk.class); + + if (chunk == null) { + throw new RuntimeException( + "Vaadin context has no fallback chunk data"); + } + + // remove fallback chunk data to that the chunk won't be loaded + session.getService().getContext() + .removeAttribute(FallbackChunk.class); + } + return false; + } + +} diff --git a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/resources/META-INF/services/com.vaadin.flow.server.VaadinServiceInitListener b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/resources/META-INF/services/com.vaadin.flow.server.VaadinServiceInitListener new file mode 100644 index 00000000000..4a0d8329e54 --- /dev/null +++ b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/main/resources/META-INF/services/com.vaadin.flow.server.VaadinServiceInitListener @@ -0,0 +1 @@ +com.vaadin.flow.testnpmonlyfeatures.bytecodescanning.RemoveFallbackChunkInfo diff --git a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/ByteCodeScanningIT.java b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/ByteCodeScanningIT.java index 0f237f6d034..ca0c4db45b4 100644 --- a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/ByteCodeScanningIT.java +++ b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/ByteCodeScanningIT.java @@ -18,37 +18,25 @@ import org.junit.Assert; import org.junit.Test; -import com.vaadin.flow.component.html.testbench.LabelElement; import com.vaadin.flow.testutil.ChromeBrowserTest; import com.vaadin.testbench.TestBenchElement; public class ByteCodeScanningIT extends ChromeBrowserTest { @Test - public void buttonIsShownIffInDevMode() { - open(); - - LabelElement modeLabel = $(LabelElement.class) - .id(ByteCodeScanningView.MODE_LABEL_ID); + public void buttonIsNotInitializedInProductionMode() { + // in case of this URL parameter presence the Fallback chunk data will + // be removed and the chunk won't be loaded + open("drop-fallback"); TestBenchElement component = $(TestBenchElement.class) .id(ByteCodeScanningView.COMPONENT_ID); - boolean productionMode = Boolean.parseBoolean(modeLabel.getText()); - boolean hasElementsInShadowRoot = !component.$("button").all() - .isEmpty(); - if (productionMode) { - // in production mode we use optimized bundle by default, so - // component should not be initialized - Assert.assertFalse( - "component expected no initialized in production mode", - hasElementsInShadowRoot); - } else { - // in dev mode we use complete bundle by default, so component - // should be initialized and shown - Assert.assertTrue("component expected initialized in dev mode", - hasElementsInShadowRoot); - } + // in production mode without fallback chunk we use optimized bundle by + // default, so component should not be initialized + Assert.assertTrue( + "component expected not initialized in production mode", + component.$("button").all().isEmpty()); } } diff --git a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/FallbackByteCodeScanningIT.java b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/FallbackByteCodeScanningIT.java new file mode 100644 index 00000000000..20600a911ee --- /dev/null +++ b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/FallbackByteCodeScanningIT.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.testnpmonlyfeatures.bytecodescanning; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.testutil.ChromeBrowserTest; +import com.vaadin.testbench.TestBenchElement; + +public class FallbackByteCodeScanningIT extends ChromeBrowserTest { + + @Test + public void buttonIsInitializedInProductionMode() { + open(); + + TestBenchElement component = $(TestBenchElement.class) + .id(ByteCodeScanningView.COMPONENT_ID); + + // in production mode with fallback chunk component should be + // initialized + Assert.assertFalse("component expected initialized in production mode", + component.$("button").all().isEmpty()); + } + + @Override + protected Class getViewClass() { + return ByteCodeScanningView.class; + } + +} diff --git a/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/FullCPScanningIT.java b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/FullCPScanningIT.java new file mode 100644 index 00000000000..36797e1e2f8 --- /dev/null +++ b/flow-tests/test-npm-only-features/test-npm-bytecode-scanning/src/test/java/com/vaadin/flow/testnpmonlyfeatures/bytecodescanning/FullCPScanningIT.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2018 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.testnpmonlyfeatures.bytecodescanning; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.testutil.ChromeBrowserTest; +import com.vaadin.testbench.TestBenchElement; + +public class FullCPScanningIT extends ChromeBrowserTest { + + @Test + public void buttonIsInitializedInDevMode() { + open(); + + TestBenchElement component = $(TestBenchElement.class) + .id(ByteCodeScanningView.COMPONENT_ID); + + // in dev mode we use complete bundle by default, so component + // should be initialized and shown + Assert.assertFalse("component expected initialized in dev mode", + component.$("button").all().isEmpty()); + } + + @Override + protected Class getViewClass() { + return ByteCodeScanningView.class; + } +} diff --git a/flow-tests/test-npm-only-features/test-npm-performance-regression/src/test/java/com/vaadin/flow/testnpmonlyfeatures/performanceregression/StartupPerformanceIT.java b/flow-tests/test-npm-only-features/test-npm-performance-regression/src/test/java/com/vaadin/flow/testnpmonlyfeatures/performanceregression/StartupPerformanceIT.java index b311d42dbf2..8599e8698e8 100644 --- a/flow-tests/test-npm-only-features/test-npm-performance-regression/src/test/java/com/vaadin/flow/testnpmonlyfeatures/performanceregression/StartupPerformanceIT.java +++ b/flow-tests/test-npm-only-features/test-npm-performance-regression/src/test/java/com/vaadin/flow/testnpmonlyfeatures/performanceregression/StartupPerformanceIT.java @@ -28,45 +28,42 @@ public class StartupPerformanceIT { @Test - public void devModeInitializerToWebpackUpIsBelow5000ms() { + public void devModeInitializerToWebpackUpIsBelow5500ms() { int startupTime = measureLogEntryTimeDistance( "com.vaadin.flow.server.startup.DevModeInitializer - Starting dev-mode updaters in", - "dev-webpack.*Time: [0-9]+ms", - true - ); + "dev-webpack.*Time: [0-9]+ms", true); int npmInstallTime = measureLogEntryTimeDistance( "dev-updater - Running `npm install`", "dev-updater - package.json updated and npm dependencies installed", - false - ); + false); int startupTimeWithoutNpmInstallTime = startupTime - npmInstallTime; - final int thresholdMs = 5000; - Assert.assertTrue(String.format("startup time expected <= %d but was %d", - thresholdMs, startupTimeWithoutNpmInstallTime), + final int thresholdMs = 5500; + Assert.assertTrue( + String.format("startup time expected <= %d but was %d", + thresholdMs, startupTimeWithoutNpmInstallTime), startupTimeWithoutNpmInstallTime <= thresholdMs); } - private int measureLogEntryTimeDistance(String startFragment, String endFragment, - boolean failIfNotFound) { + private int measureLogEntryTimeDistance(String startFragment, + String endFragment, boolean failIfNotFound) { Pattern startPattern = createPattern(startFragment); Pattern endPattern = createPattern(endFragment); AtomicInteger startTime = new AtomicInteger(); AtomicInteger endTime = new AtomicInteger(); try { - Files.lines(getLogPath()) - .forEach(line -> { - Matcher matcherFirst = startPattern.matcher(line); - if (matcherFirst.matches() && startTime.get() == 0) { - startTime.set(Integer.parseInt(matcherFirst.group(1))); - } - Matcher matcherEnd = endPattern.matcher(line); - if (matcherEnd.matches()) { - endTime.set(Integer.parseInt(matcherEnd.group(1))); - } - }); + Files.lines(getLogPath()).forEach(line -> { + Matcher matcherFirst = startPattern.matcher(line); + if (matcherFirst.matches() && startTime.get() == 0) { + startTime.set(Integer.parseInt(matcherFirst.group(1))); + } + Matcher matcherEnd = endPattern.matcher(line); + if (matcherEnd.matches()) { + endTime.set(Integer.parseInt(matcherEnd.group(1))); + } + }); if (startTime.get() == 0 && failIfNotFound) { throw new RuntimeException("No match: " + startFragment); }