You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ze...@apache.org on 2021/10/17 08:58:00 UTC

[incubator-streampipes] branch dev updated: [hotfix] Add e2e tests for data explorer. Minor bug fixes

This is an automated email from the ASF dual-hosted git repository.

zehnder pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new 568e8db  [hotfix] Add e2e tests for data explorer. Minor bug fixes
568e8db is described below

commit 568e8dbb5c2396845313b1a3f27c79d8a54272f4
Author: Philipp Zehnder <ze...@fzi.de>
AuthorDate: Sun Oct 17 10:57:32 2021 +0200

    [hotfix] Add e2e tests for data explorer. Minor bug fixes
---
 .../dataexplorer/v4/params/WhereCondition.java     |  12 ++
 .../v4/params/WhereStatementParams.java            |  14 ++-
 .../v4/params/WhereStatementParamsTest.java        |  57 +++++++++
 .../java/org/apache/streampipes/rest/TestUtil.java |  82 ------------
 ui/cypress/fixtures/datalake/sample.csv            |  11 ++
 .../cypress/support/model/DataLakeFilterConfig.ts  |  15 ++-
 ui/cypress/support/utils/DataLakeUtils.ts          | 140 +++++++++++++++++++--
 ui/cypress/tests/datalake/configuration.ts         |  55 ++------
 .../tests/datalake/widgetDataConfiguration.ts      |  98 +++++++++++++++
 ui/cypress/tests/datalake/widgets/table.ts         |  60 +++++++++
 .../data-explorer-designer-panel.component.html    |  18 ++-
 ...ta-explorer-widget-data-settings.component.html |   6 +-
 .../field-selection-panel.component.html           |   1 +
 .../filter-selection-panel.component.html          |  13 +-
 ...-explorer-visualisation-settings.component.html |   5 +-
 ...data-explorer-dashboard-overview.component.html |  11 +-
 .../time-selector/timeRangeSelector.component.html |  14 ++-
 .../widgets/table/table-widget.component.html      |   4 +-
 ...a-explorer-edit-data-view-dialog.component.html |   8 +-
 19 files changed, 455 insertions(+), 169 deletions(-)

diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereCondition.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereCondition.java
index 47dee9e..fafac95 100644
--- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereCondition.java
+++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereCondition.java
@@ -41,4 +41,16 @@ public class WhereCondition {
             .add(condition)
             .toString();
   }
+
+  public String getField() {
+    return field;
+  }
+
+  public String getOperator() {
+    return operator;
+  }
+
+  public String getCondition() {
+    return condition;
+  }
 }
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParams.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParams.java
index 78ee612..e3dbd84 100644
--- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParams.java
+++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParams.java
@@ -17,6 +17,7 @@
  */
 package org.apache.streampipes.dataexplorer.v4.params;
 
+import org.apache.commons.lang3.math.NumberUtils;
 import org.apache.streampipes.dataexplorer.v4.utils.DataLakeManagementUtils;
 
 import java.util.ArrayList;
