diff --git a/web/client-api/src/test/java/io/deephaven/web/ClientIntegrationTestSuite.java b/web/client-api/src/test/java/io/deephaven/web/ClientIntegrationTestSuite.java
index 3c3aa8791ca..7f3eb1c60a4 100644
--- a/web/client-api/src/test/java/io/deephaven/web/ClientIntegrationTestSuite.java
+++ b/web/client-api/src/test/java/io/deephaven/web/ClientIntegrationTestSuite.java
@@ -9,6 +9,7 @@
import io.deephaven.web.client.api.storage.JsStorageServiceTestGwt;
import io.deephaven.web.client.api.subscription.ConcurrentTableTestGwt;
import io.deephaven.web.client.api.subscription.ViewportTestGwt;
+import io.deephaven.web.client.api.widget.plot.ChartDataTestGwt;
import io.deephaven.web.client.fu.LazyPromiseTestGwt;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -32,6 +33,7 @@ public static Test suite() {
suite.addTestSuite(InputTableTestGwt.class);
suite.addTestSuite(ColumnStatisticsTestGwt.class);
suite.addTestSuite(GrpcTransportTestGwt.class);
+ suite.addTestSuite(ChartDataTestGwt.class);
// This should be a unit test, but it requires a browser environment to run on GWT 2.9
// GWT 2.9 doesn't have proper bindings for Promises in HtmlUnit, so we need to use the IntegrationTest suite
diff --git a/web/client-api/src/test/java/io/deephaven/web/CustomTransportTest.gwt.xml b/web/client-api/src/test/java/io/deephaven/web/CustomTransportTest.gwt.xml
new file mode 100644
index 00000000000..36e00484fd6
--- /dev/null
+++ b/web/client-api/src/test/java/io/deephaven/web/CustomTransportTest.gwt.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/web/client-api/src/test/java/io/deephaven/web/client/api/grpc/GrpcTransportTestGwt.java b/web/client-api/src/test/java/io/deephaven/web/client/api/grpc/GrpcTransportTestGwt.java
index 020c65b771a..2a9ff5d5792 100644
--- a/web/client-api/src/test/java/io/deephaven/web/client/api/grpc/GrpcTransportTestGwt.java
+++ b/web/client-api/src/test/java/io/deephaven/web/client/api/grpc/GrpcTransportTestGwt.java
@@ -16,7 +16,8 @@
public class GrpcTransportTestGwt extends AbstractAsyncGwtTestCase {
@Override
public String getModuleName() {
- return "io.deephaven.web.DeephavenIntegrationTest";
+ // This test runs in its own module to avoid risking poisoning other tests with its broken custom transports
+ return "io.deephaven.web.CustomTransportTest";
}
/**
diff --git a/web/client-api/src/test/java/io/deephaven/web/client/api/widget/plot/ChartDataTestGwt.java b/web/client-api/src/test/java/io/deephaven/web/client/api/widget/plot/ChartDataTestGwt.java
new file mode 100644
index 00000000000..c2d0d568822
--- /dev/null
+++ b/web/client-api/src/test/java/io/deephaven/web/client/api/widget/plot/ChartDataTestGwt.java
@@ -0,0 +1,87 @@
+package io.deephaven.web.client.api.widget.plot;
+
+import elemental2.promise.Promise;
+import io.deephaven.web.client.api.AbstractAsyncGwtTestCase;
+import io.deephaven.web.client.api.subscription.AbstractTableSubscription;
+import io.deephaven.web.client.api.subscription.TableSubscription;
+
+public class ChartDataTestGwt extends AbstractAsyncGwtTestCase {
+ private final AbstractAsyncGwtTestCase.TableSourceBuilder tables = new AbstractAsyncGwtTestCase.TableSourceBuilder()
+ .script("from deephaven import time_table")
+ .script("appending_table", "time_table('PT0.1s').update([\"A = i % 2\", \"B = `` + A\"])")
+ .script("updating_table", "appending_table.last_by('A')");
+
+ @Override
+ public String getModuleName() {
+ return "io.deephaven.web.DeephavenIntegrationTest";
+ }
+
+ public void testAppendingChartData() {
+ connect(tables)
+ .then(table("appending_table"))
+ .then(table -> {
+ ChartData chartData = new ChartData(table);
+ TableSubscription sub = table.subscribe(table.getColumns());
+
+ // Handle at least one event with data
+ int[] count = {0};
+
+ return new Promise((resolve, reject) -> {
+ delayTestFinish(12301);
+ sub.addEventListener(TableSubscription.EVENT_UPDATED, event -> {
+ AbstractTableSubscription.SubscriptionEventData data = (AbstractTableSubscription.SubscriptionEventData) event.getDetail();
+ chartData.update(data);
+
+ if (count[0] > 0) {
+ // Don't test on the first update, could still be empty
+ assertTrue(chartData.getColumn("A", arr -> arr, data).length > 0);
+
+ resolve.onInvoke(data);
+ }
+ count[0]++;
+ });
+ }).then(data -> {
+ sub.close();
+ table.close();
+ return Promise.resolve(data);
+ });
+ })
+ .then(this::finish).catch_(this::report);
+ }
+
+ public void testModifiedChartData() {
+ connect(tables)
+ .then(table("updating_table"))
+ .then(table -> {
+ ChartData chartData = new ChartData(table);
+ TableSubscription sub = table.subscribe(table.getColumns());
+
+ int[] count = {0};
+ return new Promise((resolve, reject) -> {
+ delayTestFinish(12302);
+ sub.addEventListener(TableSubscription.EVENT_UPDATED, event -> {
+
+ AbstractTableSubscription.SubscriptionEventData data = (AbstractTableSubscription.SubscriptionEventData) event.getDetail();
+
+ chartData.update(data);
+ if (count[0] > 0) {
+ // Don't test on the first update, could still be empty
+ assertTrue(chartData.getColumn("A", arr -> arr, data).length > 0);
+ }
+
+ if (count[0] > 2) {
+ // We've seen at least three updates, and must have modified rows at least once
+ resolve.onInvoke((AbstractTableSubscription.SubscriptionEventData) event.getDetail());
+ }
+ count[0]++;
+ });
+ })
+ .then(data -> {
+ sub.close();
+ table.close();
+ return Promise.resolve(data);
+ });
+ })
+ .then(this::finish).catch_(this::report);
+ }
+}