Skip to content

Commit e2b54d3

Browse files
committed
Add IT test for service worker and runtime
Fixes #2867
1 parent 7e3b139 commit e2b54d3

File tree

9 files changed

+254
-0
lines changed

9 files changed

+254
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { LitElement, html } from 'lit';
2+
import { customElement } from 'lit/decorators.js';
3+
4+
@customElement('about-view')
5+
export class AboutView extends LitElement {
6+
render() {
7+
return html` <div>About</div> `;
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!doctype html>
2+
<!--
3+
This file is auto-generated by Vaadin.
4+
-->
5+
6+
<html lang="en">
7+
<head>
8+
<title>ITs for Endpoints</title>
9+
<meta charset="UTF-8" />
10+
<meta name="viewport" content="width=device-width, initial-scale=1" />
11+
<style>
12+
body,
13+
#outlet {
14+
height: 100vh;
15+
width: 100%;
16+
margin: 0;
17+
}
18+
</style>
19+
<!-- index.ts is included here automatically (either by the dev server or during the build) -->
20+
</head>
21+
<body>
22+
<!-- This outlet div is where the views are rendered -->
23+
<div id="outlet"></div>
24+
</body>
25+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import './test-view.js';
2+
import './about-view.js';
3+
import { Route, Router } from '@vaadin/router';
4+
5+
const routes: Route[] = [{ path: '/', component: 'test-view' },
6+
{ path: '/about-view', component: 'about-view' }];
7+
8+
// Vaadin router needs an outlet in the index.html page to display views
9+
const router = new Router(document.querySelector('#outlet'));
10+
router.setRoutes(routes);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { LitElement, html } from 'lit';
2+
import { customElement } from 'lit/decorators.js';
3+
4+
@customElement('test-view')
5+
export class TestView extends LitElement {
6+
render() {
7+
return html` <div>Hello</div> `;
8+
}
9+
}
+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>com.vaadin</groupId>
8+
<artifactId>tests-spring</artifactId>
9+
<version>24.6-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>tests-hilla-runtime</artifactId>
13+
14+
<properties>
15+
<maven.deploy.skip>true</maven.deploy.skip>
16+
<formatter.basedir>${project.parent.parent.parent.basedir}</formatter.basedir>
17+
</properties>
18+
19+
<dependencies>
20+
<dependency>
21+
<groupId>com.vaadin</groupId>
22+
<artifactId>hilla</artifactId>
23+
</dependency>
24+
<dependency>
25+
<groupId>org.springframework.boot</groupId>
26+
<artifactId>spring-boot-starter-security</artifactId>
27+
</dependency>
28+
<dependency>
29+
<groupId>org.springframework.boot</groupId>
30+
<artifactId>spring-boot-starter-test</artifactId>
31+
<scope>test</scope>
32+
</dependency>
33+
</dependencies>
34+
35+
<build>
36+
<defaultGoal>spring-boot:run</defaultGoal>
37+
<plugins>
38+
<plugin>
39+
<groupId>com.vaadin</groupId>
40+
<artifactId>hilla-maven-plugin</artifactId>
41+
</plugin>
42+
43+
<plugin>
44+
<groupId>org.springframework.boot</groupId>
45+
<artifactId>spring-boot-maven-plugin</artifactId>
46+
</plugin>
47+
</plugins>
48+
</build>
49+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.vaadin.flow.connect;
2+
3+
import com.vaadin.flow.component.page.AppShellConfigurator;
4+
import com.vaadin.flow.server.PWA;
5+
import org.springframework.boot.SpringApplication;
6+
import org.springframework.boot.autoconfigure.SpringBootApplication;
7+
8+
/**
9+
* The entry point of the Spring Boot application.
10+
*/
11+
@SpringBootApplication
12+
@PWA(name = "My App", shortName = "app")
13+
public class Application implements AppShellConfigurator {
14+
15+
public static void main(String[] args) {
16+
SpringApplication.run(Application.class, args);
17+
}
18+
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.vaadin.flow.connect;
2+
3+
import com.vaadin.flow.spring.security.VaadinWebSecurity;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
7+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
8+
import org.springframework.security.core.userdetails.User;
9+
import org.springframework.security.core.userdetails.UserDetails;
10+
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
11+
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
12+
13+
@EnableWebSecurity
14+
@Configuration
15+
public class SecurityConfig extends VaadinWebSecurity {
16+
17+
@Override
18+
protected void configure(HttpSecurity http) throws Exception {
19+
http.csrf(h -> h.ignoringRequestMatchers(new AntPathRequestMatcher("/login")));
20+
http.authorizeHttpRequests(
21+
h -> h.requestMatchers(new AntPathRequestMatcher("/"))
22+
.permitAll());
23+
http.authorizeHttpRequests(
24+
h -> h.requestMatchers(new AntPathRequestMatcher("/about-view"))
25+
.permitAll());
26+
super.configure(http);
27+
setLoginView(http, "/login");
28+
}
29+
30+
@Bean
31+
public InMemoryUserDetailsManager userDetailsService() {
32+
// Configure users and roles in memory
33+
UserDetails user = User.withUsername("user").password("{noop}user")
34+
.roles("USER").build();
35+
UserDetails admin = User.withUsername("admin").password("{noop}admin")
36+
.roles("ADMIN", "USER").build();
37+
return new InMemoryUserDetailsManager(user, admin);
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
server.port=8888
2+
vaadin.devmode.liveReload.enabled=false
3+
logging.level.org.atmosphere = warn
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2000-2024 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.vaadin.flow.connect;
17+
18+
import com.vaadin.flow.testutil.ChromeDeviceTest;
19+
import org.junit.Assert;
20+
import org.junit.Test;
21+
import org.openqa.selenium.By;
22+
import org.openqa.selenium.JavascriptExecutor;
23+
24+
public class ServiceWorkerIT extends ChromeDeviceTest {
25+
26+
@Test
27+
public void onlineRoot_serviceWorkerInstalled_serviceWorkerActive() {
28+
getDriver().get(getRootURL() + "/");
29+
waitForDevServer();
30+
waitForServiceWorkerReady();
31+
32+
boolean serviceWorkerActive = (boolean) ((JavascriptExecutor) getDriver())
33+
.executeAsyncScript(
34+
"const resolve = arguments[arguments.length - 1];"
35+
+ "navigator.serviceWorker.ready.then( function(reg) { resolve(!!reg.active); });");
36+
Assert.assertTrue("service worker not installed", serviceWorkerActive);
37+
}
38+
39+
@Test
40+
public void offlineRoot_reload_viewReloaded() {
41+
openPageAndPreCacheWhenDevelopmentMode("/");
42+
43+
// Confirm that app shell is loaded
44+
Assert.assertNotNull("Should have outlet when loaded online",
45+
findElement(By.id("outlet")));
46+
47+
// Confirm that client side view is loaded
48+
Assert.assertNotNull(
49+
"Should have <test-view> in DOM when loaded online",
50+
findElement(By.tagName("test-view")));
51+
52+
// Reload the page in offline mode
53+
executeScript("window.location.reload();");
54+
waitUntil(webDriver -> ((JavascriptExecutor) driver)
55+
.executeScript("return document.readyState")
56+
.equals("complete"));
57+
}
58+
59+
private void openPageAndPreCacheWhenDevelopmentMode(String targetView) {
60+
openPageAndPreCacheWhenDevelopmentMode(targetView, () -> {
61+
});
62+
}
63+
64+
private void openPageAndPreCacheWhenDevelopmentMode(String targetView,
65+
Runnable activateViews) {
66+
getDriver().get(getRootURL() + targetView);
67+
waitForDevServer();
68+
waitForServiceWorkerReady();
69+
70+
boolean isDevMode = Boolean.getBoolean("vaadin.test.developmentMode");
71+
if (isDevMode) {
72+
// In production mode all views are supposed to be already in the
73+
// bundle, but in dev mode they are loaded at runtime
74+
// So, for dev mode, pre cache required views
75+
activateViews.run();
76+
77+
// In addition not all external resources are cached when the page
78+
// opens
79+
// first time, so we need to reload the page even if there is no
80+
// navigation to other views
81+
getDriver().get(getRootURL() + targetView);
82+
waitForDevServer();
83+
waitForServiceWorkerReady();
84+
}
85+
}
86+
87+
@Override
88+
protected String getRootURL() {
89+
return super.getRootURL();
90+
}
91+
}

0 commit comments

Comments
 (0)