This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new 9ef561d723 Fix the Hop Web selenium failures in the transform dialog
sweep (#8900)
9ef561d723 is described below
commit 9ef561d723e973998cd60918eaf154331989fd2f
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Wed Oct 14 09:50:36 2026 +0200
Fix the Hop Web selenium failures in the transform dialog sweep (#8900)
---
.../combinationlookup/CombinationLookupDialog.java | 11 +++++-
.../hop/web/it/pages/ExecutionResultsPanel.java | 32 +++++++++++------
web-tests/src/test/resources/transforms.csv | 41 +++++++++++++++++-----
3 files changed, 63 insertions(+), 21 deletions(-)
diff --git
a/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupDialog.java
b/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupDialog.java
index 2b3c800d74..4ce0eaf780 100644
---
a/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupDialog.java
+++
b/plugins/transforms/combinationlookup/src/main/java/org/apache/hop/pipeline/transforms/combinationlookup/CombinationLookupDialog.java
@@ -659,8 +659,17 @@ public class CombinationLookupDialog extends
BaseTransformDialog {
//
String[] fieldNames = ConstUi.sortFieldNames(inputFields);
ciKey[1].setComboValues(fieldNames);
+ // Called from the background thread that reads the input fields: touch
the widget on the UI
+ // thread only, or SWT throws "Invalid thread access".
if (wHashFieldInStream != null && !wHashFieldInStream.isDisposed()) {
- wHashFieldInStream.setItems(fieldNames);
+ wHashFieldInStream
+ .getDisplay()
+ .asyncExec(
+ () -> {
+ if (!wHashFieldInStream.isDisposed()) {
+ wHashFieldInStream.setItems(fieldNames);
+ }
+ });
}
}
diff --git
a/web-tests/src/test/java/org/apache/hop/web/it/pages/ExecutionResultsPanel.java
b/web-tests/src/test/java/org/apache/hop/web/it/pages/ExecutionResultsPanel.java
index 754f7a74b1..5b515b6e33 100644
---
a/web-tests/src/test/java/org/apache/hop/web/it/pages/ExecutionResultsPanel.java
+++
b/web-tests/src/test/java/org/apache/hop/web/it/pages/ExecutionResultsPanel.java
@@ -43,27 +43,37 @@ public class ExecutionResultsPanel {
* that has both those names and rows under it - the table is nested several
containers deep and
* every one of them "contains" the header text.
*
- * <p>A row is recognised by having exactly two children per column: a table
row lays out as an
- * alternating run of spacer and cell elements, which is also why only the
odd children are read.
- * The cells cannot simply be filtered on having text, because a metric that
is genuinely empty
- * would drop out and shift every column after it.
+ * <p>A row is a run of absolutely positioned leaf elements: one background
per column, plus one
+ * text element for every cell that has ever held a value. The text elements
cannot be read in
+ * document order. RAP creates a cell's text element the first time the cell
gets a value and
+ * appends it to the row, so a metric that was still empty on the first
paint ("Duration") ends up
+ * after "Status" and shifts every column read by position. Each text
element is put in the column
+ * whose header starts at or left of it instead, and a cell that never held
a value stays empty.
*/
private static final String METRICS =
- "const candidates=[...document.querySelectorAll('div')].filter("
+ "const left=e=>parseFloat(e.style.left)||0;"
+ + "const candidates=[...document.querySelectorAll('div')].filter("
+ "d=>d.textContent.includes('Transform
Name')&&d.textContent.includes('Written (rows)'));"
+ "for(let i=candidates.length-1;i>=0;i--){"
+ "const table=candidates[i];"
+ "const
head=[...table.children].find(c=>c.textContent.includes('Transform Name'));"
+ "if(!head)continue;"
- + "const
headers=[...head.children].map(c=>c.textContent.trim()).filter(t=>t.length>0);"
- + "if(headers.length<"
+ + "const
columns=[...head.children].filter(c=>c.textContent.trim().length>0)"
+ +
".map(c=>({name:c.textContent.trim(),left:left(c)})).sort((a,b)=>a.left-b.left);"
+ + "if(columns.length<"
+ MIN_COLUMNS
+ ")continue;"
- + "const rows=[...table.querySelectorAll('div')].filter(d=>"
- +
"d.children.length===headers.length*2&&[...d.children].every(c=>c.children.length===0));"
+ // The grid also paints empty filler rows below the last transform:
skip those.
+ + "const rows=[...table.querySelectorAll('div')].filter(d=>d!==head"
+ +
"&&d.children.length>=columns.length&&d.textContent.trim().length>0"
+ + "&&[...d.children].every(c=>c.children.length===0));"
+ "if(rows.length===0)continue;"
- + "return {headers:headers,"
- +
"rows:rows.map(r=>[...r.children].filter((c,n)=>n%2===1).map(c=>c.textContent.trim()))};}"
+ + "return {headers:columns.map(c=>c.name),rows:rows.map(r=>{"
+ + "const cells=columns.map(()=>'');"
+ + "for(const c of r.children){const
text=c.textContent.trim();if(!text)continue;"
+ + "let n=-1;columns.forEach((col,k)=>{if(col.left<=left(c))n=k;});"
+ + "if(n>=0)cells[n]=text;}"
+ + "return cells;})};}"
+ "return {headers:[],rows:[]};";
private final WebDriver driver;
diff --git a/web-tests/src/test/resources/transforms.csv
b/web-tests/src/test/resources/transforms.csv
index c030c12d93..67edc12457 100644
--- a/web-tests/src/test/resources/transforms.csv
+++ b/web-tests/src/test/resources/transforms.csv
@@ -47,6 +47,9 @@ Azure Event Hubs listener
Azure Event Hubs writer
Beam Bigtable input
Beam Bigtable output
+Beam Debezium input
+Beam Elasticsearch input
+Beam Elasticsearch output
Beam file input
Beam file output
Beam GCP Pub/Sub: publish
@@ -55,6 +58,12 @@ Beam Kafka consume
Beam Kafka produce
Beam Kinesis consume
Beam Kinesis produce
+Beam MQTT input
+Beam MQTT output
+Beam partition
+Beam Snowflake input
+Beam Snowflake output
+Beam Splunk output
Beam timestamp
Beam window
BigQuery input
@@ -79,6 +88,8 @@ Copy rows to result
CrateDB bulk loader
Credit card validator
CSV file input
+Cypher builder
+Cypher output
Data grid
Data set input
Data set output
@@ -88,6 +99,7 @@ Data validator
Database impact input
Database join
Database lookup
+Database value validation
DDL
De-serialize from file
Delay row
@@ -100,6 +112,7 @@ Dummy (do nothing)
Dynamic SQL row
EDI to XML
Email messages input
+Embed text
Enhanced JSON output
ETL metadata injection
Execute a process
@@ -107,12 +120,14 @@ Execute row SQL script
Execute SQL script
Execute unit tests
Execution information
+Extract graph
Fake data
File exists
File metadata
Filter rows
Formula
Fuzzy match
+Generate graph CSVs
Generate random value
Generate rows
Generate Snowflake ID
@@ -120,8 +135,9 @@ Get data from XML
Get file names
Get files from result
Get files rows count
+Get graph logging info
+Get graph schema
Get JDBC metadata
-Get Neo4j logging info
Get records from stream (deprecated)
Get rows from result
Get server status
@@ -129,9 +145,13 @@ Get subfolder names
Get system info
Get table names
Get variables
+Git Input
Google Analytics 4
Google Sheets input
Google Sheets output
+Graph output
+Graph query
+Graph vector search
Group by
HTML to text
HTTP client
@@ -150,6 +170,8 @@ JSON normalize input
JSON output
Kafka consumer
Kafka producer
+Lake table input
+Lake table output
Language model chat
LDAP input
LDAP output
@@ -157,6 +179,7 @@ Load file content in memory
Mail
Mapping input
Mapping output
+Mask fields
Memory group by
Merge join
Merge rows (diff)
@@ -173,24 +196,22 @@ MS SQL Server bulk loader
Multi Mapping
Multiway merge join
MySQL bulk loader
-Neo4j Cypher
-Neo4j Cypher builder
-Neo4j generate CSVs
-Neo4j graph output
Neo4j import
-Neo4j output
-Neo4j split graph
Null if
Number range
OData input
Oracle bulk loader
+Output transform metrics
Parquet file input
Parquet file output
PGP decrypt stream
PGP encrypt stream
+pgvector search
+pgvector upsert
Pipeline executor
Pipeline logging
Pipeline probe
+Plugin Catalog
PostgreSQL bulk loader
Process files
Properties input
@@ -232,13 +253,12 @@ Sorted merge
Sorted schema merge
Spark file input
Spark file output
-Spark lake table input
Spark lake table maintenance
Spark lake table merge
-Spark lake table output
Spark SQL
Split field to rows
Split fields
+Split graph
Splunk input
SQL file output
SSTable output
@@ -248,6 +268,7 @@ Stream lookup
Stream schema merge
String operations
Strings cut
+Structured extract
Surefire report output
Switch / case
Synchronize after merge
@@ -256,6 +277,7 @@ Table exists
Table input
Table output
Teradata FastLoad bulk loader
+Text chunker
Text file input
Text file output
Token replacement
@@ -268,6 +290,7 @@ Value mapper
vCard input
vCard output
Vertica bulk loader
+Watch Files
Web services lookup
Workflow executor
Workflow logging