mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-01-10 18:37:57 +01:00
[#820] Regression tests using Selenium
- Added Selenium test dependency - Added Awaitility test dependency - Added SeleniumDriver junit Rule that uses Chrome WebDriver - Added all web files to Mocker in withPluginFiles() - Added JSErrorRegressionTest - Fixed Debug page error when testing - Fixed BukkitTaskSystem error during tests - Fixed missing demo.js from HtmlExport These tests should prevent most issues of broken page in the future.
This commit is contained in:
parent
7e2ff40898
commit
b9fa29544d
@ -31,6 +31,7 @@ import com.djrapitops.plugin.task.RunnableFactory;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@ -88,6 +89,6 @@ public class BukkitTaskSystem extends ServerTaskSystem {
|
||||
@Override
|
||||
public void disable() {
|
||||
super.disable();
|
||||
Bukkit.getScheduler().cancelTasks(plugin);
|
||||
Optional.ofNullable(Bukkit.getScheduler()).ifPresent(scheduler -> scheduler.cancelTasks(plugin));
|
||||
}
|
||||
}
|
||||
|
@ -174,6 +174,7 @@ public class HtmlExport extends SpecificExport {
|
||||
|
||||
private void exportJs() {
|
||||
String[] resources = new String[]{
|
||||
"web/js/demo.js",
|
||||
"web/js/admin.js",
|
||||
"web/js/helpers.js",
|
||||
"web/js/script.js",
|
||||
|
@ -60,7 +60,7 @@ public class DebugPage implements Page {
|
||||
private final ConnectionSystem connectionSystem;
|
||||
private final CombineDebugLogger debugLogger;
|
||||
private final Timings timings;
|
||||
private final DefaultErrorHandler errorHandler;
|
||||
private final ErrorHandler errorHandler;
|
||||
|
||||
private final Formatter<DateHolder> secondFormatter;
|
||||
private final Formatter<Long> yearFormatter;
|
||||
@ -79,7 +79,7 @@ public class DebugPage implements Page {
|
||||
this.connectionSystem = connectionSystem;
|
||||
this.debugLogger = (CombineDebugLogger) debugLogger;
|
||||
this.timings = timings;
|
||||
this.errorHandler = (DefaultErrorHandler) errorHandler;
|
||||
this.errorHandler = errorHandler;
|
||||
|
||||
this.secondFormatter = formatters.second();
|
||||
this.yearFormatter = formatters.yearLong();
|
||||
@ -268,6 +268,16 @@ public class DebugPage implements Page {
|
||||
private void appendLoggedErrors(StringBuilder content) {
|
||||
content.append("<pre>### Logged Errors<br>");
|
||||
|
||||
if (errorHandler instanceof DefaultErrorHandler) {
|
||||
appendErrorLines(content, (DefaultErrorHandler) errorHandler);
|
||||
} else {
|
||||
content.append("Using incompatible ErrorHandler");
|
||||
}
|
||||
|
||||
content.append("</pre>");
|
||||
}
|
||||
|
||||
private void appendErrorLines(StringBuilder content, DefaultErrorHandler errorHandler) {
|
||||
List<String> lines = errorHandler.getErrorHandler(FolderTimeStampErrorFileLogger.class)
|
||||
.flatMap(FolderTimeStampFileLogger::getCurrentFile)
|
||||
.map(file -> {
|
||||
@ -300,7 +310,6 @@ public class DebugPage implements Page {
|
||||
} else {
|
||||
content.append("**No Errors logged.**<br>");
|
||||
}
|
||||
content.append("</pre>");
|
||||
}
|
||||
|
||||
private void appendDebugLog(StringBuilder content) {
|
||||
|
@ -32,6 +32,9 @@
|
||||
<!-- AdminBSB Themes. You can choose a theme from css/themes instead of get all themes -->
|
||||
<link href="../css/themes/all-themes.css" rel="stylesheet"/>
|
||||
|
||||
<!-- Jquery Core Js -->
|
||||
<script src="../plugins/jquery/jquery.min.js"></script>
|
||||
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
|
||||
@ -795,9 +798,6 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Jquery Core Js -->
|
||||
<script src="../plugins/jquery/jquery.min.js"></script>
|
||||
|
||||
<!-- Bootstrap Core Js -->
|
||||
<script src="../plugins/bootstrap/js/bootstrap.js"></script>
|
||||
|
||||
|
@ -5,10 +5,12 @@
|
||||
package utilities.mocks;
|
||||
|
||||
import com.djrapitops.plan.PlanPlugin;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Abstract Mocker for methods that can be used for both Bungee and Bukkit.
|
||||
@ -58,14 +60,61 @@ abstract class Mocker {
|
||||
}
|
||||
|
||||
void withPluginFiles() throws Exception {
|
||||
withPluginFile("bungeeconfig.yml");
|
||||
withPluginFile("config.yml");
|
||||
withPluginFile("web/server.html");
|
||||
withPluginFile("web/player.html");
|
||||
withPluginFile("web/network.html");
|
||||
withPluginFile("web/error.html");
|
||||
withPluginFile("themes/theme.yml");
|
||||
withPluginFile("DefaultServerInfoFile.yml");
|
||||
when(planMock.getResource(Mockito.anyString())).thenCallRealMethod();
|
||||
for (String fileName : new String[]{
|
||||
"bungeeconfig.yml",
|
||||
"config.yml",
|
||||
"DefaultServerInfoFile.yml",
|
||||
"themes/theme.yml",
|
||||
|
||||
"web/server.html",
|
||||
"web/player.html",
|
||||
"web/network.html",
|
||||
"web/error.html",
|
||||
|
||||
"web/css/main.css",
|
||||
"web/css/materialize.css",
|
||||
"web/css/style.css",
|
||||
"web/css/themes/all-themes.css",
|
||||
|
||||
"web/js/demo.js",
|
||||
"web/js/admin.js",
|
||||
"web/js/helpers.js",
|
||||
"web/js/script.js",
|
||||
"web/js/charts/activityPie.js",
|
||||
"web/js/charts/lineGraph.js",
|
||||
"web/js/charts/horizontalBarGraph.js",
|
||||
"web/js/charts/stackGraph.js",
|
||||
"web/js/charts/performanceGraph.js",
|
||||
"web/js/charts/playerGraph.js",
|
||||
"web/js/charts/playerGraphNoNav.js",
|
||||
"web/js/charts/resourceGraph.js",
|
||||
"web/js/charts/diskGraph.js",
|
||||
"web/js/charts/tpsGraph.js",
|
||||
"web/js/charts/worldGraph.js",
|
||||
"web/js/charts/worldMap.js",
|
||||
"web/js/charts/punchCard.js",
|
||||
"web/js/charts/serverPie.js",
|
||||
"web/js/charts/worldPie.js",
|
||||
"web/js/charts/healthGauge.js",
|
||||
"web/js/charts/sessionCalendar.js",
|
||||
"web/js/charts/onlineActivityCalendar.js",
|
||||
|
||||
"web/plugins/bootstrap/css/bootstrap.css",
|
||||
"web/plugins/node-waves/waves.css",
|
||||
"web/plugins/node-waves/waves.js",
|
||||
"web/plugins/animate-css/animate.css",
|
||||
"web/plugins/jquery-slimscroll/jquery.slimscroll.js",
|
||||
"web/plugins/jquery/jquery.min.js",
|
||||
"web/plugins/bootstrap/js/bootstrap.js",
|
||||
"web/plugins/jquery-datatable/skin/bootstrap/js/dataTables.bootstrap.js",
|
||||
"web/plugins/jquery-datatable/jquery.dataTables.js",
|
||||
"web/plugins/fullcalendar/fullcalendar.min.js",
|
||||
"web/plugins/fullcalendar/fullcalendar.min.css",
|
||||
"web/plugins/momentjs/moment.js"
|
||||
}) {
|
||||
withPluginFile(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,128 @@
|
||||
package com.djrapitops.plan.system.webserver;
|
||||
|
||||
import com.djrapitops.plan.DaggerPlanBukkitComponent;
|
||||
import com.djrapitops.plan.PlanBukkitComponent;
|
||||
import com.djrapitops.plan.data.container.Session;
|
||||
import com.djrapitops.plan.system.PlanSystem;
|
||||
import com.djrapitops.plan.system.database.DBSystem;
|
||||
import com.djrapitops.plan.system.database.databases.operation.SaveOperations;
|
||||
import com.djrapitops.plan.system.settings.Settings;
|
||||
import com.djrapitops.plan.system.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.system.webserver.cache.PageId;
|
||||
import com.djrapitops.plan.system.webserver.cache.ResponseCache;
|
||||
import com.jayway.awaitility.Awaitility;
|
||||
import org.junit.*;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import rules.SeleniumDriver;
|
||||
import utilities.TestConstants;
|
||||
import utilities.mocks.PlanBukkitMocker;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* This test class is for catching any JavaScript errors.
|
||||
* <p>
|
||||
* Errors may have been caused by:
|
||||
* - Missing placeholders {@code ${placeholder}} inside {@code <script>} tags.
|
||||
* - Automatic formatting of plugin javascript (See https://github.com/Rsl1122/Plan-PlayerAnalytics/issues/820)
|
||||
* - Missing file definition in {@link utilities.mocks.Mocker}
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||
public class JSErrorRegressionTest {
|
||||
|
||||
@ClassRule
|
||||
public static TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
@ClassRule
|
||||
public static SeleniumDriver seleniumDriver = new SeleniumDriver();
|
||||
|
||||
private static PlanSystem bukkitSystem;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
PlanBukkitMocker mocker = PlanBukkitMocker.setUp()
|
||||
.withDataFolder(temporaryFolder.getRoot())
|
||||
.withPluginDescription()
|
||||
.withResourceFetchingFromJar()
|
||||
.withServer();
|
||||
PlanBukkitComponent component = DaggerPlanBukkitComponent.builder().plan(mocker.getPlanMock()).build();
|
||||
|
||||
bukkitSystem = component.system();
|
||||
|
||||
PlanConfig config = bukkitSystem.getConfigSystem().getConfig();
|
||||
config.set(Settings.WEBSERVER_PORT, 9005);
|
||||
|
||||
bukkitSystem.enable();
|
||||
savePlayerData();
|
||||
}
|
||||
|
||||
private static void savePlayerData() {
|
||||
DBSystem dbSystem = bukkitSystem.getDatabaseSystem();
|
||||
SaveOperations save = dbSystem.getDatabase().save();
|
||||
UUID uuid = TestConstants.PLAYER_ONE_UUID;
|
||||
save.registerNewUser(uuid, 1000L, "TestPlayer");
|
||||
Session session = new Session(uuid, TestConstants.SERVER_UUID, 1000L, "world", "SURVIVAL");
|
||||
session.endSession(11000L);
|
||||
save.session(uuid, session);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDownTest() {
|
||||
seleniumDriver.newTab();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
if (bukkitSystem != null) {
|
||||
bukkitSystem.disable();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void playerPageDoesNotHaveJavascriptErrors() {
|
||||
System.out.println("Testing Player Page");
|
||||
WebDriver driver = seleniumDriver.getDriver();
|
||||
driver.get("http://localhost:9005/player/TestPlayer");
|
||||
assertFalse(driver.getPageSource(), driver.getPageSource().contains("500 Internal Error occurred"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serverPageDoesNotHaveJavascriptErrors() {
|
||||
System.out.println("Testing Server Page");
|
||||
WebDriver driver = seleniumDriver.getDriver();
|
||||
// Open the page that has refreshing info
|
||||
driver.get("http://localhost:9005/server");
|
||||
assertFalse(driver.getPageSource(), driver.getPageSource().contains("500 Internal Error occurred"));
|
||||
|
||||
// Wait until Plan caches analysis results
|
||||
Awaitility.await()
|
||||
.atMost(5, TimeUnit.SECONDS)
|
||||
.until(() -> ResponseCache.isCached(PageId.SERVER.of(TestConstants.SERVER_UUID)));
|
||||
|
||||
// Open the page with analysis stuff
|
||||
seleniumDriver.newTab();
|
||||
driver.get("http://localhost:9005/server");
|
||||
assertFalse(driver.getPageSource(), driver.getPageSource().contains("500 Internal Error occurred"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void playersPageDoesNotHaveJavascriptErrors() {
|
||||
System.out.println("Testing Players Page");
|
||||
WebDriver driver = seleniumDriver.getDriver();
|
||||
driver.get("http://localhost:9005/players");
|
||||
assertFalse(driver.getPageSource(), driver.getPageSource().contains("500 Internal Error occurred"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debugPageDoesNotHaveJavascriptErrors() {
|
||||
System.out.println("Testing Debug Page");
|
||||
WebDriver driver = seleniumDriver.getDriver();
|
||||
driver.get("http://localhost:9005/debug");
|
||||
assertFalse(driver.getPageSource(), driver.getPageSource().contains("500 Internal Error occurred"));
|
||||
}
|
||||
}
|
70
Plan/plugin/src/test/java/rules/SeleniumDriver.java
Normal file
70
Plan/plugin/src/test/java/rules/SeleniumDriver.java
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of Player Analytics (Plan).
|
||||
*
|
||||
* Plan is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License v3 as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Plan is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package rules;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.junit.Assume;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.Keys;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.chrome.ChromeDriver;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class SeleniumDriver extends ExternalResource {
|
||||
|
||||
private WebDriver driver;
|
||||
|
||||
@Override
|
||||
protected void before() {
|
||||
String driverLocation = getChromeDriverLocation();
|
||||
Assume.assumeNotNull("rules.SeleniumDriver: Chrome driver location not specified for this OS type", driverLocation);
|
||||
Assume.assumeTrue("rules.SeleniumDriver: Chrome driver not found at " + driverLocation, new File(driverLocation).exists());
|
||||
|
||||
System.setProperty("webdriver.chrome.driver", driverLocation);
|
||||
driver = new ChromeDriver();
|
||||
}
|
||||
|
||||
private String getChromeDriverLocation() {
|
||||
if (SystemUtils.IS_OS_LINUX) {
|
||||
return "/usr/local/share/chromedriver";
|
||||
} else if (SystemUtils.IS_OS_WINDOWS) {
|
||||
return "C:\\chromedriver.exe";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void newTab() {
|
||||
WebElement body = driver.findElement(By.tagName("body"));
|
||||
body.sendKeys(Keys.CONTROL + "t");
|
||||
driver.switchTo().window(new ArrayList<>(driver.getWindowHandles()).get(0));
|
||||
}
|
||||
|
||||
public WebDriver getDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void after() {
|
||||
if (driver != null) {
|
||||
driver.quit();
|
||||
}
|
||||
}
|
||||
}
|
14
Plan/pom.xml
14
Plan/pom.xml
@ -59,7 +59,6 @@
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>2.23.4</version>
|
||||
<type>jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -80,6 +79,19 @@
|
||||
<version>1.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
<artifactId>selenium-java</artifactId>
|
||||
<version>3.14.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jayway.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Dependency injection is used across the whole project.-->
|
||||
<dependency>
|
||||
|
Loading…
Reference in New Issue
Block a user