The following script Code is working after switching between script manual view for and back the script code will be formating an doesen’t work after.
BEFORE:
import static com.kms.katalon.core.checkpoint.CheckpointFactory.findCheckpoint
import static com.kms.katalon.core.testcase.TestCaseFactory.findTestCase
import static com.kms.katalon.core.testdata.TestDataFactory.findTestData
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import static com.kms.katalon.core.testobject.ObjectRepository.findWindowsObject
import com.github.javafaker.Faker as Faker
import com.kms.katalon.core.checkpoint.Checkpoint as Checkpoint
import com.kms.katalon.core.cucumber.keyword.CucumberBuiltinKeywords as CucumberKW
import com.kms.katalon.core.mobile.keyword.MobileBuiltInKeywords as Mobile
import com.kms.katalon.core.model.FailureHandling as FailureHandling
import com.kms.katalon.core.testcase.TestCase as TestCase
import com.kms.katalon.core.testdata.TestData as TestData
import com.kms.katalon.core.testng.keyword.TestNGBuiltinKeywords as TestNGKW
import com.kms.katalon.core.testobject.TestObject as TestObject
import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import com.kms.katalon.core.windows.keyword.WindowsBuiltinKeywords as Windows
import internal.GlobalVariable as GlobalVariable
import org.openqa.selenium.Keys as Keys
import org.openqa.selenium.WebElement as WebElement
import com.kms.katalon.core.testobject.ConditionType as ConditionType
import com.kms.katalon.core.util.KeywordUtil as KeywordUtil
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
// Funktion zur Extraktion der Werte als Key-Value-Paare
def extractValues(Map jsonMap, String parentKey = "") {
def result = [:]
jsonMap.each { key, value ->
def newKey = parentKey ? "${parentKey}.${key}" : key
if (value instanceof Map && value.containsKey("value")) {
result[newKey] = value.value
} else if (value instanceof Map) {
result.putAll(extractValues(value, newKey))
} else {
result[newKey] = value
}
}
return result
}
// Funktion zum Reconstruck Json
void buildNestedMap(Map target, List<String> keys, def value) {
if (keys.size() == 1) {
target[keys[0]] = value
return
}
if (!target.containsKey(keys[0]) || !(target[keys[0]] instanceof Map)) {
target[keys[0]] = [:]
}
buildNestedMap(target[keys[0]], keys[1..-1], value)
}
// Rekursive Vergleichsfunktion
boolean compareJson(def input, def output) {
if (input == null || output == null) {
if (input != output) {
KeywordUtil.markWarning("Fehler: Null-Werte stimmen nicht überein. Erwartet: $input, Gefunden: $output")
return false
}
return true
}
// Wenn input eine Map ist
if (input instanceof Map) {
if (!(output instanceof Map)) {
// Wenn output keine Map ist, vergleiche die Werte direkt
if (input != output) {
WebUI.comment("Fehler: Erwartete Map oder gleichen Wert, aber gefunden: ${output.getClass()} mit Wert $output")
return false
}
return true
}
input.each { key, value ->
if (!output.containsKey(key)) {
WebUI.comment("Fehlender Schlüssel in Output: $key")
return false
}
if (!compareJson(value, output[key])) return false
}
}
// Wenn input eine Liste ist
else if (input instanceof List) {
if (!(output instanceof List)) {
// Wenn output keine Liste ist, vergleiche die Werte direkt
if (input != output) {
WebUI.comment("Fehler: Erwartete Liste oder gleichen Wert, aber gefunden: ${output.getClass()} mit Wert $output")
return false
}
return true
}
if (input.size() > output.size()) {
WebUI.comment("Listenlängen stimmen nicht überein: Erwartet mindestens ${input.size()}, aber gefunden ${output.size()}")
return false
}
input.eachWithIndex { item, index ->
if (!compareJson(item, output[index])) {
WebUI.comment("Listenwert an Index $index stimmt nicht überein: Erwartet $item, aber gefunden ${output[index]}")
return false
}
}
}
// Wenn input ein primitiver Wert ist (String, Zahl, Boolean usw.)
else {
// Sicherstellen, dass Zahlen als String verglichen werden
def inputNormalized = input instanceof Number ? input.toString() : input
def outputNormalized = output instanceof Number ? output.toString() : output
if (inputNormalized != outputNormalized) {
WebUI.comment("Wert stimmt nicht überein: Erwartet $inputNormalized, aber gefunden $outputNormalized")
return false
}
}
return true
}
WebUI.openBrowser('')
WebUI.callTestCase(findTestCase('workplace/TC- Generell Steps/Step001 - Login TA1 - Natural'), [:], FailureHandling.STOP_ON_FAILURE)
WebUI.navigateToUrl(GlobalVariable.poURL)
WebUI.waitForElementPresent(findTestObject('Page_Process Orchestrator/input_PO_Search'), 0)
WebUI.setText(findTestObject('Page_Process Orchestrator/input_PO_Search'), selectDeleagate)
WebUI.sendKeys(findTestObject('Page_Process Orchestrator/input_PO_Search'), Keys.chord(Keys.ENTER))
WebUI.delay(2)
WebUI.waitForElementPresent(findTestObject('Page_Process Orchestrator/table_Delegate', [('Delegate') : selectDeleagate]),
0)
WebUI.clickOffset(findTestObject('Page_Process Orchestrator/table_Delegate', [('Delegate') : selectDeleagate]), 0, 0)
WebUI.click(findTestObject('Page_Process Orchestrator/button Open DetailsSectionAccessButton'))
WebUI.waitForElementPresent(findTestObject('Object Repository/Page_Process Orchestrator/span_BPMN'), 0)
WebUI.click(findTestObject('Page_Process Orchestrator/span_Test'))
WebUI.waitForElementPresent(findTestObject('Object Repository/Page_Process Orchestrator/span_Input'), 0)
// Initialisiere Faker für generierte Testdaten
Faker faker = new Faker(new Locale('de'))
// XPath für alle Eingabefelder/Ausgabefelder in der ersten Spalte
String xpathFirstColumnInputs = '//span[contains(text(), "Input")]/ancestor::div[3]//tbody//tr/td[1]//input'
String xpathFirstColumnOutputs = '//span[contains(text(), "Output")]/ancestor::div[3]//tbody//td[1]'
// Erstelle ein dynamisches TestObject für die Eingabefelder/Ausgabefelder der ersten Spalte
TestObject dynamicFirstColumnInputs = new TestObject()
TestObject dynamicFirstColumnOutputs = new TestObject()
dynamicFirstColumnInputs.addProperty('xpath', ConditionType.EQUALS, xpathFirstColumnInputs)
dynamicFirstColumnOutputs.addProperty('xpath', ConditionType.EQUALS, xpathFirstColumnOutputs)
// Sammle alle WebElements der Eingabefelder in der ersten Spalte
List<String> firstColumnInputs = WebUI.findWebElements(dynamicFirstColumnInputs, 30)
//############################################################################
//
// Dieser Bereich muss für jedes Deligate angepasst werden
//
//############################################################################
// Liste der Suchwerte für Spalte 1 (Pflichtfelder)
List<String> searchValues = ['offerDrafts']
String id = 'null'
// Generierte Testdaten mit Faker
String NeuerWertLegalPersonID
String NeuerWertOfferId
if (GlobalVariable.OfferDelegateID == 'null') {
NeuerWertOfferId = '133901'
} else {
NeuerWertOfferId = GlobalVariable.OfferDelegateID
}
String NeuerWertProjectID
if (GlobalVariable.ProjectDelegateID == 'null') {
NeuerWertProjectID = '53108'
} else {
NeuerWertProjectID = GlobalVariable.ProjectDelegateID
}
if (GlobalVariable.LegalPersonDelegateID == 'null') {
NeuerWertLegalPersonID = '61309'
} else {
NeuerWertLegalPersonID = GlobalVariable.LegalPersonDelegateID
}
String NeuerWertOfferDraftValues = "[{\"variables\":{"+
"\"offerId\":{\"value\":\""+NeuerWertOfferId+"\"},"+
"\"entityName\":{\"value\":\"Project\"},"+
"\"formTechnicalName\":{\"value\":\"offer_project_to_legal\"},"+
"\"entityId\":{\"value\":"+NeuerWertProjectID+"},"+
"\"entityType\":{\"value\": \"Project\"},"+
"\"offerDraftLinks\": {"+
"\"value\":[{\"linkTypeTechName\": null,"+
"\"children\":[{\"offerId\":\""+NeuerWertOfferId+"\","+
"\"entityName\":\"LegalPerson\","+
"\"formTechnicalName\":\"offer_project_to_legal\","+
"\"entityType\":\"LegalPerson\","+
"\"entityId\": "+NeuerWertLegalPersonID+","+
"\"offerDraftLinks\":[{\"linkTypeTechName\":\"project_2_legal_person\","+
"\"children\": [],"+
"\"existingLinkId\":null}]}],"+
"\"existingLinkId\":null}]}},"+
"\"withVariablesInReturn\":true}]"
// Liste der neuen Werte, die in die dritte Spalte geschrieben werden sollen (Strings)
List<String> newValuesForThirdColumn = [NeuerWertOfferDraftValues]
//############################################################################
//
// Fertig ;)
//
//############################################################################
// Liste zur Speicherung der gesetzten Werte in der dritten Spalte
List<String> setThirdColumnValues = []
// Schleife über alle Suchwerte
for (int searchIndex = 0; searchIndex < searchValues.size(); searchIndex++) {
String currentSearchValue = searchValues[searchIndex]
String newValueForThirdColumn = newValuesForThirdColumn[searchIndex]
boolean valueFound = false
// Schleife über alle Eingabefelder in der ersten Spalte
for (int i = 0; i < firstColumnInputs.size(); i++) {
// Hole den Wert des aktuellen Input-Felds
String inputValue = (firstColumnInputs[i]).getAttribute('value')
// Überprüfen, ob der Wert dem aktuellen Suchwert entspricht (z.B. 'street', 'housenumber', 'city')
if (inputValue.equals(currentSearchValue)) {
valueFound = true
// XPath für das Eingabefeld in der dritten Spalte der passenden Zeile
String xpathThirdColumnInput = ('//tbody//tr[' + (i + 1)) + ']/td[3]//input'
// Erstelle ein dynamisches TestObject für die dritte Spalte
TestObject thirdColumnInput = new TestObject()
thirdColumnInput.addProperty('xpath', ConditionType.EQUALS, xpathThirdColumnInput)
// Setze den neuen Wert in die dritte Spalte
WebUI.setText(thirdColumnInput, newValueForThirdColumn)
// Speichere den gesetzten Wert zur späteren Überprüfung
setThirdColumnValues.add(newValueForThirdColumn)
// Beende die Schleife, da der Wert gefunden und aktualisiert wurde
break
}
}
// Wenn der Wert nicht gefunden wurde, füge eine neue Zeile hinzu
if (!(valueFound)) {
// Klicke auf die Schaltfläche "Field hinzufügen", um eine neue Zeile hinzuzufügen
WebUI.click(findTestObject('Object Repository/Page_Process Orchestrator/a_Field hinzufugen'))
// Warte kurz, bis die neue Zeile hinzugefügt wurde (Wartezeit anpassen, falls nötig)
WebUI.delay(2)
// Aktualisiere die Liste der Eingabefelder in der ersten Spalte (nachdem eine neue Zeile hinzugefügt wurde)
firstColumnInputs = WebUI.findWebElements(dynamicFirstColumnInputs, 30)
// XPath für das neue Eingabefeld in der ersten Spalte (letzte Zeile)
String xpathNewFirstColumnInput = ('//tbody//tr[' + firstColumnInputs.size()) + ']/td[1]//input'
// Erstelle ein dynamisches TestObject für das Eingabefeld in der neuen Zeile, Spalte 1
TestObject newFirstColumnInput = new TestObject()
newFirstColumnInput.addProperty('xpath', ConditionType.EQUALS, xpathNewFirstColumnInput)
// Setze den aktuellen Suchwert (z.B. 'street', 'housenumber') in die erste Spalte der neuen Zeile
WebUI.setText(newFirstColumnInput, currentSearchValue)
// XPath für das Eingabefeld in der dritten Spalte der neuen Zeile
String xpathNewThirdColumnInput = ('//tbody//tr[' + firstColumnInputs.size()) + ']/td[3]//input'
// Erstelle ein dynamisches TestObject für das Eingabefeld in der dritten Spalte der neuen Zeile
TestObject newThirdColumnInput = new TestObject()
newThirdColumnInput.addProperty('xpath', ConditionType.EQUALS, xpathNewThirdColumnInput)
// Setze den neuen Wert in die dritte Spalte der neuen Zeile
WebUI.setText(newThirdColumnInput, newValueForThirdColumn)
// Speichere den gesetzten Wert zur späteren Überprüfung
setThirdColumnValues.add(newValueForThirdColumn)
}
}
// Klicke auf den "Test" Button, um die Ausgabewerte zu generieren
WebUI.click(findTestObject('Page_Process Orchestrator/button_Speichern'))
WebUI.click(findTestObject('Object Repository/Page_Process Orchestrator/button_Test'))
// Warte, bis die Ausgabewerte vollständig geladen sind (anpassen, falls nötig)
WebUI.delay(5 // Anpassung je nach Ladezeit
)
// Aktualisiere die Liste der Ausgabefelder in der ersten Spalte (nachdem der Button geklickt wurde)
List<String> firstColumnOutputs = WebUI.findWebElements(dynamicFirstColumnOutputs, 30)
searchValues.add('id')
String delegateID
inputString = NeuerWertOfferDraftValues.replace('[', '').replace(']', '')
// Original JSON-String
String inputJson = inputString
println(inputString)
println(inputJson)
def jsonSlurper = new JsonSlurper()
inputJson = inputJson.replace(", }", "}") // Korrigiert leere Objekte
.replace(",]", "]") // Korrigiert leere Arrays
.replace(": ,", ": null,") // Setzt null für fehlerhafte leere Werte
.replace(": ,", ": null") // Falls letztes Element betroffen ist
// JSON parsen (nach der Korrektur)
//jsonObject = new groovy.json.JsonSlurper().parseText(inputJson)
//println(jsonObject)
// JSON parsen
jsonObject = jsonSlurper.parseText(inputJson)
println(jsonObject)
// Extrahiere die Key-Value-Paare
def extractedData = extractValues(jsonObject)
// Ausgabe als Tabelle
println "===================input Tabelle ========================="
println "| Parameter | Value |"
println "|----------------------------------------|---------------|"
extractedData.each { key, value ->
println "| ${key.padRight(38)} | ${value.toString().padRight(12)} |"
}
println "=========================================================="
// Umwandlung zurück in JSON
def reconstructedJson = [:]
extractedData.each { key, value ->
if (key == null || key.trim().isEmpty()) {
println("⚠️ WARNUNG: Leerer oder null-Key erkannt!")
return
}
def keys = key.split("\\.").toList()
if (keys.isEmpty()) {
println("⚠️ WARNUNG: `split()` hat eine leere Liste zurückgegeben für key: ${key}")
return
}
buildNestedMap(reconstructedJson, keys.toList(), value)
}
println("✅ Rekonstruiertes JSON: " + reconstructedJson)
// Speichern als JSON-Datei
inputJson = JsonOutput.prettyPrint(JsonOutput.toJson(reconstructedJson))
println "========================== inputJson ========================="
println inputJson
println "|------------------------------------------------------------|"
def matcher
String outputValue2
String outputString
String outputJson
// Schleife über alle Suchwerte in der Ausgabe
for (int searchIndex = 0; searchIndex < searchValues.size(); searchIndex++) {
String currentSearchValue = searchValues[searchIndex]
String newValueForThirdColumn = newValuesForThirdColumn[searchIndex]
// Schleife über alle Eingabefelder in der ersten Spalte
for (int i = 0; i < firstColumnOutputs.size(); i++) {
// Hole den Wert des aktuellen Output-Felds
String outputValue = (firstColumnOutputs[i]).getText()
// Überprüfen, ob der Wert dem aktuellen Suchwert entspricht (z.B. 'street', 'housenumber', 'city')
// XPath für das Eingabefeld in der dritten Spalte der passenden Zeile
// Erstelle ein dynamisches TestObject für die dritte Spalte
// Beende die Schleife, da der Wert gefunden und aktualisiert wurde
if (outputValue.equals(currentSearchValue)) {
String xpathThirdColumnOutput = ('//span[contains(text(), "Output")]/ancestor::div[3]//tbody//tr[' + (i + 1)) +
']/td[3]'
TestObject thirdColumnOutput = new TestObject()
thirdColumnOutput.addProperty('xpath', ConditionType.EQUALS, xpathThirdColumnOutput)
outputValue2 = WebUI.findWebElement(thirdColumnOutput).getText()
outputString = outputValue2
// DelegateID extrahieren
matcher = (outputString =~ '\\{(\\d+)=\\{')
delegateID = matcher.find() ? matcher.group(1) : null
//outputString= outputString.replace("{"+delegateID+"=","")
println("DelegateID: $delegateID")
// Original JSON-String
outputJson = outputString
println(outputString)
println(outputJson)
// JSON-String korrigieren
String correctedJson = outputString.replaceAll("(\\d+)=\\{", '"$1": {') // Zahlenschlüssel als Strings
.replaceAll("(\\w+)=", '"$1": ') // Schlüssel als Strings
.replaceAll(": ([^\"{}\\[\\d][^,}\\]]+)", ': "$1"') // Werte ohne Anführungszeichen in Strings umwandeln
.replaceAll(": (\\d+)\\b", ': $1') // Zahlenwerte korrekt setzen
.replaceAll(": \"(null)\"", ': null') // "null" als echten null-Wert setzen
.replaceAll(": ,", ': null,') // Fehlende Werte durch null ersetzen
.replaceAll(": }", ': null }') // Falls letztes Element betroffen ist
.replace(", }", "}") // Leere Objekte korrigieren
.replace(",]", "]") // Leere Arrays korrigieren
.replaceAll(": (\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+Z)", ': "$1"') // Datumswerte als Strings setzen
.replaceAll("\"entityGroupUUID\": ([^\",}{\\]]+)", '"entityGroupUUID": "$1"') // UUID als String
.replaceAll("\"linkTypeTechName\": ([^\",}{\\]]+)", '"linkTypeTechName": "$1"') // Strings sichern
.replaceAll("\"relationEntity\": ([^\",}{\\]]+)", '"relationEntity": "$1"') // Strings sichern
// Korrektur für spezifische Werte in fieldValue
correctedJson = correctedJson.replaceAll(
" Assess the organization's technology infrastructure and implement upgrades or enhancements to improve efficiency\", productivity, and cybersecurity. This might involve upgrading software systems, implementing cloud solutions, or enhancing network security measures.,",
" Assess the organization's technology infrastructure and implement upgrades or enhancements to improve efficiency, productivity, and cybersecurity. This might involve upgrading software systems, implementing cloud solutions, or enhancing network security measures.\","
)
println("Korrigiertes JSON:")
println(correctedJson)
// JSON parsen
jsonSlurper = new groovy.json.JsonSlurper()
jsonObject = jsonSlurper.parseText(correctedJson)
println("Parsed JSON Object:")
println(jsonObject)
// JSON schön formatieren
outputJson = JsonOutput.prettyPrint(JsonOutput.toJson(jsonObject))
println("Finales JSON:")
println(outputJson)
// Extrahiere die Key-Value-Paare
extractedData = extractValues(jsonObject)
// Ausgabe als Tabelle
println "================= Output Tabelle ========================="
println "| Parameter | Value |"
println "|----------------------------------------|---------------|"
extractedData.each { key, value ->
println "| ${key.padRight(38)} | ${value.toString().padRight(12)} |"
}
println "=========================================================="
println(inputJson)
println(outputJson)
break
}
}
}
def inputJsonObjekt = jsonSlurper.parseText(inputJson)
def outputJsonObjekt = jsonSlurper.parseText(outputJson)
// Sicherstellen, dass inputJson tatsächlich ein JSON-Objekt ist
if (!(inputJsonObjekt instanceof Map)) {
KeywordUtil.markWarning("inputJsonObjekt wurde nicht als Map geparst!")
}
if (!(inputJsonObjekt.variables instanceof Map)) {
KeywordUtil.markWarning("inputJsonObjekt.variables ist keine Map, sondern ${inputJsonObjekt.variables.getClass()}")
}
// Sicherstellen, dass outputJson tatsächlich ein JSON-Objekt ist
if (!(outputJsonObjekt instanceof Map)) {
KeywordUtil.markWarning("outputJsonObjekt wurde nicht als Map geparst!")
}
if (!outputJsonObjekt.containsKey(delegateID)) {
KeywordUtil.markFailed("Fehler: delegateID '$delegateID' nicht in outputJsonObjekt gefunden!")
return false
}
// **Handling für den Vergleich**: Falls `outputJsonObjekt[delegateID]` eine Liste ist, wird die erste Map aus der Liste verwendet.
def outputData = outputJsonObjekt[delegateID]
if (outputData instanceof List) {
outputData = outputData.find { it instanceof Map } // Nimm die erste Map aus der Liste
}
if (compareJson(inputJsonObjekt.variables, outputData)) {
KeywordUtil.markPassed("Alle Werte sind enthalten und korrekt!")
} else {
KeywordUtil.markFailed("Abweichungen in der JSON-Struktur gefunden!")
}
WebUI.navigateToUrl('https://po-client-dev-core-qa.services.fintus.io/')
GlobalVariable.OfferDraftFromExistingDataDelegateID = delegateID
WebUI.comment(GlobalVariable.OfferDraftFromExistingDataDelegateID)
WebUI.verifyNotEqual(findTestObject(GlobalVariable.OfferDraftFromExistingDataDelegateID), 'null')
//WebUI.comment(NeuerWertOfferDraftValues)
//WebUI.closeBrowser()
AFTER:
import static com.kms.katalon.core.checkpoint.CheckpointFactory.findCheckpoint
import static com.kms.katalon.core.testcase.TestCaseFactory.findTestCase
import static com.kms.katalon.core.testdata.TestDataFactory.findTestData
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import static com.kms.katalon.core.testobject.ObjectRepository.findWindowsObject
import com.github.javafaker.Faker as Faker
import com.kms.katalon.core.checkpoint.Checkpoint as Checkpoint
import com.kms.katalon.core.cucumber.keyword.CucumberBuiltinKeywords as CucumberKW
import com.kms.katalon.core.mobile.keyword.MobileBuiltInKeywords as Mobile
import com.kms.katalon.core.model.FailureHandling as FailureHandling
import com.kms.katalon.core.testcase.TestCase as TestCase
import com.kms.katalon.core.testdata.TestData as TestData
import com.kms.katalon.core.testng.keyword.TestNGBuiltinKeywords as TestNGKW
import com.kms.katalon.core.testobject.TestObject as TestObject
import com.kms.katalon.core.webservice.keyword.WSBuiltInKeywords as WS
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import com.kms.katalon.core.windows.keyword.WindowsBuiltinKeywords as Windows
import internal.GlobalVariable as GlobalVariable
import org.openqa.selenium.Keys as Keys
import org.openqa.selenium.WebElement as WebElement
import com.kms.katalon.core.testobject.ConditionType as ConditionType
import com.kms.katalon.core.util.KeywordUtil as KeywordUtil
import groovy.json.JsonSlurper as JsonSlurper
import groovy.json.JsonOutput as JsonOutput
WebUI.openBrowser('')
WebUI.callTestCase(findTestCase('workplace/TC- Generell Steps/Step001 - Login TA1 - Natural'), [:], FailureHandling.STOP_ON_FAILURE)
WebUI.navigateToUrl(GlobalVariable.poURL)
WebUI.waitForElementPresent(findTestObject('Page_Process Orchestrator/input_PO_Search'), 0)
WebUI.setText(findTestObject('Page_Process Orchestrator/input_PO_Search'), selectDeleagate)
WebUI.sendKeys(findTestObject('Page_Process Orchestrator/input_PO_Search'), Keys.chord(Keys.ENTER))
WebUI.delay(2)
WebUI.waitForElementPresent(findTestObject('Page_Process Orchestrator/table_Delegate', [('Delegate') : selectDeleagate]),
0)
WebUI.clickOffset(findTestObject('Page_Process Orchestrator/table_Delegate', [('Delegate') : selectDeleagate]), 0, 0)
WebUI.click(findTestObject('Page_Process Orchestrator/button Open DetailsSectionAccessButton'))
WebUI.waitForElementPresent(findTestObject('Object Repository/Page_Process Orchestrator/span_BPMN'), 0)
WebUI.click(findTestObject('Page_Process Orchestrator/span_Test'))
WebUI.waitForElementPresent(findTestObject('Object Repository/Page_Process Orchestrator/span_Input'), 0)
// Initialisiere Faker für generierte Testdaten
Faker faker = new Faker(new Locale('de'))
// XPath für alle Eingabefelder/Ausgabefelder in der ersten Spalte
String xpathFirstColumnInputs = '//span[contains(text(), "Input")]/ancestor::div[3]//tbody//tr/td[1]//input'
String xpathFirstColumnOutputs = '//span[contains(text(), "Output")]/ancestor::div[3]//tbody//td[1]'
// Erstelle ein dynamisches TestObject für die Eingabefelder/Ausgabefelder der ersten Spalte
TestObject dynamicFirstColumnInputs = new TestObject()
TestObject dynamicFirstColumnOutputs = new TestObject()
dynamicFirstColumnInputs.addProperty('xpath', ConditionType.EQUALS, xpathFirstColumnInputs)
dynamicFirstColumnOutputs.addProperty('xpath', ConditionType.EQUALS, xpathFirstColumnOutputs)
// Sammle alle WebElements der Eingabefelder in der ersten Spalte
List<String> firstColumnInputs = WebUI.findWebElements(dynamicFirstColumnInputs, 30)
//############################################################################
//
// Dieser Bereich muss für jedes Deligate angepasst werden
//
//############################################################################
// Liste der Suchwerte für Spalte 1 (Pflichtfelder)
List<String> searchValues = ['offerDrafts']
String id = 'null'
// Generierte Testdaten mit Faker
String NeuerWertLegalPersonID
String NeuerWertOfferId
if (GlobalVariable.OfferDelegateID == 'null') {
NeuerWertOfferId = '133901'
} else {
NeuerWertOfferId = GlobalVariable.OfferDelegateID
}
String NeuerWertProjectID
if (GlobalVariable.ProjectDelegateID == 'null') {
NeuerWertProjectID = '53108'
} else {
NeuerWertProjectID = GlobalVariable.ProjectDelegateID
}
if (GlobalVariable.LegalPersonDelegateID == 'null') {
NeuerWertLegalPersonID = '61309'
} else {
NeuerWertLegalPersonID = GlobalVariable.LegalPersonDelegateID
}
String NeuerWertOfferDraftValues = (((((((((((((((((((((((('[{"variables":{' + '"offerId":{"value":"') + NeuerWertOfferId) +
'"},') + '"entityName":{"value":"Project"},') + '"formTechnicalName":{"value":"offer_project_to_legal"},') + '"entityId":{"value":') +
NeuerWertProjectID) + '},') + '"entityType":{"value": "Project"},') + '"offerDraftLinks": {') + '"value":[{"linkTypeTechName": null,') +
'"children":[{"offerId":"') + NeuerWertOfferId) + '",') + '"entityName":"LegalPerson",') + '"formTechnicalName":"offer_project_to_legal",') +
'"entityType":"LegalPerson",') + '"entityId": ') + NeuerWertLegalPersonID) + ',') + '"offerDraftLinks":[{"linkTypeTechName":"project_2_legal_person",') +
'"children": [],') + '"existingLinkId":null}]}],') + '"existingLinkId":null}]}},') + '"withVariablesInReturn":true}]'
// Liste der neuen Werte, die in die dritte Spalte geschrieben werden sollen (Strings)
List<String> newValuesForThirdColumn = [NeuerWertOfferDraftValues]
//############################################################################
//
// Fertig ;)
//
//############################################################################
// Liste zur Speicherung der gesetzten Werte in der dritten Spalte
List<String> setThirdColumnValues = []
// Schleife über alle Suchwerte
for (int searchIndex = 0; searchIndex < searchValues.size(); searchIndex++) {
String currentSearchValue = searchValues[searchIndex]
String newValueForThirdColumn = newValuesForThirdColumn[searchIndex]
boolean valueFound = false
// Schleife über alle Eingabefelder in der ersten Spalte
for (int i = 0; i < firstColumnInputs.size(); i++) {
// Hole den Wert des aktuellen Input-Felds
String inputValue = (firstColumnInputs[i]).getAttribute('value')
// Überprüfen, ob der Wert dem aktuellen Suchwert entspricht (z.B. 'street', 'housenumber', 'city')
if (inputValue.equals(currentSearchValue)) {
valueFound = true
// XPath für das Eingabefeld in der dritten Spalte der passenden Zeile
String xpathThirdColumnInput = ('//tbody//tr[' + (i + 1)) + ']/td[3]//input'
// Erstelle ein dynamisches TestObject für die dritte Spalte
TestObject thirdColumnInput = new TestObject()
thirdColumnInput.addProperty('xpath', ConditionType.EQUALS, xpathThirdColumnInput)
// Setze den neuen Wert in die dritte Spalte
WebUI.setText(thirdColumnInput, newValueForThirdColumn)
// Speichere den gesetzten Wert zur späteren Überprüfung
setThirdColumnValues.add(newValueForThirdColumn)
// Beende die Schleife, da der Wert gefunden und aktualisiert wurde
break
}
}
// Wenn der Wert nicht gefunden wurde, füge eine neue Zeile hinzu
if (!(valueFound)) {
// Klicke auf die Schaltfläche "Field hinzufügen", um eine neue Zeile hinzuzufügen
WebUI.click(findTestObject('Object Repository/Page_Process Orchestrator/a_Field hinzufugen'))
// Warte kurz, bis die neue Zeile hinzugefügt wurde (Wartezeit anpassen, falls nötig)
WebUI.delay(2)
// Aktualisiere die Liste der Eingabefelder in der ersten Spalte (nachdem eine neue Zeile hinzugefügt wurde)
firstColumnInputs = WebUI.findWebElements(dynamicFirstColumnInputs, 30)
// XPath für das neue Eingabefeld in der ersten Spalte (letzte Zeile)
String xpathNewFirstColumnInput = ('//tbody//tr[' + firstColumnInputs.size()) + ']/td[1]//input'
// Erstelle ein dynamisches TestObject für das Eingabefeld in der neuen Zeile, Spalte 1
TestObject newFirstColumnInput = new TestObject()
newFirstColumnInput.addProperty('xpath', ConditionType.EQUALS, xpathNewFirstColumnInput)
// Setze den aktuellen Suchwert (z.B. 'street', 'housenumber') in die erste Spalte der neuen Zeile
WebUI.setText(newFirstColumnInput, currentSearchValue)
// XPath für das Eingabefeld in der dritten Spalte der neuen Zeile
String xpathNewThirdColumnInput = ('//tbody//tr[' + firstColumnInputs.size()) + ']/td[3]//input'
// Erstelle ein dynamisches TestObject für das Eingabefeld in der dritten Spalte der neuen Zeile
TestObject newThirdColumnInput = new TestObject()
newThirdColumnInput.addProperty('xpath', ConditionType.EQUALS, xpathNewThirdColumnInput)
// Setze den neuen Wert in die dritte Spalte der neuen Zeile
WebUI.setText(newThirdColumnInput, newValueForThirdColumn)
// Speichere den gesetzten Wert zur späteren Überprüfung
setThirdColumnValues.add(newValueForThirdColumn)
}
}
// Klicke auf den "Test" Button, um die Ausgabewerte zu generieren
WebUI.click(findTestObject('Page_Process Orchestrator/button_Speichern'))
WebUI.click(findTestObject('Object Repository/Page_Process Orchestrator/button_Test'))
// Warte, bis die Ausgabewerte vollständig geladen sind (anpassen, falls nötig)
WebUI.delay(5 // Anpassung je nach Ladezeit
)
// Aktualisiere die Liste der Ausgabefelder in der ersten Spalte (nachdem der Button geklickt wurde)
List<String> firstColumnOutputs = WebUI.findWebElements(dynamicFirstColumnOutputs, 30)
searchValues.add('id')
String delegateID
inputString = NeuerWertOfferDraftValues.replace('[', '').replace(']', '')
// Original JSON-String
String inputJson = inputString
println(inputString)
println(inputJson)
def jsonSlurper = new JsonSlurper()
// Korrigiert leere Objekte
// Korrigiert leere Arrays
// Setzt null für fehlerhafte leere Werte
// Falls letztes Element betroffen ist
inputJson = inputJson.replace(', }', '}').replace(',]', ']').replace(': ,', ': null,').replace(': ,', ': null')
// JSON parsen
jsonObject = jsonSlurper.parseText(inputJson)
//println(jsonObject)
println(jsonObject)
//##############################################################################
// Funktion zur Extraktion der Werte als Key-Value-Paare
// Funktion zum Reconstruck Json
// Rekursive Vergleichsfunktion
// Wenn input eine Map ist
// Wenn output keine Map ist, vergleiche die Werte direkt
// Wenn input eine Liste ist
// Wenn output keine Liste ist, vergleiche die Werte direkt
// Wenn input ein primitiver Wert ist (String, Zahl, Boolean usw.)
// Sicherstellen, dass Zahlen als String verglichen werden
//##############################################################################
// Extrahiere die Key-Value-Paare
def extractedData = extractValues(jsonObject)
// Ausgabe als Tabelle
println('===================input Tabelle =========================')
println('| Parameter | Value |')
println('|----------------------------------------|---------------|')
extractedData.each({ def key, def value ->
println("| $key.padRight(38) | $value.toString().padRight(12) |")
})
println('==========================================================')
// Umwandlung zurück in JSON
def reconstructedJson = [:]
extractedData.each({ def key, def value ->
if ((key == null) || key.trim().isEmpty()) {
println('⚠️ WARNUNG: Leerer oder null-Key erkannt!')
return null
}
def keys = key.split('\\.').toList()
if (keys.isEmpty()) {
println("⚠️ WARNUNG: `split()` hat eine leere Liste zurückgegeben für key: $key")
return null
}
buildNestedMap(reconstructedJson, keys.toList(), value)
})
println('✅ Rekonstruiertes JSON: ' + reconstructedJson)
// Speichern als JSON-Datei
inputJson = JsonOutput.prettyPrint(JsonOutput.toJson(reconstructedJson))
println('========================== inputJson =========================')
println(inputJson)
println('|------------------------------------------------------------|')
def matcher
String outputValue2
String outputString
String outputJson
// Schleife über alle Suchwerte in der Ausgabe
for (int searchIndex = 0; searchIndex < searchValues.size(); searchIndex++) {
String currentSearchValue = searchValues[searchIndex]
String newValueForThirdColumn = newValuesForThirdColumn[searchIndex]
// Schleife über alle Eingabefelder in der ersten Spalte
for (int i = 0; i < firstColumnOutputs.size(); i++) {
// Hole den Wert des aktuellen Output-Felds
String outputValue = (firstColumnOutputs[i]).getText()
// Überprüfen, ob der Wert dem aktuellen Suchwert entspricht (z.B. 'street', 'housenumber', 'city')
// XPath für das Eingabefeld in der dritten Spalte der passenden Zeile
// Erstelle ein dynamisches TestObject für die dritte Spalte
// Beende die Schleife, da der Wert gefunden und aktualisiert wurde
if (outputValue.equals(currentSearchValue)) {
String xpathThirdColumnOutput = ('//span[contains(text(), "Output")]/ancestor::div[3]//tbody//tr[' + (i + 1)) +
']/td[3]'
TestObject thirdColumnOutput = new TestObject()
thirdColumnOutput.addProperty('xpath', ConditionType.EQUALS, xpathThirdColumnOutput)
outputValue2 = WebUI.findWebElement(thirdColumnOutput).getText()
outputString = outputValue2
// DelegateID extrahieren
matcher = (outputString =~ '\\{(\\d+)=\\{')
delegateID = matcher.find() ? matcher.group(1) : null
//outputString= outputString.replace("{"+delegateID+"=","")
println("DelegateID: $delegateID")
// Original JSON-String
outputJson = outputString
println(outputString)
println(outputJson)
// JSON-String korrigieren
String correctedJson = outputString.replaceAll('(\\d+)=\\{', '"$1": {' // Zahlenschlüssel als Strings
).replaceAll('(\\w+)=', '"$1": ' // Schlüssel als Strings
).replaceAll(': ([^"{}\\[\\d][^,}\\]]+)', ': "$1"' // Werte ohne Anführungszeichen in Strings umwandeln
).replaceAll(': (\\d+)\\b', ': $1' // Zahlenwerte korrekt setzen
).replaceAll(': "(null)"', ': null' // "null" als echten null-Wert setzen
).replaceAll(': ,', ': null,' // Fehlende Werte durch null ersetzen
).replaceAll(': }', ': null }' // Falls letztes Element betroffen ist
).replace(', }', '}' // Leere Objekte korrigieren
).replace(',]', ']' // Leere Arrays korrigieren
).replaceAll(': (\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+Z)', ': "$1"' // Datumswerte als Strings setzen
).replaceAll('"entityGroupUUID": ([^",}{\\]]+)', '"entityGroupUUID": "$1"' // UUID als String
).replaceAll('"linkTypeTechName": ([^",}{\\]]+)', '"linkTypeTechName": "$1"' // Strings sichern
).replaceAll('"relationEntity": ([^",}{\\]]+)', '"relationEntity": "$1"' // Strings sichern
).replaceAll('"fieldValue": ",', '"fieldValue": null,').replaceAll('"fieldType": CUSTOM"', '"fieldType": "CUSTOM"')
if (GlobalVariable.LegalPersonDelegateName == 'null') {
println('Debug Run') // Dynamischer Teil mit Regex erfassen (alles zwischen "LegalPerson " und ', "fieldType":')
} else {
correctedJson = correctedJson.replaceAll('("fieldValue": "LegalPerson )(.*?)(", "fieldType":)', ('$1' +
GlobalVariable.LegalPersonDelegateName) + '$3')
}
// Korrektur für spezifische Werte in fieldValue
correctedJson = correctedJson.replaceAll(' Assess the organization\'s technology infrastructure and implement upgrades or enhancements to improve efficiency", productivity, and cybersecurity. This might involve upgrading software systems, implementing cloud solutions, or enhancing network security measures.,',
' Assess the organization\'s technology infrastructure and implement upgrades or enhancements to improve efficiency, productivity, and cybersecurity. This might involve upgrading software systems, implementing cloud solutions, or enhancing network security measures.",')
println('Korrigiertes JSON:')
println(correctedJson)
// JSON parsen
jsonSlurper = new JsonSlurper()
jsonObject = jsonSlurper.parseText(correctedJson)
println('Parsed JSON Object:')
println(jsonObject)
// JSON schön formatieren
outputJson = JsonOutput.prettyPrint(JsonOutput.toJson(jsonObject))
println('Finales JSON:')
println(outputJson)
// Extrahiere die Key-Value-Paare
extractedData = extractValues(jsonObject)
// Ausgabe als Tabelle
println('================= Output Tabelle =========================')
println('| Parameter | Value |')
println('|----------------------------------------|---------------|')
extractedData.each({ def key, def value ->
println("| $key.padRight(38) | $value.toString().padRight(12) |")
})
println('==========================================================')
println(inputJson)
println(outputJson)
break
}
}
}
def inputJsonObjekt = jsonSlurper.parseText(inputJson)
def outputJsonObjekt = jsonSlurper.parseText(outputJson)
// Sicherstellen, dass inputJson tatsächlich ein JSON-Objekt ist
if (!(inputJsonObjekt instanceof Map)) {
KeywordUtil.markWarning('inputJsonObjekt wurde nicht als Map geparst!')
}
if (!(inputJsonObjekt.variables instanceof Map)) {
KeywordUtil.markWarning("inputJsonObjekt.variables ist keine Map, sondern $inputJsonObjekt.variables.getClass()")
}
// Sicherstellen, dass outputJson tatsächlich ein JSON-Objekt ist
if (!(outputJsonObjekt instanceof Map)) {
KeywordUtil.markWarning('outputJsonObjekt wurde nicht als Map geparst!')
}
if (!(outputJsonObjekt.containsKey(delegateID))) {
KeywordUtil.markFailed("Fehler: delegateID '$delegateID' nicht in outputJsonObjekt gefunden!")
return false
}
// **Handling für den Vergleich**: Falls `outputJsonObjekt[delegateID]` eine Liste ist, wird die erste Map aus der Liste verwendet.
def outputData = outputJsonObjekt[delegateID]
if (outputData instanceof List) {
outputData = outputData.find({
it instanceof Map // Nimm die erste Map aus der Liste
})
}
if (compareJson(inputJsonObjekt.variables, outputData)) {
KeywordUtil.markPassed('Alle Werte sind enthalten und korrekt!')
} else {
KeywordUtil.markFailed('Abweichungen in der JSON-Struktur gefunden!')
}
WebUI.navigateToUrl('https://po-client-dev-core-qa.services.fintus.io/')
GlobalVariable.OfferDraftFromExistingDataDelegateID = delegateID
newValuesForThirdColumn.add(delegateID)
GlobalVariable.OfferDraftFromExistingDataDelegateSearchList = searchValues
GlobalVariable.OfferDraftFromExistingDataDelegateResultList = newValuesForThirdColumn
WebUI.comment(GlobalVariable.OfferDraftFromExistingDataDelegateSearchList.toString())
WebUI.comment(GlobalVariable.OfferDraftFromExistingDataDelegateResultList.toString())
WebUI.comment(GlobalVariable.OfferDraftFromExistingDataDelegateID)
WebUI.verifyNotEqual(findTestObject(GlobalVariable.OfferDraftFromExistingDataDelegateID), 'null')
not_run: WebUI.closeBrowser()
def extractValues(Map jsonMap, String parentKey = '') {
def result = [:]
jsonMap.each({ def key, def value ->
def newKey = parentKey ? "$parentKey.$key" : key
if ((value instanceof Map) && value.containsKey('value')) {
(result[newKey]) = value.value
} else if (value instanceof Map) {
result.putAll(extractValues(value, newKey))
} else {
(result[newKey]) = value
}
})
return result
}
void buildNestedMap(Map target, List<String> keys, def value) {
if (keys.size() == 1) {
(target[(keys[0])]) = value
return null
}
if (!(target.containsKey(keys[0])) || !((target[(keys[0])]) instanceof Map)) {
(target[(keys[0])]) = [:]
}
buildNestedMap(target[(keys[0])], keys[(1..-1)], value)
}
boolean compareJson(def input, def output) {
if ((input == null) || (output == null)) {
if (input != output) {
KeywordUtil.markWarning("Fehler: Null-Werte stimmen nicht überein. Erwartet: $input, Gefunden: $output")
return false
}
return true
}
if (input instanceof Map) {
if (!(output instanceof Map)) {
if (input != output) {
WebUI.comment("Fehler: Erwartete Map oder gleichen Wert, aber gefunden: $output.getClass() mit Wert $output")
return false
}
return true
}
input.each({ def key, def value ->
if (!(output.containsKey(key))) {
WebUI.comment("Fehlender Schlüssel in Output: $key")
return false
}
if (!(compareJson(value, output[key]))) {
return false
}
})
} else if (input instanceof List) {
if (!(output instanceof List)) {
if (input != output) {
WebUI.comment("Fehler: Erwartete Liste oder gleichen Wert, aber gefunden: $output.getClass() mit Wert $output")
return false
}
return true
}
if (input.size() > output.size()) {
WebUI.comment("Listenlängen stimmen nicht überein: Erwartet mindestens $input.size(), aber gefunden $output.size()")
return false
}
input.eachWithIndex({ def item, def index ->
if (!(compareJson(item, output[index]))) {
WebUI.comment("Listenwert an Index $index stimmt nicht überein: Erwartet $item, aber gefunden $output[index]")
return false
}
})
} else {
def inputNormalized = input instanceof Number ? input.toString() : input
def outputNormalized = output instanceof Number ? output.toString() : output
if (inputNormalized != outputNormalized) {
WebUI.comment("Wert stimmt nicht überein: Erwartet $inputNormalized, aber gefunden $outputNormalized")
return false
}
}
return true
}