@@ -92,11 +93,22 @@ public class WhereStatementParams extends QueryParamsV4 {
 
   private void buildConditions(String whereConditions) {
     List<String[]> whereParts = DataLakeManagementUtils.buildConditions(whereConditions);
+    // Add single quotes to strings except for true and false
     whereParts.forEach(singleCondition -> {
-      this.whereConditions.add(new WhereCondition(singleCondition[0], singleCondition[1], singleCondition[2]));
+
+      this.whereConditions.add(new WhereCondition(singleCondition[0], singleCondition[1], this.returnCondition(singleCondition[2])));
     });
   }
 
+  private String returnCondition(String inputCondition) {
+    if (NumberUtils.isCreatable(inputCondition) || Boolean.parseBoolean(inputCondition)) {
+      return inputCondition;
+    } else {
+      return "'" + inputCondition + "'";
+    }
+
+  }
+
   public List<WhereCondition> getWhereConditions() {
     return whereConditions;
   }
diff --git a/streampipes-rest/src/test/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParamsTest.java b/streampipes-rest/src/test/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParamsTest.java
new file mode 100644
index 0000000..c58f6f2
--- /dev/null
+++ b/streampipes-rest/src/test/java/org/apache/streampipes/dataexplorer/v4/params/WhereStatementParamsTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.streampipes.dataexplorer.v4.params;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class WhereStatementParamsTest {
+    @Test
+    public void filterNumber() {
+        WhereStatementParams result = WhereStatementParams.from("", "[fieldName;=;6]");
+        WhereCondition expected = new WhereCondition("fieldName", "=", "6");
+
+        assertWhereCondition(result, expected);
+    }
+
+    @Test
+    public void filterBoolean() {
+        WhereStatementParams result = WhereStatementParams.from("", "[fieldName;=;true]");
+        WhereCondition expected = new WhereCondition("fieldName", "=", "true");
+
+        assertWhereCondition(result, expected);
+    }
+
+    @Test
+    public void filterString() {
+        WhereStatementParams result = WhereStatementParams.from("", "[fieldName;=;a]");
+        WhereCondition expected = new WhereCondition("fieldName", "=", "'a'");
+
+        assertWhereCondition(result, expected);
+    }
+    private void assertWhereCondition(WhereStatementParams result, WhereCondition expected) {
+        assertEquals(1, result.getWhereConditions().size());
+        WhereCondition resultingWhereCondition = result.getWhereConditions().get(0);
+        assertEquals(expected.getField(), resultingWhereCondition.getField());
+        assertEquals(expected.getOperator(), resultingWhereCondition.getOperator());
+        assertEquals(expected.getCondition(), resultingWhereCondition.getCondition());
+    }
+
+
+}
\ No newline at end of file
diff --git a/streampipes-rest/src/test/java/org/apache/streampipes/rest/TestUtil.java b/streampipes-rest/src/test/java/org/apache/streampipes/rest/TestUtil.java
deleted file mode 100644
index 3ff28e3..0000000
--- a/streampipes-rest/src/test/java/org/apache/streampipes/rest/TestUtil.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.rest;
-
-public class TestUtil {
-
-    public static String getMinimalStreamAdapterJsonLD() {
-        return getMinimalAdapterJsonLD("sp:AdapterStreamDescription");
-    }
-
-    public static String getMinimalSetAdapterJsonLD() {
-        return getMinimalAdapterJsonLD("sp:AdapterSetDescription");
-    }
-
-    public static String getMinimalAdapterJsonLD(String type) {
-        return "{\n" +
-                "  \"@graph\" : [ {\n" +
-                "    \"@id\" : \"http://test.de/1\",\n" +
-                "    \"@type\" : \""+ type + "\",\n" +
-                "    \"http://www.w3.org/2000/01/rdf-schema#label\" : \"TestAdapterDescription\",\n" +
-                "    \"sp:hasDataSet\" : {\n" +
-                "      \"@id\" : \"urn:fzi.de:eventstream:lDVmMJ\"\n" +
-                "    },\n" +
-                "    \"sp:hasUri\" : \"http://test.de/1\"\n" +
-                "  }, {\n" +
-                "    \"@id\" : \"urn:fzi.de:eventstream:lDVmMJ\",\n" +
-                "    \"@type\" : \"sp:DataSet\",\n" +
-                "    \"sp:hasUri\" : \"urn:fzi.de:eventstream:lDVmMJ\"\n" +
-                "  } ],\n" +
-                "  \"@context\" : {\n" +
-                "    \"sp\" : \"https://streampipes.org/vocabulary/v1/\",\n" +
-                "    \"ssn\" : \"http://purl.oclc.org/NET/ssnx/ssn#\",\n" +
-                "    \"xsd\" : \"http://www.w3.org/2001/XMLSchema#\",\n" +
-                "    \"empire\" : \"urn:clarkparsia.com:empire:\",\n" +
-                "    \"spi\" : \"urn:streampipes.org:spi:\"\n" +
-                "  }\n" +
-                "}";
-    }
-
-    public static String getMinimalDataSet() {
-        return "{\n" +
-                "  \"@graph\" : [ {\n" +
-                "    \"@id\" : \"http://bla.de/1\",\n" +
-                "    \"@type\" : \"sp:DataSet\",\n" +
-                "    \"http://www.w3.org/2000/01/rdf-schema#description\" : \"des\",\n" +
-                "    \"http://www.w3.org/2000/01/rdf-schema#label\" : \"name\",\n" +
-                "    \"sp:hasSchema\" : {\n" +
-                "      \"@id\" : \"spi:eventschema:adbgUv\"\n" +
-                "    },\n" +
-                "    \"sp:hasUri\" : \"http://bla.de/1\"\n" +
-                "  }, {\n" +
-                "    \"@id\" : \"spi:eventschema:adbgUv\",\n" +
-                "    \"@type\" : \"sp:EventSchema\",\n" +
-                "    \"sp:hasElementName\" : \"urn:streampipes.org:spi:eventschema:adbgUv\"\n" +
-                "  } ],\n" +
-                "  \"@context\" : {\n" +
-                "    \"sp\" : \"https://streampipes.org/vocabulary/v1/\",\n" +
-                "    \"ssn\" : \"http://purl.oclc.org/NET/ssnx/ssn#\",\n" +
-                "    \"xsd\" : \"http://www.w3.org/2001/XMLSchema#\",\n" +
-                "    \"empire\" : \"urn:clarkparsia.com:empire:\",\n" +
-                "    \"spi\" : \"urn:streampipes.org:spi:\"\n" +
-                "  }\n" +
-                "}";
-    }
-
-}
diff --git a/ui/cypress/fixtures/datalake/sample.csv b/ui/cypress/fixtures/datalake/sample.csv
new file mode 100644
index 0000000..355a4a0
--- /dev/null
+++ b/ui/cypress/fixtures/datalake/sample.csv
@@ -0,0 +1,11 @@
+timestamp;randombool;randomnumber;randomtext
+1623871499055;true;62.0;c
+1623871500059;false;46.0;a
+1623871501064;true;41.0;b
+1623871502070;true;41.0;b
+1623871503078;false;22.0;b
+1623871504082;true;56.0;a
+1623871505084;false;77.0;b
+1623871506086;true;77.0;a
+1623871507091;true;85.0;b
+1623871508093;false;22.0;a
diff --git a/streampipes-rest/src/test/java/org/apache/streampipes/rest/Mock.java b/ui/cypress/support/model/DataLakeFilterConfig.ts
similarity index 75%
rename from streampipes-rest/src/test/java/org/apache/streampipes/rest/Mock.java
rename to ui/cypress/support/model/DataLakeFilterConfig.ts
index 1fd658d..42c53db 100644
--- a/streampipes-rest/src/test/java/org/apache/streampipes/rest/Mock.java
+++ b/ui/cypress/support/model/DataLakeFilterConfig.ts
@@ -16,11 +16,14 @@
  *
  */
 
-package org.apache.streampipes.rest;
-
-public class Mock {
-  public static int PORT = 8042;
-
-  public static String HOST = "http://localhost:" + PORT;
+export class DataLakeFilterConfig {
+  field: string;
+  value: string;
+  operator: string | '<' | '>' | '=' | '!=';
 
+  constructor(field: string, value: string, operator: string) {
+    this.field = field;
+    this.value = value;
+    this.operator = operator;
+  }
 }
diff --git a/ui/cypress/support/utils/DataLakeUtils.ts b/ui/cypress/support/utils/DataLakeUtils.ts
index e7aea29..d06f267 100644
--- a/ui/cypress/support/utils/DataLakeUtils.ts
+++ b/ui/cypress/support/utils/DataLakeUtils.ts
@@ -18,9 +18,142 @@
 
 // tslint:disable-next-line:no-implicit-dependencies
 import * as CSV from 'csv-string';
+import { FileManagementUtils } from './FileManagementUtils';
+import { GenericAdapterBuilder } from '../builder/GenericAdapterBuilder';
+import { AdapterUtils } from './AdapterUtils';
+import { DataLakeFilterConfig } from '../model/DataLakeFilterConfig';
 
 export class DataLakeUtils {
 
+
+  public static loadDataIntoDataLake(dataSet: string) {
+    // Create adapter with dataset
+    FileManagementUtils.addFile(dataSet);
+
+    const adapter = GenericAdapterBuilder
+      .create('File_Set')
+      .setName('datalake_configuration')
+      .setTimestampProperty('timestamp')
+      .setStoreInDataLake()
+      .setFormat('csv')
+      .addFormatInput('input', 'delimiter', ';')
+      .addFormatInput('checkbox', 'header', 'check')
+      .build();
+    AdapterUtils.addGenericSetAdapter(adapter);
+
+    // Wait till data is stored
+    cy.wait(10000);
+  }
+
+  public static loadRandomDataSetIntoDataLake() {
+    this.loadDataIntoDataLake('fileTest/random.csv');
+  }
+
+  public static goToDatalake() {
+    cy.visit('#/dataexplorer');
+  }
+
+  public static createAndEditDataView() {
+    // Create new data view
+    cy.dataCy('open-new-data-view-dialog')
+      .click();
+
+    // Configure data view
+    cy.dataCy('data-view-name').type('Test View');
+    cy.dataCy('save-data-view')
+      .click();
+
+    // Click edit button
+    cy.dataCy('edit-data-view')
+      .click();
+  }
+
+  public static addNewWidget() {
+    cy.dataCy('add-new-widget')
+      .click();
+  }
+
+  public static selectDataSet(dataSet: string) {
+    cy.dataCy('data-explorer-select-data-set')
+      .click()
+      .get('mat-option')
+      .contains(dataSet)
+      .click();
+  }
+
+  /**
+   * In the data set panel select all property fields
+   */
+  public static dataConfigSelectAllFields() {
+    cy.dataCy('data-explorer-data-set-field-select-all')
+      .click();
+  }
+
+
+  public static dataConfigAddFilter(filterConfig: DataLakeFilterConfig) {
+    cy.dataCy('design-panel-data-settings-add-filter')
+      .click();
+
+    // Select field
+    cy.dataCy('design-panel-data-settings-filter-field')
+      .click()
+      .get('mat-option')
+      .contains(filterConfig.field)
+      .click();
+
+    // Select value
+    cy.dataCy('design-panel-data-settings-filter-value').type(filterConfig.value);
+
+    // Select operator
+    cy.dataCy('design-panel-data-settings-filter-operator')
+      .click()
+      .get('mat-option')
+      .contains(filterConfig.operator)
+      .click();
+  }
+
+  public static dataConfigRemoveFilter() {
+    cy.dataCy('design-panel-data-settings-remove-filter')
+      .first()
+      .click();
+  }
+
+  /**
+   * Select visualization type
+   */
+  public static selectVisualizationType(type: string | 'Table') {
+    // Select visualization type
+    cy.dataCy('data-explorer-select-visualization-type')
+      .click()
+      .get('mat-option')
+      .contains(type)
+      .click();
+  }
+
+  public static selectDataConfig() {
+    cy.get('.mat-tab-label').contains('Data').parent().click();
+  }
+
+  public static selectVisualizationConfig() {
+    // Click Next button
+    cy.get('.mat-tab-label').contains('Visualization').parent().click();
+  }
+
+  public static selectAppearanceConfig() {
+    cy.get('.mat-tab-label').contains('Appearance').parent().click();
+  }
+
+  public static clickCreateButton() {
+    // Create widget
+    cy.dataCy('data-explorer-select-data-set-create-btn')
+      .click();
+  }
+
+  public static goToDatalakeConfiguration() {
+    cy.visit('#/configuration');
+    cy.get('div').contains('DataLake').parent().click();
+  }
+
   public static checkResults(dataLakeIndex: string, fileRoute: string) {
 
     // Validate result in datalake
@@ -41,12 +174,5 @@ export class DataLakeUtils {
 
   private static parseCsv(csv: string) {
     return CSV.parse(csv, ';');
-    // const result = CSV.parse(csv, ';');
-    // const newResult = [];
-    // result.forEach(row => {
-    //   newResult.push(row);
-    // });
-    // return newResult;
-
   }
 }
diff --git a/ui/cypress/tests/datalake/configuration.ts b/ui/cypress/tests/datalake/configuration.ts
index c89dedd..c821ba2 100644
--- a/ui/cypress/tests/datalake/configuration.ts
+++ b/ui/cypress/tests/datalake/configuration.ts
@@ -16,27 +16,20 @@
  *
  */
 
-import { FileManagementUtils } from '../../support/utils/FileManagementUtils';
-import { GenericAdapterBuilder } from '../../support/builder/GenericAdapterBuilder';
-import { AdapterUtils } from '../../support/utils/AdapterUtils';
-import { PipelineBuilder } from '../../support/builder/PipelineBuilder';
-import { PipelineElementBuilder } from '../../support/builder/PipelineElementBuilder';
 import { PipelineUtils } from '../../support/utils/PipelineUtils';
-
-const adapterName = 'datalake_configuration';
-const pipelineName = 'Datalake Configuration Test';
-const dataLakeIndex = 'configurationtest';
+import { DataLakeUtils } from '../../support/utils/DataLakeUtils';
 
 
 describe('Test Truncate data in datalake', () => {
 
   before('Setup Test', () => {
-    prepareTest();
+    cy.initStreamPipesTest();
+    DataLakeUtils.loadRandomDataSetIntoDataLake();
   });
 
   it('Perform Test', () => {
 
-    goToDatalakeConfiguration();
+    DataLakeUtils.goToDatalakeConfiguration();
 
     // Check if amount of events is correct
     cy.dataCy('datalake-number-of-events', { timeout: 10000 })
@@ -61,15 +54,16 @@ describe('Test Truncate data in datalake', () => {
 });
 
 describe('Delete data in datalake', () => {
-  before('Setup Test', () => {
-    prepareTest();
 
+  before('Setup Test', () => {
+    cy.initStreamPipesTest();
+    DataLakeUtils.loadRandomDataSetIntoDataLake();
     PipelineUtils.deletePipeline();
   });
 
   it('Perform Test', () => {
 
-    goToDatalakeConfiguration();
+    DataLakeUtils.goToDatalakeConfiguration();
 
     // Check if amount of events is correct
     cy.dataCy('datalake-number-of-events', { timeout: 10000 })
@@ -91,36 +85,3 @@ describe('Delete data in datalake', () => {
 
 });
 
-const goToDatalakeConfiguration = () => {
-  cy.visit('#/configuration');
-  cy.get('div').contains('DataLake').parent().click();
-};
-
-const prepareTest = () => {
-  cy.initStreamPipesTest();
-  // Create adapter with dataset
-  FileManagementUtils.addFile('fileTest/random.csv');
-  const adapter = GenericAdapterBuilder
-    .create('File_Set')
-    .setName(adapterName)
-    .setTimestampProperty('timestamp')
-    .setFormat('csv')
-    .addFormatInput('input', 'delimiter', ';')
-    .addFormatInput('checkbox', 'header', 'check')
-    .build();
-  AdapterUtils.addGenericSetAdapter(adapter);
-
-  // Create pipeline to store dataset in datalake
-  const pipelineInput = PipelineBuilder.create(pipelineName)
-    .addSource(adapterName)
-    .addSourceType('set')
-    .addSink(
-      PipelineElementBuilder.create('data_lake')
-        .addInput('input', 'db_measurement', dataLakeIndex)
-        .build())
-    .build();
-  PipelineUtils.addPipeline(pipelineInput);
-
-  // Wait till data is stored
-  cy.wait(10000);
-};
diff --git a/ui/cypress/tests/datalake/widgetDataConfiguration.ts b/ui/cypress/tests/datalake/widgetDataConfiguration.ts
new file mode 100644
index 0000000..47fd884
--- /dev/null
+++ b/ui/cypress/tests/datalake/widgetDataConfiguration.ts
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ *
+ */
+
+import { DataLakeUtils } from '../../support/utils/DataLakeUtils';
+import { DataLakeFilterConfig } from '../../support/model/DataLakeFilterConfig';
+
+
+describe('Test Table View in Data Explorer', () => {
+
+  before('Setup Test', () => {
+    // cy.login();
+    cy.initStreamPipesTest();
+    DataLakeUtils.loadDataIntoDataLake('datalake/sample.csv');
+  });
+
+  it('Perform Test', () => {
+
+    DataLakeUtils.goToDatalake();
+
+    DataLakeUtils.createAndEditDataView();
+    // Click edit button
+    // cy.dataCy('edit-data-view')
+    //   .click();
+
+    // TODO Set Time Range
+    cy.dataCy('1_year')
+      .click();
+
+    DataLakeUtils.addNewWidget();
+
+    DataLakeUtils.selectDataSet('Persist');
+
+    DataLakeUtils.dataConfigSelectAllFields();
+
+    DataLakeUtils.selectVisualizationConfig();
+
+    DataLakeUtils.selectVisualizationType('Table');
+
+    DataLakeUtils.clickCreateButton();
+
+    // Validate that X lines are available
+    cy.dataCy('data-explorer-table-row', { timeout: 10000 }).should('have.length', 10);
+
+    /**
+     * Test filter configuration
+     */
+
+    // Go back to data configuration
+    DataLakeUtils.selectDataConfig();
+
+    // Test number
+    let filterConfig = new DataLakeFilterConfig('randomnumber', '22', '=');
+    DataLakeUtils.dataConfigAddFilter(filterConfig);
+    cy.dataCy('data-explorer-table-row', { timeout: 10000 }).should('have.length', 2);
+    DataLakeUtils.dataConfigRemoveFilter();
+    cy.dataCy('data-explorer-table-row', { timeout: 10000 }).should('have.length', 10);
+
+    // Test number greater then
+    filterConfig = new DataLakeFilterConfig('randomnumber', '50', '>');
+    DataLakeUtils.dataConfigAddFilter(filterConfig);
+    cy.dataCy('data-explorer-table-row', { timeout: 10000 }).should('have.length', 5);
+    DataLakeUtils.dataConfigRemoveFilter();
+
+    // Test number smaller then
+    filterConfig = new DataLakeFilterConfig('randomnumber', '50', '<');
+    DataLakeUtils.dataConfigAddFilter(filterConfig);
+    cy.dataCy('data-explorer-table-row', { timeout: 10000 }).should('have.length', 5);
+    DataLakeUtils.dataConfigRemoveFilter();
+
+    // Test boolean
+    filterConfig = new DataLakeFilterConfig('randombool', 'true', '=');
+    DataLakeUtils.dataConfigAddFilter(filterConfig);
+    cy.dataCy('data-explorer-table-row', { timeout: 10000 }).should('have.length', 6);
+    DataLakeUtils.dataConfigRemoveFilter();
+
+    // Test string
+    filterConfig = new DataLakeFilterConfig('randomtext', 'a', '=');
+    DataLakeUtils.dataConfigAddFilter(filterConfig);
+    cy.dataCy('data-explorer-table-row', { timeout: 10000 }).should('have.length', 4);
+    DataLakeUtils.dataConfigRemoveFilter();
+  });
+
+});
diff --git a/ui/cypress/tests/datalake/widgets/table.ts b/ui/cypress/tests/datalake/widgets/table.ts
new file mode 100644
index 0000000..5937158
--- /dev/null
+++ b/ui/cypress/tests/datalake/widgets/table.ts
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ *
+ */
+
+import { DataLakeUtils } from '../../../support/utils/DataLakeUtils';
+
+
+describe('Test Table View in Data Explorer', () => {
+
+  before('Setup Test', () => {
+    cy.login();
+    // cy.initStreamPipesTest();
+    // DataLakeUtils.loadRandomDataSetIntoDataLake();
+  });
+
+  it('Perform Test', () => {
+
+    DataLakeUtils.goToDatalake();
+
+    // DataLakeUtils.createAndEditDataView();
+    // Click edit button
+    cy.dataCy('edit-data-view')
+      .click();
+
+    DataLakeUtils.addNewWidget();
+
+    DataLakeUtils.selectDataSet('Persist');
+
+    DataLakeUtils.dataConfigSelectAllFields();
+
+    DataLakeUtils.clickNextButton();
+
+    DataLakeUtils.selectVisualizationType('Table');
+
+    DataLakeUtils.clickCreateButton();
+
+    // TODO Set Time Range
+    cy.dataCy('1_year')
+      .click();
+
+    cy.dataCy('data-explorer-table-row', { timeout: 10000 }).should('have.length', 10);
+    // Validate that X lines are available
+
+  });
+
+});
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html b/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html
index 72e227b..ede4df4 100644
--- a/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html
+++ b/ui/src/app/data-explorer/components/designer-panel/data-explorer-designer-panel.component.html
@@ -20,7 +20,9 @@
     <div fxLayout="row" class="sp-tab-bg designer-panel-header">
         <div fxLayoutAlign="start center" class="designer-panel-title">Widget Configuration</div>
         <div fxFlex fxLayoutAlign="end end">
-            <button mat-button mat-icon-button (click)="addWidget()" matTooltip="New widget">
+            <button mat-button mat-icon-button
+                    data-cy="add-new-widget"
+                    (click)="addWidget()" matTooltip="New widget">
                 <mat-icon>add</mat-icon>
             </button>
         </div>
@@ -31,9 +33,9 @@
         </div>
         <mat-tab-group [selectedIndex]="selectedIndex" (selectedIndexChange)="selectOptionsPanel($event)" color="accent"
                        class="small">
-            <mat-tab label="Data"></mat-tab>
-            <mat-tab label="Visualization"></mat-tab>
-            <mat-tab label="Appearance"></mat-tab>
+            <mat-tab data-cy="designer-panel-data-config" label="Data"></mat-tab>
+            <mat-tab data-cy="designer-panel-visualization-config" label="Visualization"></mat-tab>
+            <mat-tab data-cy="designer-panel-appearance-config" label="Appearance"></mat-tab>
         </mat-tab-group>
 
         <div fxFlex="100" fxLayout="column">
@@ -63,7 +65,9 @@
             <mat-divider *ngIf="newWidgetMode"></mat-divider>
             <div fxLayout="row" fxLayoutAlign="center end" class="mt-10 actions-align-right p-15"
                  *ngIf="newWidgetMode">
-                <button mat-button mat-raised-button color="accent" *ngIf="newWidgetMode && selectedIndex == 0"
+                <button mat-button mat-raised-button color="accent"
+                        data-cy="data-explorer-select-data-set-next-btn"
+                        *ngIf="newWidgetMode && selectedIndex == 0"
                         (click)="selectedIndex = 1">
                     Next
                 </button>
@@ -71,7 +75,9 @@
                         (click)="selectedIndex = 0" style="margin-right: 10px;">
                     Back
                 </button>
-                <button *ngIf="newWidgetMode && selectedIndex == 1" mat-button mat-raised-button color="accent"
+                <button mat-button mat-raised-button color="accent"
+                        data-cy="data-explorer-select-data-set-create-btn"
+                        *ngIf="newWidgetMode && selectedIndex == 1"
                         (click)="createNewWidget()">
                     Create
                 </button>
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.html b/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.html
index 99e6674..d538b3e 100644
--- a/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.html
+++ b/ui/src/app/data-explorer/components/designer-panel/data-settings/data-explorer-widget-data-settings.component.html
@@ -48,8 +48,10 @@
                     <mat-form-field color="accent" fxFlex="100" *ngIf="sourceConfig.sourceType == 'pipeline'">
                         <mat-label>Data Explorer Sinks</mat-label>
                         <mat-select [(value)]="sourceConfig.measureName"
-                                    (selectionChange)="updateMeasure(sourceConfig, $event)">
-                            <mat-option [value]="pipeline.measureName" *ngFor="let pipeline of availablePipelines">
+                                    (selectionChange)="updateMeasure(sourceConfig, $event)"
+                                    data-cy="data-explorer-select-data-set">
+                            <mat-option *ngFor="let pipeline of availablePipelines"
+                                        [value]="pipeline.measureName">
                                 <span class="pipeline-name">{{ pipeline.pipelineName }}</span>&nbsp;&nbsp;{{ pipeline.measureName }}
                             </mat-option>
                         </mat-select>
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-settings/field-selection-panel/field-selection-panel.component.html b/ui/src/app/data-explorer/components/designer-panel/data-settings/field-selection-panel/field-selection-panel.component.html
index c28388a..1ee90e5 100644
--- a/ui/src/app/data-explorer/components/designer-panel/data-settings/field-selection-panel/field-selection-panel.component.html
+++ b/ui/src/app/data-explorer/components/designer-panel/data-settings/field-selection-panel/field-selection-panel.component.html
@@ -21,6 +21,7 @@
         <div fxLayout="row" fxLayoutAlign="start center">
             <button mat-button mat-raised-button color="accent" class="small-button"
                     style="margin-right:10px;"
+                    data-cy="data-explorer-data-set-field-select-all"
                     (click)="selectAllFields()">Select all
             </button>
             <button mat-button mat-raised-button class="small-button mat-basic"
diff --git a/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.html b/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.html
index 3c84ae9..4b72295 100644
--- a/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.html
+++ b/ui/src/app/data-explorer/components/designer-panel/data-settings/filter-selection-panel/filter-selection-panel.component.html
@@ -20,6 +20,7 @@
     <span class="data-explorer-header">Filter</span>
     <div>
         <button mat-button mat-raised-button color="accent" class="small-button"
+                data-cy="design-panel-data-settings-add-filter"
                 (click)="addFilter()"
                 style="margin-right:10px;margin-bottom: 15px;">Add Filter
         </button>
@@ -33,7 +34,8 @@
                     <mat-select
                             [(value)]="filter.field"
                             (selectionChange)="updateWidget()"
-                            [compareWith]="compare">
+                            [compareWith]="compare"
+                            data-cy="design-panel-data-settings-filter-field">
                         <mat-option *ngFor="let field of sourceConfig.queryConfig.fields"
                                     [value]="field">{{field.runtimeName}}</mat-option>
                     </mat-select>
@@ -42,7 +44,8 @@
                     <mat-label>Operator</mat-label>
                     <mat-select
                             [(value)]="filter.operator"
-                            (selectionChange)="updateWidget()">
+                            (selectionChange)="updateWidget()"
+                            data-cy="design-panel-data-settings-filter-operator">
                         <mat-option [value]="'='">
                             <span class="pipeline-name">=</span>
                         </mat-option>
@@ -67,10 +70,12 @@
                     <mat-label>Value</mat-label>
                     <input matInput
                            [(ngModel)]="filter.value"
-                           (change)="updateWidget()">
+                           (change)="updateWidget()"
+                           data-cy="design-panel-data-settings-filter-value">
                 </mat-form-field>
                 <button mat-icon-button color="accent"
-                        (click)="remove(sourceConfig, filter.index)">
+                        (click)="remove(sourceConfig, filter.index)"
+                        data-cy="design-panel-data-settings-remove-filter">
                     <i class="material-icons">remove</i>
                 </button>
             </div>
diff --git a/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.html b/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.html
index 01f986f..4f76b8c 100644
--- a/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.html
+++ b/ui/src/app/data-explorer/components/designer-panel/visualisation-settings/data-explorer-visualisation-settings.component.html
@@ -21,7 +21,10 @@
         <span class="data-explorer-header">Visualization Type</span>
         <mat-form-field color="accent" fxFlex="100">
             <mat-label>Select visualization</mat-label>
-            <mat-select [(value)]="currentlyConfiguredWidget.widgetType" (selectionChange)="triggerWidgetTypeChange($event)">
+            <mat-select
+                    [(value)]="currentlyConfiguredWidget.widgetType"
+                    (selectionChange)="triggerWidgetTypeChange($event)"
+                    data-cy="data-explorer-select-visualization-type">
                 <mat-option [value]="widget.id" *ngFor="let widget of availableWidgets">
                     <span class="pipeline-name">{{widget.label}}</span>
                 </mat-option>
diff --git a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.html b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.html
index 78b111d..cbec366 100644
--- a/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.html
+++ b/ui/src/app/data-explorer/components/overview/data-explorer-dashboard-overview.component.html
@@ -21,13 +21,15 @@
     <div fxFlex="100" fxLayout="column">
         <div fxLayout="row" class="fixed-height options-bar page-container-nav sp-tab-bg">
             <div fxLayoutAlign="start center" fxLayout="row" class="pl-10">
-                <button mat-button mat-raised-button color="accent" (click)="openNewDataViewDialog()" class="mr-10">
+                <button mat-button mat-raised-button color="accent"
+                        data-cy="open-new-data-view-dialog"
+                        (click)="openNewDataViewDialog()" class="mr-10">
                     <i class="material-icons">add</i>
                     <span>New Data View</span>
                 </button>
-<!--                <button mat-button mat-raised-button color="accent" (click)="openEditLabelView()">-->
-<!--                    Edit Labels-->
-<!--                </button>-->
+                <!--                <button mat-button mat-raised-button color="accent" (click)="openEditLabelView()">-->
+                <!--                    Edit Labels-->
+                <!--                </button>-->
             </div>
         </div>
     </div>
@@ -67,6 +69,7 @@
                         <td fxFlex="10" fxLayoutAlign="start center" mat-cell *matCellDef="let element">
                             <div fxLayout="row">
                                 <button mat-button mat-icon-button color="accent"
+                                        data-cy="edit-data-view"
                                         (click)="showDashboard(element, true)">
                                     <i class="material-icons">edit</i>
                                 </button>
diff --git a/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.html b/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.html
index 3a10934..e549aa6 100644
--- a/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.html
+++ b/ui/src/app/data-explorer/components/time-selector/timeRangeSelector.component.html
@@ -18,17 +18,19 @@
 
 <div fxLayout="row" fxLayoutAlign="start center">
     <div class="time-range-wrapper" fxFlex fxLayoutAlign="center center">
-    <button mat-button mat-raised-button
-            *ngFor="let item of possibleTimeButtons"
-            [color]="selectedTimeButton.value === item.value ? 'accent' : ''"
-            class="button-margin smaller-button-font-size"
-            (click)="this.setCurrentDateRange(item)">{{item.value}}</button>
+        <button mat-button mat-raised-button
+                *ngFor="let item of possibleTimeButtons"
+                [color]="selectedTimeButton.value === item.value ? 'accent' : ''"
+                [attr.data-cy]="item.value.replace(' ', '_')"
+                class="button-margin smaller-button-font-size"
+                (click)="this.setCurrentDateRange(item)">{{item.value}}</button>
     </div>
     <div class="time-wrapper" fxFlex fxLayoutAlign="center center">
         <button mat-button class="button-icon icon-button-font-size mr--15" color="accent">
             <mat-icon (click)="decreaseTime()">navigate_before</mat-icon>
         </button>
-        <mat-form-field appearance="standard" class="start-date form-field-margin form-field-size-smaller" color="accent">
+        <mat-form-field appearance="standard" class="start-date form-field-margin form-field-size-smaller"
+                        color="accent">
             <mat-label>From</mat-label>
             <input matInput
                    [owlDateTime]="dt1"
diff --git a/ui/src/app/data-explorer/components/widgets/table/table-widget.component.html b/ui/src/app/data-explorer/components/widgets/table/table-widget.component.html
index aee17c7..d302a4b 100644
--- a/ui/src/app/data-explorer/components/widgets/table/table-widget.component.html
+++ b/ui/src/app/data-explorer/components/widgets/table/table-widget.component.html
@@ -38,7 +38,9 @@
                         [ngStyle]="{background: dataExplorerWidget.baseAppearanceConfig.backgroundColor, color: dataExplorerWidget.baseAppearanceConfig.textColor}">
                         <label class="column-header">Timestamp</label>
                     </th>
-                    <td mat-cell *matCellDef="let row" style="text-align: left;">
+                    <td mat-cell
+                        data-cy="data-explorer-table-row"
+                        *matCellDef="let row" style="text-align: left;">
                         {{row['time'] | date:'yyyy-MM-dd HH:mm:ss.SSS'}}
                     </td>
                 </div>
diff --git a/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.html b/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.html
index 341ec02..20a5501 100644
--- a/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.html
+++ b/ui/src/app/data-explorer/dialogs/edit-dashboard/data-explorer-edit-data-view-dialog.component.html
@@ -22,7 +22,9 @@
             <div fxFlex="100" fxLayout="column" style="margin:5px;width:100%">
                 <mat-form-field class="full-width" color="accent">
                     <mat-label>Data View Name</mat-label>
-                    <input matInput [(ngModel)]="dashboard.name">
+                    <input matInput
+                           data-cy="data-view-name"
+                           [(ngModel)]="dashboard.name">
                 </mat-form-field>
                 <mat-form-field class="full-width" color="accent">
                     <mat-label>Description</mat-label>
@@ -39,7 +41,9 @@
                 (click)="onCancel()">
             Close
         </button>
-        <button mat-button mat-raised-button color="accent" (click)="onSave()">
+        <button mat-button mat-raised-button color="accent"
+                data-cy="save-data-view"
+                (click)="onSave()">
             {{createMode ? 'Create' : 'Save'}}
         </button>
     </div>