jms -> mq
This commit is contained in:
parent
70c4540c4a
commit
ab7d898b8e
@ -30,7 +30,6 @@
|
|||||||
<commons-configuration.version>1.6</commons-configuration.version>
|
<commons-configuration.version>1.6</commons-configuration.version>
|
||||||
<cxf.version>4.0.3</cxf.version>
|
<cxf.version>4.0.3</cxf.version>
|
||||||
<ibm.mq.version>9.4.5.0</ibm.mq.version>
|
<ibm.mq.version>9.4.5.0</ibm.mq.version>
|
||||||
<javax.jms.version>2.0.1</javax.jms.version>
|
|
||||||
<kafka.clients.version>3.7.0</kafka.clients.version>
|
<kafka.clients.version>3.7.0</kafka.clients.version>
|
||||||
<confluent.version>7.6.0</confluent.version>
|
<confluent.version>7.6.0</confluent.version>
|
||||||
<assertj.version>3.24.2</assertj.version>
|
<assertj.version>3.24.2</assertj.version>
|
||||||
@ -296,12 +295,6 @@
|
|||||||
<artifactId>com.ibm.mq.allclient</artifactId>
|
<artifactId>com.ibm.mq.allclient</artifactId>
|
||||||
<version>${ibm.mq.version}</version>
|
<version>${ibm.mq.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>javax.jms</groupId>
|
|
||||||
<artifactId>javax.jms-api</artifactId>
|
|
||||||
<version>${javax.jms.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Kafka dependencies -->
|
<!-- Kafka dependencies -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.kafka</groupId>
|
<groupId>org.apache.kafka</groupId>
|
||||||
|
|||||||
@ -1,24 +1,23 @@
|
|||||||
package cz.moneta.test.harness.connectors.messaging;
|
package cz.moneta.test.harness.connectors.messaging;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.EOFException;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Hashtable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.jms.BytesMessage;
|
|
||||||
import javax.jms.JMSConsumer;
|
|
||||||
import javax.jms.JMSContext;
|
|
||||||
import javax.jms.JMSException;
|
|
||||||
import javax.jms.JMSRuntimeException;
|
|
||||||
import javax.jms.Message;
|
|
||||||
import javax.jms.TextMessage;
|
|
||||||
import javax.net.ssl.KeyManagerFactory;
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
@ -27,26 +26,28 @@ import javax.net.ssl.TrustManagerFactory;
|
|||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import com.ibm.mq.jms.MQConnectionFactory;
|
import com.ibm.mq.MQException;
|
||||||
|
import com.ibm.mq.MQGetMessageOptions;
|
||||||
|
import com.ibm.mq.MQMessage;
|
||||||
|
import com.ibm.mq.MQPutMessageOptions;
|
||||||
|
import com.ibm.mq.MQQueue;
|
||||||
|
import com.ibm.mq.MQQueueManager;
|
||||||
|
import com.ibm.mq.constants.CMQC;
|
||||||
import com.ibm.msg.client.wmq.WMQConstants;
|
import com.ibm.msg.client.wmq.WMQConstants;
|
||||||
|
|
||||||
import cz.moneta.test.harness.connectors.Connector;
|
import cz.moneta.test.harness.connectors.Connector;
|
||||||
import cz.moneta.test.harness.messaging.MessageContentType;
|
|
||||||
import cz.moneta.test.harness.messaging.MqMessageFormat;
|
|
||||||
import cz.moneta.test.harness.messaging.ReceivedMessage;
|
|
||||||
import cz.moneta.test.harness.messaging.exception.MessagingConnectionException;
|
|
||||||
import cz.moneta.test.harness.messaging.exception.MessagingDestinationException;
|
|
||||||
import cz.moneta.test.harness.messaging.exception.MessagingTimeoutException;
|
|
||||||
import cz.moneta.test.harness.support.messaging.ImqRequest;
|
import cz.moneta.test.harness.support.messaging.ImqRequest;
|
||||||
|
import cz.moneta.test.harness.support.messaging.MessageContentType;
|
||||||
|
import cz.moneta.test.harness.support.messaging.MqMessageFormat;
|
||||||
|
import cz.moneta.test.harness.support.messaging.ReceivedMessage;
|
||||||
|
import cz.moneta.test.harness.support.messaging.exception.MessagingConnectionException;
|
||||||
|
import cz.moneta.test.harness.support.messaging.exception.MessagingDestinationException;
|
||||||
|
import cz.moneta.test.harness.support.messaging.exception.MessagingTimeoutException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IBM MQ connector using JMS client with Jakarta JMS API. Supports
|
* IBM MQ connector using the native com.ibm.mq classes. Supports
|
||||||
* multi-instance Queue Manager, SSL/TLS, and multiple message formats.
|
* multi-instance Queue Manager connection lists, SSL/TLS, message properties,
|
||||||
* <p>
|
* and JSON/XML/UTF-8/EBCDIC payload formats.
|
||||||
* Supported formats: - JSON: JMS TextMessage with plain JSON string (default) -
|
|
||||||
* XML: JMS TextMessage with XML string - UTF-8 (CCSID 1208): JMS BytesMessage
|
|
||||||
* with UTF-8 encoding - EBCDIC (CCSID 870): JMS BytesMessage with EBCDIC
|
|
||||||
* IBM-870 encoding
|
|
||||||
*/
|
*/
|
||||||
public class IbmMqConnector implements Connector {
|
public class IbmMqConnector implements Connector {
|
||||||
|
|
||||||
@ -59,12 +60,19 @@ public class IbmMqConnector implements Connector {
|
|||||||
private static final long DEFAULT_MAX_POLL_INTERVAL_MS = 1000;
|
private static final long DEFAULT_MAX_POLL_INTERVAL_MS = 1000;
|
||||||
|
|
||||||
private static final String TLS_VERSION = "TLSv1.2";
|
private static final String TLS_VERSION = "TLSv1.2";
|
||||||
|
private static final String JMS_ID_PREFIX = "ID:";
|
||||||
|
private static final Pattern SELECTOR_EQUALS_PATTERN = Pattern
|
||||||
|
.compile("\\s*([A-Za-z_][A-Za-z0-9_.-]*)\\s*=\\s*'((?:''|[^'])*)'\\s*");
|
||||||
|
|
||||||
private final MQConnectionFactory connectionFactory;
|
private final String connectionNameList;
|
||||||
private JMSContext jmsContext;
|
private final String channel;
|
||||||
private final String queueManager;
|
private final String queueManager;
|
||||||
private final String user;
|
private final String user;
|
||||||
private final String password;
|
private final String password;
|
||||||
|
private final SSLSocketFactory sslSocketFactory;
|
||||||
|
private final String sslCipherSuite;
|
||||||
|
|
||||||
|
private MQQueueManager mqQueueManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor with multi-instance Queue Manager support.
|
* Constructor with multi-instance Queue Manager support.
|
||||||
@ -82,35 +90,17 @@ public class IbmMqConnector implements Connector {
|
|||||||
*/
|
*/
|
||||||
public IbmMqConnector(String connectionNameList, String channel, String queueManager, String user, String password,
|
public IbmMqConnector(String connectionNameList, String channel, String queueManager, String user, String password,
|
||||||
String keystorePath, String keystorePassword, String sslCipherSuite) {
|
String keystorePath, String keystorePassword, String sslCipherSuite) {
|
||||||
|
this.connectionNameList = connectionNameList;
|
||||||
|
this.channel = channel;
|
||||||
this.queueManager = queueManager;
|
this.queueManager = queueManager;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
|
this.sslCipherSuite = sslCipherSuite;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
connectionFactory = new MQConnectionFactory();
|
this.sslSocketFactory = keystorePath != null && !keystorePath.isBlank() && keystorePassword != null
|
||||||
connectionFactory.setConnectionNameList(connectionNameList);
|
&& !keystorePassword.isBlank() ? getSslSocketFactory(keystorePath, keystorePassword) : null;
|
||||||
connectionFactory.setQueueManager(queueManager);
|
|
||||||
connectionFactory.setChannel(channel);
|
|
||||||
connectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
|
|
||||||
if (user != null && !user.isBlank()) {
|
|
||||||
connectionFactory.setStringProperty(WMQConstants.USERID, user);
|
|
||||||
}
|
|
||||||
if (password != null && !password.isBlank()) {
|
|
||||||
connectionFactory.setStringProperty(WMQConstants.PASSWORD, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keystorePath != null && !keystorePath.isBlank() && keystorePassword != null
|
|
||||||
&& !keystorePassword.isBlank()) {
|
|
||||||
connectionFactory.setSSLSocketFactory(getSslSocketFactory(keystorePath, keystorePassword));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sslCipherSuite != null && !sslCipherSuite.isBlank()) {
|
|
||||||
connectionFactory.setSSLCipherSuite(sslCipherSuite);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize JMS context
|
|
||||||
connect();
|
connect();
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new MessagingConnectionException("Failed to create IBM MQ connection to " + queueManager, e);
|
throw new MessagingConnectionException("Failed to create IBM MQ connection to " + queueManager, e);
|
||||||
}
|
}
|
||||||
@ -121,97 +111,82 @@ public class IbmMqConnector implements Connector {
|
|||||||
*/
|
*/
|
||||||
private void connect() {
|
private void connect() {
|
||||||
try {
|
try {
|
||||||
this.jmsContext = connectionFactory.createContext(user, password, JMSContext.AUTO_ACKNOWLEDGE);
|
this.mqQueueManager = new MQQueueManager(queueManager, createConnectionProperties());
|
||||||
this.jmsContext.start();
|
|
||||||
LOG.info("Connected to IBM MQ: {}", queueManager);
|
LOG.info("Connected to IBM MQ: {}", queueManager);
|
||||||
} catch (Exception e) {
|
} catch (MQException e) {
|
||||||
throw new MessagingConnectionException(
|
throw new MessagingConnectionException(
|
||||||
"Failed to connect to IBM MQ: " + queueManager + " - " + e.getMessage(), e);
|
"Failed to connect to IBM MQ: " + queueManager + " - " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Hashtable<String, Object> createConnectionProperties() {
|
||||||
|
Hashtable<String, Object> properties = new Hashtable<>();
|
||||||
|
if (connectionNameList != null && !connectionNameList.isBlank()) {
|
||||||
|
properties.put(WMQConstants.WMQ_CONNECTION_NAME_LIST, connectionNameList);
|
||||||
|
}
|
||||||
|
properties.put(CMQC.CHANNEL_PROPERTY, channel);
|
||||||
|
properties.put(CMQC.TRANSPORT_PROPERTY, CMQC.TRANSPORT_MQSERIES_CLIENT);
|
||||||
|
|
||||||
|
if (user != null && !user.isBlank()) {
|
||||||
|
properties.put(CMQC.USER_ID_PROPERTY, user);
|
||||||
|
}
|
||||||
|
if (password != null && !password.isBlank()) {
|
||||||
|
properties.put(CMQC.PASSWORD_PROPERTY, password);
|
||||||
|
}
|
||||||
|
if (sslSocketFactory != null) {
|
||||||
|
properties.put(CMQC.SSL_SOCKET_FACTORY_PROPERTY, sslSocketFactory);
|
||||||
|
}
|
||||||
|
if (sslCipherSuite != null && !sslCipherSuite.isBlank()) {
|
||||||
|
properties.put(CMQC.SSL_CIPHER_SUITE_PROPERTY, sslCipherSuite);
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a JSON or XML message as TextMessage.
|
* Send a JSON or XML message as MQ string message.
|
||||||
*/
|
*/
|
||||||
private void sendTextMessage(String queueName, String payload, Map<String, String> properties) {
|
private void sendTextMessage(String queueName, String payload, Map<String, String> properties) {
|
||||||
javax.jms.Queue queue = getQueue(queueName);
|
sendMessage(queueName, payload.getBytes(UTF_8), UTF_8, 1208, CMQC.MQFMT_STRING, properties, "JSON/XML");
|
||||||
|
|
||||||
TextMessage message = jmsContext.createTextMessage(payload);
|
|
||||||
|
|
||||||
// Set JMS properties
|
|
||||||
if (properties != null) {
|
|
||||||
for (Map.Entry<String, String> entry : properties.entrySet()) {
|
|
||||||
try {
|
|
||||||
if (entry.getKey().equals(ImqRequest.PROP_JMS_CORRELATION_ID)) {
|
|
||||||
message.setJMSCorrelationID(entry.getValue());
|
|
||||||
continue;
|
|
||||||
} else if (entry.getKey().equals(ImqRequest.PROP_JMS_TYPE)) {
|
|
||||||
message.setJMSType(entry.getValue());
|
|
||||||
continue;
|
|
||||||
} else if (entry.getKey().equals(ImqRequest.PROP_JMS_MESSAGE_ID)) {
|
|
||||||
message.setJMSMessageID(entry.getValue());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
message.setStringProperty(entry.getKey(), entry.getValue());
|
|
||||||
} catch (JMSException e) {
|
|
||||||
LOG.warn("Failed to set property: {}", entry.getKey(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
jmsContext.createProducer().send(queue, message);
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
throw new MessagingDestinationException("Failed to send message to queue: " + queueName, e);
|
|
||||||
}
|
|
||||||
LOG.debug("Sent JSON/XML message to queue: {}", queueName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message as BytesMessage with specific encoding and CCSID.
|
* Send a message as raw bytes with specific encoding and CCSID.
|
||||||
*/
|
*/
|
||||||
private void sendBytesMessage(String queueName, String payload, Charset charset, int ccsid,
|
private void sendBytesMessage(String queueName, String payload, Charset charset, int ccsid,
|
||||||
Map<String, String> properties) {
|
Map<String, String> properties) {
|
||||||
javax.jms.Queue queue = getQueue(queueName);
|
sendMessage(queueName, payload.getBytes(charset), charset, ccsid, CMQC.MQFMT_NONE, properties,
|
||||||
|
charset.displayName());
|
||||||
|
}
|
||||||
|
|
||||||
BytesMessage message = jmsContext.createBytesMessage();
|
private void sendMessage(String queueName, byte[] payload, Charset charset, int ccsid, String mqFormat,
|
||||||
|
Map<String, String> properties, String logFormat) {
|
||||||
// Convert payload to bytes using specified charset
|
MQQueue queue = null;
|
||||||
byte[] bytes = payload.getBytes(charset);
|
|
||||||
try {
|
try {
|
||||||
message.writeBytes(bytes);
|
int openOptions = CMQC.MQOO_OUTPUT | CMQC.MQOO_FAIL_IF_QUIESCING;
|
||||||
|
|
||||||
|
queue = openQueue(queueName, openOptions);
|
||||||
|
|
||||||
|
MQMessage message = new MQMessage();
|
||||||
|
message.format = mqFormat;
|
||||||
|
message.characterSet = ccsid;
|
||||||
|
message.write(payload);
|
||||||
|
if (!CMQC.MQFMT_STRING.equals(mqFormat)) {
|
||||||
message.setIntProperty("CCSID", ccsid);
|
message.setIntProperty("CCSID", ccsid);
|
||||||
} catch (JMSException e) {
|
|
||||||
throw new MessagingDestinationException("Failed to create bytes message", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set JMS properties
|
MQPutMessageOptions putOptions = new MQPutMessageOptions();
|
||||||
if (properties != null) {
|
putOptions.options = CMQC.MQPMO_NO_SYNCPOINT | CMQC.MQPMO_FAIL_IF_QUIESCING;
|
||||||
for (Map.Entry<String, String> entry : properties.entrySet()) {
|
applyMessageProperties(message, properties);
|
||||||
try {
|
|
||||||
if (entry.getKey().equals(ImqRequest.PROP_JMS_CORRELATION_ID)) {
|
|
||||||
message.setJMSCorrelationID(entry.getValue());
|
|
||||||
continue;
|
|
||||||
} else if (entry.getKey().equals(ImqRequest.PROP_JMS_TYPE)) {
|
|
||||||
message.setJMSType(entry.getValue());
|
|
||||||
continue;
|
|
||||||
} else if (entry.getKey().equals(ImqRequest.PROP_JMS_MESSAGE_ID)) {
|
|
||||||
message.setJMSMessageID(entry.getValue());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
message.setStringProperty(entry.getKey(), entry.getValue());
|
|
||||||
} catch (JMSException e) {
|
|
||||||
LOG.warn("Failed to set property: {}", entry.getKey(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
queue.put(message, putOptions);
|
||||||
jmsContext.createProducer().send(queue, message);
|
} catch (MQException | IOException e) {
|
||||||
} catch (RuntimeException e) {
|
|
||||||
throw new MessagingDestinationException("Failed to send message to queue: " + queueName, e);
|
throw new MessagingDestinationException("Failed to send message to queue: " + queueName, e);
|
||||||
|
} finally {
|
||||||
|
closeQueue(queue, queueName);
|
||||||
}
|
}
|
||||||
LOG.debug("Sent {} message to queue: {}", charset, queueName);
|
|
||||||
|
LOG.debug("Sent {} message ({}) to queue: {}", logFormat, charset, queueName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,7 +195,7 @@ public class IbmMqConnector implements Connector {
|
|||||||
* @param queueName Queue name
|
* @param queueName Queue name
|
||||||
* @param payload Message payload
|
* @param payload Message payload
|
||||||
* @param format Message format (JSON, XML, EBCDIC_870, UTF8_1208)
|
* @param format Message format (JSON, XML, EBCDIC_870, UTF8_1208)
|
||||||
* @param properties JMS properties to set
|
* @param properties message properties to set
|
||||||
*/
|
*/
|
||||||
public void send(String queueName, String payload, MqMessageFormat format, Map<String, String> properties) {
|
public void send(String queueName, String payload, MqMessageFormat format, Map<String, String> properties) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
@ -234,64 +209,108 @@ public class IbmMqConnector implements Connector {
|
|||||||
* Receive a message from a queue with timeout.
|
* Receive a message from a queue with timeout.
|
||||||
*
|
*
|
||||||
* @param queueName Queue name
|
* @param queueName Queue name
|
||||||
* @param messageSelector JMS message selector (optional)
|
* @param messageSelector JMS-style message selector (optional). Equality
|
||||||
|
* predicates joined by AND are evaluated client-side.
|
||||||
* @param format Expected message format
|
* @param format Expected message format
|
||||||
* @param timeout Timeout duration
|
* @param timeout Timeout duration
|
||||||
* @return Received message
|
* @return Received message
|
||||||
*/
|
*/
|
||||||
public ReceivedMessage receive(String queueName, String messageSelector, MqMessageFormat format,
|
public ReceivedMessage receive(String queueName, String messageSelector, MqMessageFormat format, Duration timeout) {
|
||||||
java.time.Duration timeout) {
|
if (messageSelector == null || messageSelector.isBlank()) {
|
||||||
long timeoutMs = timeout.toMillis();
|
return receiveNext(queueName, format, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
javax.jms.Queue queue = getQueue(queueName);
|
return receiveMatching(queueName, messageSelector, format, timeout);
|
||||||
JMSConsumer consumer = (messageSelector == null || messageSelector.isBlank() ? jmsContext.createConsumer(queue)
|
}
|
||||||
: jmsContext.createConsumer(queue, messageSelector));
|
|
||||||
|
|
||||||
AtomicBoolean messageFound = new AtomicBoolean(false);
|
|
||||||
ReceivedMessage received = null;
|
|
||||||
|
|
||||||
long pollInterval = DEFAULT_POLL_INTERVAL_MS;
|
|
||||||
long remainingTime = timeoutMs;
|
|
||||||
|
|
||||||
|
private ReceivedMessage receiveNext(String queueName, MqMessageFormat format, Duration timeout) {
|
||||||
|
MQQueue queue = null;
|
||||||
try {
|
try {
|
||||||
while (remainingTime > 0 && !messageFound.get()) {
|
queue = openQueue(queueName, CMQC.MQOO_INPUT_SHARED | CMQC.MQOO_FAIL_IF_QUIESCING);
|
||||||
Message message = consumer.receive(remainingTime);
|
MQMessage message = new MQMessage();
|
||||||
|
MQGetMessageOptions getOptions = new MQGetMessageOptions();
|
||||||
|
getOptions.options = CMQC.MQGMO_WAIT | CMQC.MQGMO_NO_SYNCPOINT | CMQC.MQGMO_FAIL_IF_QUIESCING;
|
||||||
|
getOptions.waitInterval = toWaitInterval(timeout.toMillis());
|
||||||
|
|
||||||
if (message != null) {
|
queue.get(message, getOptions);
|
||||||
received = decodeMessage(message, queueName, format);
|
return decodeMessage(message, queueName, format);
|
||||||
messageFound.set(true);
|
} catch (MQException e) {
|
||||||
} else {
|
if (e.reasonCode == CMQC.MQRC_NO_MSG_AVAILABLE) {
|
||||||
// Exponential backoff
|
|
||||||
pollInterval = Math.min(pollInterval * 2, DEFAULT_MAX_POLL_INTERVAL_MS);
|
|
||||||
remainingTime -= pollInterval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (received == null) {
|
|
||||||
throw new MessagingTimeoutException("No message matching filter found on queue '" + queueName
|
throw new MessagingTimeoutException("No message matching filter found on queue '" + queueName
|
||||||
+ "' within " + timeout.toMillis() + "ms");
|
+ "' within " + timeout.toMillis() + "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
return received;
|
|
||||||
|
|
||||||
} catch (MessagingTimeoutException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new MessagingDestinationException("Failed to receive message from queue: " + queueName, e);
|
throw new MessagingDestinationException("Failed to receive message from queue: " + queueName, e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
closeQueue(queue, queueName);
|
||||||
consumer.close();
|
|
||||||
} catch (JMSRuntimeException e) {
|
|
||||||
LOG.warn("Failed to close consumer", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReceivedMessage receiveMatching(String queueName, String messageSelector, MqMessageFormat format,
|
||||||
|
Duration timeout) {
|
||||||
|
long deadline = System.currentTimeMillis() + timeout.toMillis();
|
||||||
|
long pollInterval = DEFAULT_POLL_INTERVAL_MS;
|
||||||
|
Selector selector = Selector.parse(messageSelector);
|
||||||
|
|
||||||
|
while (System.currentTimeMillis() < deadline) {
|
||||||
|
ReceivedMessage received = tryReceiveMatching(queueName, format, selector);
|
||||||
|
if (received != null) {
|
||||||
|
return received;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleepQuietly(Math.min(pollInterval, Math.max(1, deadline - System.currentTimeMillis())));
|
||||||
|
pollInterval = Math.min(pollInterval * 2, DEFAULT_MAX_POLL_INTERVAL_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new MessagingTimeoutException("No message matching filter found on queue '" + queueName + "' within "
|
||||||
|
+ timeout.toMillis() + "ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReceivedMessage tryReceiveMatching(String queueName, MqMessageFormat format, Selector selector) {
|
||||||
|
MQQueue queue = null;
|
||||||
|
try {
|
||||||
|
queue = openQueue(queueName,
|
||||||
|
CMQC.MQOO_BROWSE | CMQC.MQOO_INPUT_SHARED | CMQC.MQOO_FAIL_IF_QUIESCING);
|
||||||
|
|
||||||
|
MQGetMessageOptions browseOptions = new MQGetMessageOptions();
|
||||||
|
browseOptions.options = CMQC.MQGMO_BROWSE_FIRST | CMQC.MQGMO_NO_SYNCPOINT | CMQC.MQGMO_FAIL_IF_QUIESCING;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
MQMessage browsedMessage = new MQMessage();
|
||||||
|
try {
|
||||||
|
queue.get(browsedMessage, browseOptions);
|
||||||
|
} catch (MQException e) {
|
||||||
|
if (e.reasonCode == CMQC.MQRC_NO_MSG_AVAILABLE) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReceivedMessage browsed = decodeMessage(browsedMessage, queueName, format);
|
||||||
|
if (selector.matches(browsed.getHeaders())) {
|
||||||
|
MQMessage removedMessage = new MQMessage();
|
||||||
|
MQGetMessageOptions removeOptions = new MQGetMessageOptions();
|
||||||
|
removeOptions.options = CMQC.MQGMO_MSG_UNDER_CURSOR | CMQC.MQGMO_NO_SYNCPOINT
|
||||||
|
| CMQC.MQGMO_FAIL_IF_QUIESCING;
|
||||||
|
queue.get(removedMessage, removeOptions);
|
||||||
|
return decodeMessage(removedMessage, queueName, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
browseOptions.options = CMQC.MQGMO_BROWSE_NEXT | CMQC.MQGMO_NO_SYNCPOINT
|
||||||
|
| CMQC.MQGMO_FAIL_IF_QUIESCING;
|
||||||
|
}
|
||||||
|
} catch (MQException | RuntimeException e) {
|
||||||
|
throw new MessagingDestinationException("Failed to receive message from queue: " + queueName, e);
|
||||||
|
} finally {
|
||||||
|
closeQueue(queue, queueName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Browse a queue (non-destructive read).
|
* Browse a queue (non-destructive read).
|
||||||
*
|
*
|
||||||
* @param queueName Queue name
|
* @param queueName Queue name
|
||||||
* @param messageSelector JMS message selector (optional)
|
* @param messageSelector JMS-style message selector (optional). Equality
|
||||||
|
* predicates joined by AND are evaluated client-side.
|
||||||
* @param format Expected message format
|
* @param format Expected message format
|
||||||
* @param maxMessages Maximum number of messages to browse
|
* @param maxMessages Maximum number of messages to browse
|
||||||
* @return List of received messages
|
* @return List of received messages
|
||||||
@ -299,170 +318,268 @@ public class IbmMqConnector implements Connector {
|
|||||||
public List<ReceivedMessage> browse(String queueName, String messageSelector, MqMessageFormat format,
|
public List<ReceivedMessage> browse(String queueName, String messageSelector, MqMessageFormat format,
|
||||||
int maxMessages) {
|
int maxMessages) {
|
||||||
List<ReceivedMessage> messages = new ArrayList<>();
|
List<ReceivedMessage> messages = new ArrayList<>();
|
||||||
javax.jms.Queue queue = getQueue(queueName);
|
Selector selector = Selector.parse(messageSelector);
|
||||||
|
MQQueue queue = null;
|
||||||
|
|
||||||
try (javax.jms.QueueBrowser browser = (messageSelector == null || messageSelector.isBlank())
|
try {
|
||||||
? jmsContext.createBrowser(queue)
|
queue = openQueue(queueName, CMQC.MQOO_BROWSE | CMQC.MQOO_FAIL_IF_QUIESCING);
|
||||||
: jmsContext.createBrowser(queue, messageSelector)) {
|
|
||||||
|
|
||||||
Enumeration<?> enumeration = browser.getEnumeration();
|
MQGetMessageOptions browseOptions = new MQGetMessageOptions();
|
||||||
int count = 0;
|
browseOptions.options = CMQC.MQGMO_BROWSE_FIRST | CMQC.MQGMO_NO_SYNCPOINT | CMQC.MQGMO_FAIL_IF_QUIESCING;
|
||||||
|
|
||||||
while (enumeration.hasMoreElements() && count < maxMessages) {
|
while (messages.size() < maxMessages) {
|
||||||
Message message = (Message) enumeration.nextElement();
|
MQMessage message = new MQMessage();
|
||||||
if (message != null) {
|
try {
|
||||||
ReceivedMessage received = decodeMessage(message, queueName, format);
|
queue.get(message, browseOptions);
|
||||||
messages.add(received);
|
} catch (MQException e) {
|
||||||
count++;
|
if (e.reasonCode == CMQC.MQRC_NO_MSG_AVAILABLE) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReceivedMessage received = decodeMessage(message, queueName, format);
|
||||||
|
if (selector.matches(received.getHeaders())) {
|
||||||
|
messages.add(received);
|
||||||
|
}
|
||||||
|
|
||||||
|
browseOptions.options = CMQC.MQGMO_BROWSE_NEXT | CMQC.MQGMO_NO_SYNCPOINT
|
||||||
|
| CMQC.MQGMO_FAIL_IF_QUIESCING;
|
||||||
}
|
}
|
||||||
|
|
||||||
return messages;
|
return messages;
|
||||||
} catch (JMSException e) {
|
} catch (MQException e) {
|
||||||
throw new MessagingDestinationException("Failed to browse queue: " + queueName, e);
|
throw new MessagingDestinationException("Failed to browse queue: " + queueName, e);
|
||||||
|
} finally {
|
||||||
|
closeQueue(queue, queueName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a JMS message to ReceivedMessage.
|
* Decode an IBM MQ message to ReceivedMessage.
|
||||||
*/
|
*/
|
||||||
private ReceivedMessage decodeMessage(Message jmsMessage, String queueName, MqMessageFormat format) {
|
private ReceivedMessage decodeMessage(MQMessage mqMessage, String queueName, MqMessageFormat format) {
|
||||||
long timestamp;
|
long timestamp = mqMessage.putDateTime != null ? mqMessage.putDateTime.getTimeInMillis()
|
||||||
try {
|
: System.currentTimeMillis();
|
||||||
timestamp = jmsMessage.getJMSTimestamp();
|
|
||||||
} catch (JMSException e) {
|
|
||||||
timestamp = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
if (timestamp == 0) {
|
if (timestamp == 0) {
|
||||||
timestamp = System.currentTimeMillis();
|
timestamp = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, String> headers = new HashMap<>();
|
||||||
|
extractMqHeadersAndProperties(mqMessage, headers, queueName);
|
||||||
|
|
||||||
|
byte[] data = readMessageBody(mqMessage);
|
||||||
String body;
|
String body;
|
||||||
MessageContentType contentType;
|
MessageContentType contentType;
|
||||||
Map<String, String> headers = new HashMap<>();
|
|
||||||
|
|
||||||
// Extract JMS properties as headers
|
switch (format) {
|
||||||
extractJmsProperties(jmsMessage, headers);
|
case XML -> {
|
||||||
|
body = new String(data, charsetFor(mqMessage.characterSet, UTF_8));
|
||||||
if (jmsMessage instanceof TextMessage textMessage) {
|
contentType = MessageContentType.XML;
|
||||||
try {
|
|
||||||
body = textMessage.getText();
|
|
||||||
} catch (JMSException e) {
|
|
||||||
throw new RuntimeException("Failed to read text message body", e);
|
|
||||||
}
|
}
|
||||||
contentType = switch (format) {
|
case JSON -> {
|
||||||
case XML -> MessageContentType.XML;
|
body = new String(data, charsetFor(mqMessage.characterSet, UTF_8));
|
||||||
default -> MessageContentType.JSON;
|
contentType = MessageContentType.JSON;
|
||||||
};
|
|
||||||
} else if (jmsMessage instanceof BytesMessage bytesMessage) {
|
|
||||||
int ccsid;
|
|
||||||
try {
|
|
||||||
ccsid = bytesMessage.getIntProperty("CCSID");
|
|
||||||
} catch (JMSException e) {
|
|
||||||
ccsid = 1208; // default UTF-8
|
|
||||||
}
|
}
|
||||||
body = decodeBytesMessage(bytesMessage, ccsid);
|
case EBCDIC_870 -> {
|
||||||
|
body = new String(data, EBCDIC_870);
|
||||||
|
contentType = MessageContentType.RAW_TEXT;
|
||||||
|
}
|
||||||
|
case UTF8_1208 -> {
|
||||||
|
body = new String(data, UTF_8);
|
||||||
|
contentType = MessageContentType.RAW_TEXT;
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
body = new String(data, UTF_8);
|
||||||
contentType = MessageContentType.RAW_TEXT;
|
contentType = MessageContentType.RAW_TEXT;
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
throw new IllegalArgumentException("Unsupported message type: " + jmsMessage.getJMSType());
|
|
||||||
} catch (JMSException e) {
|
|
||||||
throw new IllegalArgumentException("Unsupported message type", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ReceivedMessage(body, contentType, headers, timestamp, queueName, null);
|
return new ReceivedMessage(body, contentType, headers, timestamp, queueName, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private byte[] readMessageBody(MQMessage message) {
|
||||||
* Decode BytesMessage body based on CCSID.
|
|
||||||
*/
|
|
||||||
private String decodeBytesMessage(BytesMessage bytesMessage, int ccsid) {
|
|
||||||
try {
|
try {
|
||||||
long bodyLength;
|
message.seek(0);
|
||||||
try {
|
int length = message.getMessageLength();
|
||||||
bodyLength = bytesMessage.getBodyLength();
|
byte[] data = new byte[length];
|
||||||
} catch (JMSException e) {
|
message.readFully(data);
|
||||||
throw new RuntimeException("Failed to get message body length", e);
|
return data;
|
||||||
}
|
} catch (EOFException e) {
|
||||||
byte[] data = new byte[(int) bodyLength];
|
throw new RuntimeException("Failed to seek message body", e);
|
||||||
bytesMessage.readBytes(data);
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Failed to read message body", e);
|
||||||
Charset charset = switch (ccsid) {
|
|
||||||
case 870 -> EBCDIC_870;
|
|
||||||
case 1208 -> UTF_8;
|
|
||||||
default -> UTF_8;
|
|
||||||
};
|
|
||||||
|
|
||||||
return new String(data, charset);
|
|
||||||
} catch (JMSException e) {
|
|
||||||
throw new RuntimeException("Failed to read BytesMessage body", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract JMS properties as headers.
|
* Extract MQ headers and message properties as headers.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
private void extractMqHeadersAndProperties(MQMessage message, Map<String, String> headers, String queueName) {
|
||||||
private void extractJmsProperties(Message message, Map<String, String> headers) {
|
headers.put("JMSMessageID", toJmsId(message.messageId));
|
||||||
|
headers.put("JMSCorrelationID", toJmsId(message.correlationId));
|
||||||
|
headers.put("JMSType", getStringProperty(message, ImqRequest.PROP_JMS_TYPE, ""));
|
||||||
|
headers.put("JMSDestination", queueName);
|
||||||
|
headers.put("JMSDeliveryMode", String.valueOf(message.persistence));
|
||||||
|
headers.put("JMSPriority", String.valueOf(message.priority));
|
||||||
|
headers.put("JMSTimestamp",
|
||||||
|
message.putDateTime != null ? String.valueOf(message.putDateTime.getTimeInMillis()) : "");
|
||||||
|
headers.put("MQFormat", message.format != null ? message.format.trim() : "");
|
||||||
|
headers.put("MQCharacterSet", String.valueOf(message.characterSet));
|
||||||
|
headers.put("MQEncoding", String.valueOf(message.encoding));
|
||||||
|
headers.put("MQBackoutCount", String.valueOf(message.backoutCount));
|
||||||
|
headers.put("MQReplyToQueue", message.replyToQueueName != null ? message.replyToQueueName.trim() : "");
|
||||||
|
headers.put("MQReplyToQueueManager",
|
||||||
|
message.replyToQueueManagerName != null ? message.replyToQueueManagerName.trim() : "");
|
||||||
|
headers.put("MQUserId", message.userId != null ? message.userId.trim() : "");
|
||||||
|
|
||||||
|
Enumeration<String> propertyNames;
|
||||||
try {
|
try {
|
||||||
// Common JMS headers
|
propertyNames = message.getPropertyNames("%");
|
||||||
headers.put("JMSMessageID", message.getJMSMessageID());
|
} catch (MQException e) {
|
||||||
try {
|
LOG.warn("Failed to extract MQ properties", e);
|
||||||
headers.put("JMSType", message.getJMSType() != null ? message.getJMSType() : "");
|
return;
|
||||||
} catch (JMSException e) {
|
|
||||||
headers.put("JMSType", "");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
headers.put("JMSDestination",
|
|
||||||
message.getJMSDestination() != null ? message.getJMSDestination().toString() : "");
|
|
||||||
} catch (JMSException e) {
|
|
||||||
headers.put("JMSDestination", "");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
headers.put("JMSDeliveryMode", String.valueOf(message.getJMSDeliveryMode()));
|
|
||||||
} catch (JMSException e) {
|
|
||||||
headers.put("JMSDeliveryMode", "");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
headers.put("JMSPriority", String.valueOf(message.getJMSPriority()));
|
|
||||||
} catch (JMSException e) {
|
|
||||||
headers.put("JMSPriority", "");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
headers.put("JMSTimestamp", String.valueOf(message.getJMSTimestamp()));
|
|
||||||
} catch (JMSException e) {
|
|
||||||
headers.put("JMSTimestamp", "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract custom properties
|
|
||||||
Enumeration<String> propertyNames = (Enumeration<String>) message.getPropertyNames();
|
|
||||||
while (propertyNames.hasMoreElements()) {
|
while (propertyNames.hasMoreElements()) {
|
||||||
String propName = propertyNames.nextElement();
|
String propName = propertyNames.nextElement();
|
||||||
|
try {
|
||||||
Object propValue = message.getObjectProperty(propName);
|
Object propValue = message.getObjectProperty(propName);
|
||||||
if (propValue != null) {
|
if (propValue != null) {
|
||||||
headers.put(propName, propValue.toString());
|
headers.put(propName, propValue.toString());
|
||||||
}
|
}
|
||||||
|
} catch (MQException e) {
|
||||||
|
LOG.warn("Failed to extract MQ property: {}", propName, e);
|
||||||
}
|
}
|
||||||
} catch (JMSException e) {
|
|
||||||
LOG.warn("Failed to extract JMS properties", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void applyMessageProperties(MQMessage message, Map<String, String> properties) {
|
||||||
* Get Queue object from queue name.
|
if (properties == null) {
|
||||||
*/
|
return;
|
||||||
private javax.jms.Queue getQueue(String queueName) {
|
}
|
||||||
return jmsContext.createQueue(queueName);
|
|
||||||
|
for (Map.Entry<String, String> entry : properties.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
String value = entry.getValue();
|
||||||
|
try {
|
||||||
|
if (ImqRequest.PROP_JMS_CORRELATION_ID.equals(key)) {
|
||||||
|
message.correlationId = toMqId(value);
|
||||||
|
message.setStringProperty(key, value);
|
||||||
|
} else if (ImqRequest.PROP_JMS_MESSAGE_ID.equals(key)) {
|
||||||
|
message.messageId = toMqId(value);
|
||||||
|
} else if (ImqRequest.PROP_JMS_TYPE.equals(key)) {
|
||||||
|
message.setStringProperty(ImqRequest.PROP_JMS_TYPE, value);
|
||||||
|
} else {
|
||||||
|
message.setStringProperty(key, value);
|
||||||
|
}
|
||||||
|
} catch (MQException e) {
|
||||||
|
LOG.warn("Failed to set property: {}", key, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStringProperty(MQMessage message, String property, String defaultValue) {
|
||||||
|
try {
|
||||||
|
String value = message.getStringProperty(property);
|
||||||
|
return value != null ? value : defaultValue;
|
||||||
|
} catch (MQException e) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MQQueue openQueue(String queueName, int openOptions) throws MQException {
|
||||||
|
ensureConnected();
|
||||||
|
return mqQueueManager.accessQueue(queueName, openOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureConnected() {
|
||||||
|
if (mqQueueManager == null || !mqQueueManager.isConnected()) {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeQueue(MQQueue queue, String queueName) {
|
||||||
|
if (queue == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
queue.close();
|
||||||
|
} catch (MQException e) {
|
||||||
|
LOG.warn("Failed to close IBM MQ queue: {}", queueName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int toWaitInterval(long timeoutMs) {
|
||||||
|
if (timeoutMs <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return timeoutMs > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) timeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Charset charsetFor(int ccsid, Charset defaultCharset) {
|
||||||
|
return switch (ccsid) {
|
||||||
|
case 870 -> EBCDIC_870;
|
||||||
|
case 1208 -> UTF_8;
|
||||||
|
default -> defaultCharset;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] toMqId(String value) {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
return CMQC.MQMI_NONE.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.regionMatches(true, 0, JMS_ID_PREFIX, 0, JMS_ID_PREFIX.length())) {
|
||||||
|
String hex = value.substring(JMS_ID_PREFIX.length());
|
||||||
|
if (hex.length() == CMQC.MQ_MSG_ID_LENGTH * 2 && hex.matches("[0-9A-Fa-f]+")) {
|
||||||
|
return hexToBytes(hex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] id = CMQC.MQMI_NONE.clone();
|
||||||
|
byte[] source = value.getBytes(UTF_8);
|
||||||
|
System.arraycopy(source, 0, id, 0, Math.min(source.length, id.length));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toJmsId(byte[] value) {
|
||||||
|
if (value == null || value.length == 0 || Arrays.equals(value, CMQC.MQMI_NONE)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder(JMS_ID_PREFIX);
|
||||||
|
for (byte b : value) {
|
||||||
|
builder.append(String.format(Locale.ROOT, "%02X", b));
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] hexToBytes(String hex) {
|
||||||
|
byte[] data = new byte[hex.length() / 2];
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
int index = i * 2;
|
||||||
|
data[i] = (byte) Integer.parseInt(hex.substring(index, index + 2), 16);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sleepQuietly(long millis) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(millis);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new MessagingDestinationException("Interrupted while waiting for IBM MQ message", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (jmsContext != null) {
|
if (mqQueueManager != null && mqQueueManager.isConnected()) {
|
||||||
try {
|
try {
|
||||||
jmsContext.close();
|
mqQueueManager.disconnect();
|
||||||
LOG.info("Closed connection to IBM MQ: {}", queueManager);
|
LOG.info("Closed connection to IBM MQ: {}", queueManager);
|
||||||
} catch (Exception e) {
|
} catch (MQException e) {
|
||||||
LOG.error("Failed to close IBM MQ connection", e);
|
LOG.error("Failed to close IBM MQ connection", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -499,4 +616,34 @@ public class IbmMqConnector implements Connector {
|
|||||||
|
|
||||||
return sslContext.getSocketFactory();
|
return sslContext.getSocketFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private record Selector(Map<String, String> expectedValues) {
|
||||||
|
|
||||||
|
private static Selector parse(String selector) {
|
||||||
|
if (selector == null || selector.isBlank()) {
|
||||||
|
return new Selector(Map.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> predicates = new HashMap<>();
|
||||||
|
for (String predicate : selector.split("(?i)\\s+AND\\s+")) {
|
||||||
|
Matcher matcher = SELECTOR_EQUALS_PATTERN.matcher(predicate);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unsupported IBM MQ selector expression. Supported format: property = 'value' joined by AND. Selector: "
|
||||||
|
+ selector);
|
||||||
|
}
|
||||||
|
predicates.put(matcher.group(1), matcher.group(2).replace("''", "'"));
|
||||||
|
}
|
||||||
|
return new Selector(predicates);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matches(Map<String, String> headers) {
|
||||||
|
for (Map.Entry<String, String> expectedValue : expectedValues.entrySet()) {
|
||||||
|
if (!expectedValue.getValue().equals(headers.get(expectedValue.getKey()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
package cz.moneta.test.harness.connectors.messaging;
|
package cz.moneta.test.harness.connectors.messaging;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import cz.moneta.test.harness.connectors.messaging.kafkautils.CustomKafkaAvroDeserializer;
|
||||||
import java.time.Duration;
|
import cz.moneta.test.harness.connectors.messaging.kafkautils.JsonToAvroConverter;
|
||||||
import java.util.ArrayList;
|
import cz.moneta.test.harness.support.messaging.exception.MessagingConnectionException;
|
||||||
import java.util.Collections;
|
import cz.moneta.test.harness.support.messaging.exception.MessagingDestinationException;
|
||||||
import java.util.HashMap;
|
import cz.moneta.test.harness.support.messaging.exception.MessagingSchemaException;
|
||||||
import java.util.List;
|
import cz.moneta.test.harness.support.messaging.exception.MessagingTimeoutException;
|
||||||
import java.util.Map;
|
import cz.moneta.test.harness.support.messaging.kafka.MessageContentType;
|
||||||
import java.util.Properties;
|
import cz.moneta.test.harness.support.messaging.kafka.ReceivedMessage;
|
||||||
import java.util.concurrent.ExecutionException;
|
import io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient;
|
||||||
import java.util.function.Predicate;
|
import io.confluent.kafka.schemaregistry.client.SchemaRegistryClientConfig;
|
||||||
|
import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig;
|
||||||
|
import io.confluent.kafka.serializers.KafkaAvroSerializer;
|
||||||
import org.apache.avro.generic.GenericRecord;
|
import org.apache.avro.generic.GenericRecord;
|
||||||
import org.apache.kafka.clients.consumer.ConsumerConfig;
|
import org.apache.kafka.clients.consumer.ConsumerConfig;
|
||||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||||
@ -23,18 +24,14 @@ import org.apache.kafka.common.TopicPartition;
|
|||||||
import org.apache.kafka.common.header.Headers;
|
import org.apache.kafka.common.header.Headers;
|
||||||
import org.apache.kafka.common.serialization.StringDeserializer;
|
import org.apache.kafka.common.serialization.StringDeserializer;
|
||||||
import org.apache.kafka.common.serialization.StringSerializer;
|
import org.apache.kafka.common.serialization.StringSerializer;
|
||||||
import org.slf4j.Logger;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import cz.moneta.test.harness.messaging.exception.MessagingConnectionException;
|
import java.nio.charset.StandardCharsets;
|
||||||
import cz.moneta.test.harness.messaging.exception.MessagingDestinationException;
|
import java.time.Duration;
|
||||||
import cz.moneta.test.harness.messaging.exception.MessagingSchemaException;
|
import java.util.*;
|
||||||
import cz.moneta.test.harness.messaging.exception.MessagingTimeoutException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import cz.moneta.test.harness.support.messaging.kafka.MessageContentType;
|
import java.util.function.Predicate;
|
||||||
import cz.moneta.test.harness.support.messaging.kafka.ReceivedMessage;
|
|
||||||
import io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient;
|
|
||||||
import io.confluent.kafka.serializers.KafkaAvroDeserializer;
|
|
||||||
import io.confluent.kafka.serializers.KafkaAvroSerializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kafka connector for sending and receiving messages.
|
* Kafka connector for sending and receiving messages.
|
||||||
@ -45,7 +42,7 @@ import io.confluent.kafka.serializers.KafkaAvroSerializer;
|
|||||||
*/
|
*/
|
||||||
public class KafkaConnector implements cz.moneta.test.harness.connectors.Connector {
|
public class KafkaConnector implements cz.moneta.test.harness.connectors.Connector {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(KafkaConnector.class);
|
private static final Logger LOG = LogManager.getLogger(KafkaConnector.class);
|
||||||
|
|
||||||
private final Properties producerConfig;
|
private final Properties producerConfig;
|
||||||
private final Properties consumerConfig;
|
private final Properties consumerConfig;
|
||||||
@ -70,35 +67,45 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
|
|||||||
String schemaRegistryApiKey,
|
String schemaRegistryApiKey,
|
||||||
String schemaRegistryApiSecret) {
|
String schemaRegistryApiSecret) {
|
||||||
this.schemaRegistryUrl = schemaRegistryUrl;
|
this.schemaRegistryUrl = schemaRegistryUrl;
|
||||||
this.schemaRegistryClient = new CachedSchemaRegistryClient(
|
|
||||||
Collections.singletonList(schemaRegistryUrl), 100, new HashMap<>());
|
|
||||||
|
|
||||||
this.producerConfig = createProducerConfig(bootstrapServers, apiKey, apiSecret);
|
HashMap<String, String> schemaRegistryProps = new HashMap<>();
|
||||||
this.consumerConfig = createConsumerConfig(bootstrapServers, schemaRegistryApiKey, schemaRegistryApiSecret);
|
schemaRegistryProps.put(SchemaRegistryClientConfig.BASIC_AUTH_CREDENTIALS_SOURCE, "USER_INFO");
|
||||||
|
schemaRegistryProps.put(SchemaRegistryClientConfig.USER_INFO_CONFIG, schemaRegistryApiKey + ":" + schemaRegistryApiSecret);
|
||||||
|
this.schemaRegistryClient = new CachedSchemaRegistryClient(
|
||||||
|
Collections.singletonList(schemaRegistryUrl), 100, schemaRegistryProps);
|
||||||
|
|
||||||
|
this.producerConfig = createProducerConfig(bootstrapServers, apiKey, apiSecret, schemaRegistryApiKey, schemaRegistryApiSecret);
|
||||||
|
this.consumerConfig = createConsumerConfig(bootstrapServers, apiKey, apiSecret, schemaRegistryApiKey, schemaRegistryApiSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates producer configuration.
|
* Creates producer configuration.
|
||||||
*/
|
*/
|
||||||
private Properties createProducerConfig(String bootstrapServers, String apiKey, String apiSecret) {
|
private Properties createProducerConfig(String bootstrapServers, String apiKey, String apiSecret,
|
||||||
|
String schemaRegistryApiKey, String schemaRegistryApiSecret) {
|
||||||
Properties config = new Properties();
|
Properties config = new Properties();
|
||||||
config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
|
config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
|
||||||
config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||||
config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, KafkaAvroSerializer.class);
|
config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, KafkaAvroSerializer.class);
|
||||||
config.put("schema.registry.url", schemaRegistryUrl);
|
|
||||||
config.put(ProducerConfig.ACKS_CONFIG, "all");
|
config.put(ProducerConfig.ACKS_CONFIG, "all");
|
||||||
config.put(ProducerConfig.LINGER_MS_CONFIG, 1);
|
config.put(ProducerConfig.LINGER_MS_CONFIG, 1);
|
||||||
config.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
|
config.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
|
||||||
|
|
||||||
// SASL/PLAIN authentication
|
config.put(AbstractKafkaSchemaSerDeConfig.AUTO_REGISTER_SCHEMAS, false);
|
||||||
// config.put("security.protocol", "SASL_SSL");
|
config.put(AbstractKafkaSchemaSerDeConfig.USE_LATEST_VERSION, true);
|
||||||
// config.put("sasl.mechanism", "PLAIN");
|
config.put(AbstractKafkaSchemaSerDeConfig.SCHEMA_REGISTRY_URL_CONFIG, schemaRegistryUrl);
|
||||||
// config.put("sasl.jaas.config",
|
config.put(SchemaRegistryClientConfig.BASIC_AUTH_CREDENTIALS_SOURCE, "USER_INFO");
|
||||||
// "org.apache.kafka.common.security.plain.PlainLoginModule required " +
|
config.put(SchemaRegistryClientConfig.USER_INFO_CONFIG, schemaRegistryApiKey + ":" + schemaRegistryApiSecret);
|
||||||
// "username=\"" + apiKey + "\" password=\"" + apiSecret + "\";");
|
|
||||||
|
|
||||||
// SSL configuration
|
// SASL/PLAIN authentication
|
||||||
// config.put("ssl.endpoint.identification.algorithm", "https");
|
config.put("security.protocol", "SASL_SSL");
|
||||||
|
config.put("sasl.mechanism", "PLAIN");
|
||||||
|
config.put("sasl.jaas.config",
|
||||||
|
"org.apache.kafka.common.security.plain.PlainLoginModule required " +
|
||||||
|
"username=\"" + apiKey + "\" password=\"" + apiSecret + "\";");
|
||||||
|
|
||||||
|
// SSL configuration
|
||||||
|
config.put("ssl.endpoint.identification.algorithm", "https");
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@ -106,14 +113,16 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
|
|||||||
/**
|
/**
|
||||||
* Creates consumer configuration.
|
* Creates consumer configuration.
|
||||||
*/
|
*/
|
||||||
private Properties createConsumerConfig(String bootstrapServers, String apiKey, String apiSecret) {
|
private Properties createConsumerConfig(String bootstrapServers, String apiKey, String apiSecret,
|
||||||
|
String schemaRegistryApiKey, String schemaRegistryApiSecret) {
|
||||||
Properties config = new Properties();
|
Properties config = new Properties();
|
||||||
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
|
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
|
||||||
config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
|
config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
|
||||||
config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, KafkaAvroDeserializer.class);
|
config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, CustomKafkaAvroDeserializer.class);
|
||||||
config.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "none");
|
config.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "none");
|
||||||
config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
|
config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
|
||||||
|
|
||||||
|
|
||||||
// SASL/PLAIN authentication
|
// SASL/PLAIN authentication
|
||||||
config.put("security.protocol", "SASL_SSL");
|
config.put("security.protocol", "SASL_SSL");
|
||||||
config.put("sasl.mechanism", "PLAIN");
|
config.put("sasl.mechanism", "PLAIN");
|
||||||
@ -122,7 +131,12 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
|
|||||||
"username=\"" + apiKey + "\" password=\"" + apiSecret + "\";");
|
"username=\"" + apiKey + "\" password=\"" + apiSecret + "\";");
|
||||||
|
|
||||||
// Schema Registry for deserialization
|
// Schema Registry for deserialization
|
||||||
config.put("schema.registry.url", schemaRegistryUrl);
|
|
||||||
|
config.put(AbstractKafkaSchemaSerDeConfig.SCHEMA_REGISTRY_URL_CONFIG, schemaRegistryUrl);
|
||||||
|
config.put(AbstractKafkaSchemaSerDeConfig.AUTO_REGISTER_SCHEMAS, false);
|
||||||
|
config.put(AbstractKafkaSchemaSerDeConfig.USE_LATEST_VERSION, true);
|
||||||
|
config.put(SchemaRegistryClientConfig.BASIC_AUTH_CREDENTIALS_SOURCE, "USER_INFO");
|
||||||
|
config.put(SchemaRegistryClientConfig.USER_INFO_CONFIG, schemaRegistryApiKey + ":" + schemaRegistryApiSecret);
|
||||||
config.put("specific.avro.reader", false);
|
config.put("specific.avro.reader", false);
|
||||||
|
|
||||||
// SSL configuration
|
// SSL configuration
|
||||||
@ -179,7 +193,7 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
|
|||||||
*/
|
*/
|
||||||
public List<ReceivedMessage> receive(String topic,
|
public List<ReceivedMessage> receive(String topic,
|
||||||
Predicate<ReceivedMessage> filter,
|
Predicate<ReceivedMessage> filter,
|
||||||
Duration timeout) {
|
Duration timeout, boolean startFromBeginning) {
|
||||||
KafkaConsumer<String, GenericRecord> consumer = null;
|
KafkaConsumer<String, GenericRecord> consumer = null;
|
||||||
try {
|
try {
|
||||||
consumer = new KafkaConsumer<>(consumerConfig);
|
consumer = new KafkaConsumer<>(consumerConfig);
|
||||||
@ -191,10 +205,12 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
|
|||||||
"Topic '" + topic + "' does not exist or has no partitions");
|
"Topic '" + topic + "' does not exist or has no partitions");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign partitions and seek to end
|
|
||||||
consumer.assign(partitions);
|
consumer.assign(partitions);
|
||||||
// consumer.seekToBeginning(partitions);
|
if (startFromBeginning) {
|
||||||
consumer.seekToBeginning(partitions);
|
consumer.seekToBeginning(partitions);
|
||||||
|
} else {
|
||||||
|
consumer.seekToEnd(partitions);
|
||||||
|
}
|
||||||
|
|
||||||
// Poll loop with exponential backoff
|
// Poll loop with exponential backoff
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
@ -310,8 +326,12 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
|
|||||||
*/
|
*/
|
||||||
private ReceivedMessage convertToReceivedMessage(ConsumerRecord<String, GenericRecord> record, String topic) {
|
private ReceivedMessage convertToReceivedMessage(ConsumerRecord<String, GenericRecord> record, String topic) {
|
||||||
try {
|
try {
|
||||||
String jsonBody = avroToJson(record.value());
|
String jsonBody;
|
||||||
|
if (null != record.value()) {
|
||||||
|
jsonBody = avroToJson(record.value());
|
||||||
|
} else {
|
||||||
|
jsonBody = "";
|
||||||
|
}
|
||||||
Map<String, String> headers = new HashMap<>();
|
Map<String, String> headers = new HashMap<>();
|
||||||
Headers kafkaHeaders = record.headers();
|
Headers kafkaHeaders = record.headers();
|
||||||
for (org.apache.kafka.common.header.Header header : kafkaHeaders) {
|
for (org.apache.kafka.common.header.Header header : kafkaHeaders) {
|
||||||
@ -340,6 +360,7 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
|
|||||||
*/
|
*/
|
||||||
private String avroToJson(GenericRecord record) {
|
private String avroToJson(GenericRecord record) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
return record.toString();
|
return record.toString();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Failed to convert Avro to JSON: " + e.getMessage(), e);
|
throw new RuntimeException("Failed to convert Avro to JSON: " + e.getMessage(), e);
|
||||||
|
|||||||
@ -0,0 +1,54 @@
|
|||||||
|
package cz.moneta.test.harness.connectors.messaging.kafkautils;
|
||||||
|
|
||||||
|
import cz.moneta.test.harness.connectors.messaging.KafkaConnector;
|
||||||
|
import io.confluent.kafka.serializers.KafkaAvroDeserializer;
|
||||||
|
import org.apache.avro.Schema;
|
||||||
|
import org.apache.kafka.common.errors.SerializationException;
|
||||||
|
import org.apache.kafka.common.header.Headers;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
public class CustomKafkaAvroDeserializer extends KafkaAvroDeserializer {
|
||||||
|
|
||||||
|
private static final Logger LOG = LogManager.getLogger(KafkaConnector.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object deserialize(String topic, byte[] bytes) {
|
||||||
|
try {
|
||||||
|
return super.deserialize(topic, bytes);
|
||||||
|
} catch (SerializationException e) {
|
||||||
|
LOG.error("Message deserialization by avro schema failed", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object deserialize(String topic, Headers headers, byte[] bytes) {
|
||||||
|
try {
|
||||||
|
return super.deserialize(topic, headers, bytes);
|
||||||
|
} catch (SerializationException e) {
|
||||||
|
LOG.error("Message deserialization by avro schema failed", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object deserialize(String topic, byte[] bytes, Schema readerSchema) {
|
||||||
|
try {
|
||||||
|
return super.deserialize(topic, bytes, readerSchema);
|
||||||
|
} catch (SerializationException e) {
|
||||||
|
LOG.error("Message deserialization by avro schema failed", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object deserialize(String topic, Headers headers, byte[] bytes, Schema readerSchema) {
|
||||||
|
try {
|
||||||
|
return super.deserialize(topic, headers, bytes, readerSchema);
|
||||||
|
} catch (SerializationException e) {
|
||||||
|
LOG.error("Message deserialization by avro schema failed", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,22 +1,16 @@
|
|||||||
package cz.moneta.test.harness.connectors.messaging;
|
package cz.moneta.test.harness.connectors.messaging.kafkautils;
|
||||||
|
|
||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
import org.apache.avro.Schema;
|
import org.apache.avro.Schema;
|
||||||
import org.apache.avro.generic.GenericData;
|
import org.apache.avro.generic.GenericData;
|
||||||
import org.apache.avro.generic.GenericDatumReader;
|
|
||||||
import org.apache.avro.generic.GenericDatumWriter;
|
|
||||||
import org.apache.avro.generic.GenericRecord;
|
import org.apache.avro.generic.GenericRecord;
|
||||||
import org.apache.avro.io.DatumReader;
|
|
||||||
import org.apache.avro.io.DatumWriter;
|
|
||||||
import org.apache.avro.io.Decoder;
|
|
||||||
import org.apache.avro.io.JsonDecoder;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class JsonToAvroConverter {
|
public class JsonToAvroConverter {
|
||||||
|
|
||||||
protected static GenericRecord processJson(String json, Schema schema) throws IllegalArgumentException, JsonSchemaException {
|
public static GenericRecord processJson(String json, Schema schema) throws IllegalArgumentException, JsonSchemaException {
|
||||||
GenericRecord result = (GenericRecord) jsonElementToAvro(JsonParser.parseString(json), schema);
|
GenericRecord result = (GenericRecord) jsonElementToAvro(JsonParser.parseString(json), schema);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -86,7 +80,7 @@ public class JsonToAvroConverter {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object jsonPrimitiveToAvro(JsonPrimitive primitive, Schema schema){
|
private static Object jsonPrimitiveToAvro(JsonPrimitive primitive, Schema schema) {
|
||||||
switch (schema.getType()) {
|
switch (schema.getType()) {
|
||||||
case NULL:
|
case NULL:
|
||||||
return null;
|
return null;
|
||||||
@ -7,6 +7,7 @@ public final class HarnessConfigConstants {
|
|||||||
public static final String VAULT_USERNAME_CONFIG = "vault.username";
|
public static final String VAULT_USERNAME_CONFIG = "vault.username";
|
||||||
public static final String VAULT_PASSWORD_CONFIG = "vault.password";
|
public static final String VAULT_PASSWORD_CONFIG = "vault.password";
|
||||||
public static final String VAULT_URL_CONFIG = "vault.url";
|
public static final String VAULT_URL_CONFIG = "vault.url";
|
||||||
|
public static final String VAULT_KAFKA_KEYS_CONFIG = "vault.kafka.secrets.path";
|
||||||
public static final String VAULT_WSO2_KEYS_PATH = "vault.client.secrets.path";
|
public static final String VAULT_WSO2_KEYS_PATH = "vault.client.secrets.path";
|
||||||
public static final String VAULT_CAGW_KEYS_PATH = "vault.cagw.client.secrets.path";
|
public static final String VAULT_CAGW_KEYS_PATH = "vault.cagw.client.secrets.path";
|
||||||
public static final String ENVIRONMENT_TYPE = "environment.type";
|
public static final String ENVIRONMENT_TYPE = "environment.type";
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
package cz.moneta.test.harness.endpoints.bankid;
|
||||||
|
|
||||||
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
|
import cz.moneta.test.harness.endpoints.WebEndpoint;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
|
||||||
|
public class BankIdSoniaDemoWebEndpoint extends WebEndpoint {
|
||||||
|
|
||||||
|
private static final String ENDPOINT_URL_IDENTIFIER = "endpoints.bankid.demoapp.url";
|
||||||
|
|
||||||
|
public BankIdSoniaDemoWebEndpoint(StoreAccessor storeAccessor) {
|
||||||
|
super(ENDPOINT_URL_IDENTIFIER, By::xpath, storeAccessor);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
package cz.moneta.test.harness.endpoints.cds;
|
||||||
|
|
||||||
|
import cz.moneta.test.harness.connectors.database.OracleConnector;
|
||||||
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
|
import cz.moneta.test.harness.endpoints.Endpoint;
|
||||||
|
import cz.moneta.test.harness.support.auth.AuthSupport;
|
||||||
|
import cz.moneta.test.harness.support.auth.Credentials;
|
||||||
|
import org.jooq.Record;
|
||||||
|
import org.jooq.Result;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class CdsEndpoint implements Endpoint {
|
||||||
|
|
||||||
|
private final StoreAccessor store;
|
||||||
|
private final ThreadLocal<OracleConnector> connector = ThreadLocal.withInitial(this::initConnector);
|
||||||
|
|
||||||
|
public CdsEndpoint(StoreAccessor store) {
|
||||||
|
this.store = store;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Record> executeSql(String sql) {
|
||||||
|
return connector.get().executeSql(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAccess() {
|
||||||
|
return AuthSupport.hasCredentials("cds", store);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OracleConnector initConnector() {
|
||||||
|
String endpointName = "endpoints.cds.url";
|
||||||
|
Credentials credentials = AuthSupport.getCredentials("cds", store);
|
||||||
|
return Optional.ofNullable(store.getConfig(endpointName))
|
||||||
|
.map(url -> new OracleConnector(url, credentials.getUsername(), credentials.getPassword()))
|
||||||
|
.orElseThrow(() -> new IllegalStateException("You need to configure " + endpointName + " to work with CDS"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,13 +7,12 @@ import java.util.Optional;
|
|||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import cz.moneta.test.harness.connectors.VaultConnector;
|
|
||||||
import cz.moneta.test.harness.connectors.messaging.IbmMqConnector;
|
import cz.moneta.test.harness.connectors.messaging.IbmMqConnector;
|
||||||
import cz.moneta.test.harness.constants.HarnessConfigConstants;
|
|
||||||
import cz.moneta.test.harness.context.StoreAccessor;
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
import cz.moneta.test.harness.endpoints.Endpoint;
|
import cz.moneta.test.harness.endpoints.Endpoint;
|
||||||
import cz.moneta.test.harness.messaging.MqMessageFormat;
|
import cz.moneta.test.harness.support.messaging.MqMessageFormat;
|
||||||
import cz.moneta.test.harness.messaging.ReceivedMessage;
|
import cz.moneta.test.harness.support.messaging.ReceivedMessage;
|
||||||
|
import cz.moneta.test.harness.support.auth.AuthSupport;
|
||||||
import cz.moneta.test.harness.support.auth.Credentials;
|
import cz.moneta.test.harness.support.auth.Credentials;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,8 +37,7 @@ public class ImqFirstVisionEndpoint implements Endpoint {
|
|||||||
private static final String SSL_CIPHER_SUITE_KEY = "endpoints.imq-first-vision.ssl-cipher-suite";
|
private static final String SSL_CIPHER_SUITE_KEY = "endpoints.imq-first-vision.ssl-cipher-suite";
|
||||||
private static final String VAULT_PATH_KEY = "vault.imq-first-vision.secrets.path";
|
private static final String VAULT_PATH_KEY = "vault.imq-first-vision.secrets.path";
|
||||||
private static final String VAULT_KEYSTORE_PASSWORD_KEY = "keystorePassword";
|
private static final String VAULT_KEYSTORE_PASSWORD_KEY = "keystorePassword";
|
||||||
|
private static final String KEYSTORE_PATH = "keystores/imq.jks";
|
||||||
private static final String KEYSTORE_PATH = "keystores/imq-keystore.jks";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor that reads configuration from StoreAccessor.
|
* Constructor that reads configuration from StoreAccessor.
|
||||||
@ -79,25 +77,10 @@ public class ImqFirstVisionEndpoint implements Endpoint {
|
|||||||
*/
|
*/
|
||||||
private void loadCredentialsFromVault() {
|
private void loadCredentialsFromVault() {
|
||||||
try {
|
try {
|
||||||
// Get vault URL from configuration
|
Credentials credentials = AuthSupport.getCredentials("imq-first-vision", store);
|
||||||
String vaultPath = getConfig(VAULT_PATH_KEY);
|
this.username = credentials.getUsername();
|
||||||
String vaultUrl = getConfig(HarnessConfigConstants.VAULT_URL_CONFIG);
|
this.password = credentials.getPassword();
|
||||||
String vaultUser = getConfig(HarnessConfigConstants.VAULT_USERNAME_CONFIG);
|
this.keystorePassword = AuthSupport.getClientSecret(VAULT_KEYSTORE_PASSWORD_KEY, store, VAULT_PATH_KEY);
|
||||||
String vaultPassword = getConfig(HarnessConfigConstants.VAULT_PASSWORD_CONFIG);
|
|
||||||
|
|
||||||
VaultConnector vaultConnector = new VaultConnector(vaultUrl, vaultUser, vaultPassword);
|
|
||||||
|
|
||||||
Optional<Credentials> credentials = vaultConnector.getUsernameAndPassword(vaultPath);
|
|
||||||
|
|
||||||
if (credentials.isPresent()) {
|
|
||||||
this.username = credentials.get().getUsername();
|
|
||||||
this.password = credentials.get().getPassword();
|
|
||||||
this.keystorePassword = vaultConnector.getValue(vaultPath, VAULT_KEYSTORE_PASSWORD_KEY)
|
|
||||||
.map(Object::toString).orElse(null);
|
|
||||||
LOG.info("Successfully loaded credentials from Vault for path: {}", vaultPath);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Credentials not found in Vault at path: " + vaultPath);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalStateException("Failed to load credentials from Vault", e);
|
throw new IllegalStateException("Failed to load credentials from Vault", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,16 @@
|
|||||||
package cz.moneta.test.harness.endpoints.kafka;
|
package cz.moneta.test.harness.endpoints.kafka;
|
||||||
|
|
||||||
import cz.moneta.test.harness.connectors.messaging.KafkaConnector;
|
import cz.moneta.test.harness.connectors.messaging.KafkaConnector;
|
||||||
import cz.moneta.test.harness.context.BaseStoreAccessor;
|
|
||||||
import cz.moneta.test.harness.context.StoreAccessor;
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
import cz.moneta.test.harness.endpoints.Endpoint;
|
import cz.moneta.test.harness.endpoints.Endpoint;
|
||||||
import cz.moneta.test.harness.messaging.exception.MessagingConnectionException;
|
import cz.moneta.test.harness.support.auth.AuthSupport;
|
||||||
import cz.moneta.test.harness.support.messaging.kafka.ReceivedMessage;
|
import cz.moneta.test.harness.support.messaging.kafka.ReceivedMessage;
|
||||||
import com.bettercloud.vault.Vault;
|
|
||||||
import com.bettercloud.vault.VaultConfig;
|
|
||||||
import com.bettercloud.vault.VaultException;
|
|
||||||
import com.bettercloud.vault.response.LogicalResponse;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
import static cz.moneta.test.harness.constants.HarnessConfigConstants.VAULT_KAFKA_KEYS_CONFIG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kafka endpoint that provides high-level API for Kafka messaging.
|
* Kafka endpoint that provides high-level API for Kafka messaging.
|
||||||
@ -55,16 +50,10 @@ public class KafkaEndpoint implements Endpoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve credentials from Vault
|
// Retrieve credentials from Vault
|
||||||
String vaultPath = store.getConfig("vault.kafka.secrets.path");
|
String apiKey = getVaultValue("apiKey");
|
||||||
if (vaultPath == null) {
|
String apiSecret = getVaultValue("apiSecret");
|
||||||
throw new IllegalStateException(
|
String schemaRegistryApiKey = getVaultValue("schemaRegistryApiKey");
|
||||||
"You need to configure vault.kafka.secrets.path");
|
String schemaRegistryApiSecret = getVaultValue("schemaRegistryApiSecret");
|
||||||
}
|
|
||||||
//
|
|
||||||
String apiKey = getVaultValue(vaultPath, "apiKey");
|
|
||||||
String apiSecret = getVaultValue(vaultPath, "apiSecret");
|
|
||||||
String schemaRegistryApiKey = getVaultValue(vaultPath, "schemaRegistryApiKey");
|
|
||||||
String schemaRegistryApiSecret = getVaultValue(vaultPath, "schemaRegistryApiSecret");
|
|
||||||
|
|
||||||
// Create connector
|
// Create connector
|
||||||
this.connector = new KafkaConnector(
|
this.connector = new KafkaConnector(
|
||||||
@ -99,16 +88,16 @@ public class KafkaEndpoint implements Endpoint {
|
|||||||
*/
|
*/
|
||||||
public List<ReceivedMessage> receive(String topic,
|
public List<ReceivedMessage> receive(String topic,
|
||||||
java.util.function.Predicate<ReceivedMessage> filter,
|
java.util.function.Predicate<ReceivedMessage> filter,
|
||||||
Duration timeout) {
|
Duration timeout, boolean startFromBeginning) {
|
||||||
return connector.receive(topic, filter, timeout);
|
return connector.receive(topic, filter, timeout, startFromBeginning);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receives a message with default timeout (30 seconds).
|
* Receives a message with default timeout (30 seconds).
|
||||||
*/
|
*/
|
||||||
public List<ReceivedMessage> receive(String topic,
|
public List<ReceivedMessage> receive(String topic,
|
||||||
java.util.function.Predicate<ReceivedMessage> filter) {
|
java.util.function.Predicate<ReceivedMessage> filter, boolean startFromBeginning) {
|
||||||
return receive(topic, filter, Duration.ofSeconds(30));
|
return receive(topic, filter, Duration.ofSeconds(30), startFromBeginning);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,8 +107,8 @@ public class KafkaEndpoint implements Endpoint {
|
|||||||
* @param timeout Maximum time to wait
|
* @param timeout Maximum time to wait
|
||||||
* @return First message
|
* @return First message
|
||||||
*/
|
*/
|
||||||
public List<ReceivedMessage> receive(String topic, Duration timeout) {
|
public List<ReceivedMessage> receive(String topic, Duration timeout, boolean startFromBeginning) {
|
||||||
return receive(topic, msg -> true, timeout);
|
return receive(topic, msg -> true, timeout, startFromBeginning);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -164,36 +153,7 @@ public class KafkaEndpoint implements Endpoint {
|
|||||||
/**
|
/**
|
||||||
* Retrieves a value from Vault.
|
* Retrieves a value from Vault.
|
||||||
*/
|
*/
|
||||||
private String getVaultValue(String path, String key) {
|
private String getVaultValue(String key) {
|
||||||
try {
|
return AuthSupport.getClientSecret(key, store, VAULT_KAFKA_KEYS_CONFIG);
|
||||||
VaultConfig vaultConfig = new VaultConfig()
|
|
||||||
.address(store.getConfig("vault.address", "http://localhost:8200"))
|
|
||||||
.token(store.getConfig("vault.token"))
|
|
||||||
.build();
|
|
||||||
Vault vault = new Vault(vaultConfig, 2);
|
|
||||||
|
|
||||||
LogicalResponse response = vault.logical().read(path);
|
|
||||||
if (response == null) {
|
|
||||||
throw new MessagingConnectionException(
|
|
||||||
"Failed to read from Vault path: " + path);
|
|
||||||
}
|
|
||||||
Map<String, String> data = response.getData();
|
|
||||||
if (data == null) {
|
|
||||||
throw new MessagingConnectionException(
|
|
||||||
"No data found in Vault path: " + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
String value = data.get(key);
|
|
||||||
if (value == null) {
|
|
||||||
throw new MessagingConnectionException(
|
|
||||||
"Credential '" + key + "' not found in Vault path: " + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
|
|
||||||
} catch (VaultException e) {
|
|
||||||
throw new MessagingConnectionException(
|
|
||||||
"Failed to retrieve credential '" + key + "' from Vault at " + path, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,83 +0,0 @@
|
|||||||
package cz.moneta.test.harness.messaging;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.node.NullNode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper for extracted JSON path values.
|
|
||||||
* Provides fluent methods for value extraction and conversion.
|
|
||||||
*/
|
|
||||||
public class JsonPathValue {
|
|
||||||
|
|
||||||
private final JsonNode node;
|
|
||||||
private final String rawValue;
|
|
||||||
|
|
||||||
public JsonPathValue(JsonNode node) {
|
|
||||||
this.node = node;
|
|
||||||
this.rawValue = node != null ? node.asText() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonPathValue(String rawValue) {
|
|
||||||
this.node = null;
|
|
||||||
this.rawValue = rawValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value as a string.
|
|
||||||
*/
|
|
||||||
public String asText() {
|
|
||||||
if (node != null && !(node instanceof NullNode)) {
|
|
||||||
return node.asText();
|
|
||||||
}
|
|
||||||
return rawValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value as an integer.
|
|
||||||
*/
|
|
||||||
public int asInt() {
|
|
||||||
if (node != null && !(node instanceof NullNode)) {
|
|
||||||
return node.asInt();
|
|
||||||
}
|
|
||||||
return Integer.parseInt(rawValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value as a long.
|
|
||||||
*/
|
|
||||||
public long asLong() {
|
|
||||||
if (node != null && !(node instanceof NullNode)) {
|
|
||||||
return node.asLong();
|
|
||||||
}
|
|
||||||
return Long.parseLong(rawValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value as a boolean.
|
|
||||||
*/
|
|
||||||
public boolean asBoolean() {
|
|
||||||
if (node != null && !(node instanceof NullNode)) {
|
|
||||||
return node.asBoolean();
|
|
||||||
}
|
|
||||||
return Boolean.parseBoolean(rawValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the value is null or missing.
|
|
||||||
*/
|
|
||||||
public boolean isNull() {
|
|
||||||
return node == null || node instanceof NullNode || rawValue == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the underlying JsonNode.
|
|
||||||
*/
|
|
||||||
public JsonNode getNode() {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return asText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package cz.moneta.test.harness.messaging;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Content type of a received message.
|
|
||||||
*/
|
|
||||||
public enum MessageContentType {
|
|
||||||
/**
|
|
||||||
* JSON content - body is a JSON string.
|
|
||||||
*/
|
|
||||||
JSON,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XML content - body is an XML string.
|
|
||||||
*/
|
|
||||||
XML,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Raw text content - body is plain text (e.g., EBCDIC decoded, UTF-8).
|
|
||||||
*/
|
|
||||||
RAW_TEXT
|
|
||||||
}
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
package cz.moneta.test.harness.messaging;
|
|
||||||
|
|
||||||
import org.assertj.core.api.AbstractObjectAssert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Response interface for received messages.
|
|
||||||
* Provides assertion methods for verifying message content.
|
|
||||||
* Shared interface for both Kafka and IBM MQ message responses.
|
|
||||||
*/
|
|
||||||
public interface MessageResponse {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assert that a field in the message body has the expected value.
|
|
||||||
* For JSON: uses JSON path (dot/bracket notation).
|
|
||||||
* For XML: uses XPath expression.
|
|
||||||
*
|
|
||||||
* @param path JSON path or XPath expression
|
|
||||||
* @param value expected value as string
|
|
||||||
* @return this instance for fluent assertions
|
|
||||||
* @throws AssertionError if assertion fails
|
|
||||||
*/
|
|
||||||
MessageResponse andAssertFieldValue(String path, String value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assert that a field exists in the message body.
|
|
||||||
*
|
|
||||||
* @param path JSON path or XPath expression
|
|
||||||
* @return this instance for fluent assertions
|
|
||||||
* @throws AssertionError if assertion fails
|
|
||||||
*/
|
|
||||||
MessageResponse andAssertPresent(String path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assert that a field does not exist in the message body.
|
|
||||||
*
|
|
||||||
* @param path JSON path or XPath expression
|
|
||||||
* @return this instance for fluent assertions
|
|
||||||
* @throws AssertionError if assertion fails
|
|
||||||
*/
|
|
||||||
MessageResponse andAssertNotPresent(String path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assert that a header (Kafka header or JMS property) has the expected value.
|
|
||||||
*
|
|
||||||
* @param headerName name of the header/property
|
|
||||||
* @param value expected value
|
|
||||||
* @return this instance for fluent assertions
|
|
||||||
* @throws AssertionError if assertion fails
|
|
||||||
*/
|
|
||||||
MessageResponse andAssertHeaderValue(String headerName, String value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assert that the message body contains a substring.
|
|
||||||
* Primarily used for EBCDIC/UTF-8 raw text assertions.
|
|
||||||
*
|
|
||||||
* @param substring expected substring
|
|
||||||
* @return this instance for fluent assertions
|
|
||||||
* @throws AssertionError if assertion fails
|
|
||||||
*/
|
|
||||||
MessageResponse andAssertBodyContains(String substring);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get AssertJ fluent assertion for complex object assertions.
|
|
||||||
*
|
|
||||||
* @return AssertJ AbstractObjectAssert for fluent assertions
|
|
||||||
*/
|
|
||||||
AbstractObjectAssert<?, ?> andAssertWithAssertJ();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract a value from the message body.
|
|
||||||
* For JSON: uses JSON path (dot/bracket notation).
|
|
||||||
* For XML: uses XPath expression.
|
|
||||||
*
|
|
||||||
* @param path JSON path or XPath expression
|
|
||||||
* @return JsonPathValue wrapper for the extracted value
|
|
||||||
*/
|
|
||||||
JsonPathValue extract(String path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deserialize the message body to a Java object.
|
|
||||||
* For JSON: uses Jackson ObjectMapper.
|
|
||||||
* For XML: uses JAXB or Jackson XmlMapper.
|
|
||||||
*
|
|
||||||
* @param type target type
|
|
||||||
* @param <T> target type
|
|
||||||
* @return deserialized object
|
|
||||||
*/
|
|
||||||
<T> T mapTo(Class<T> type);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the raw message body.
|
|
||||||
*
|
|
||||||
* @return message body as string
|
|
||||||
*/
|
|
||||||
String getBody();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a header value (Kafka header or JMS property).
|
|
||||||
*
|
|
||||||
* @param name header/property name
|
|
||||||
* @return header value or null if not present
|
|
||||||
*/
|
|
||||||
String getHeader(String name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the underlying received message.
|
|
||||||
*
|
|
||||||
* @return ReceivedMessage instance
|
|
||||||
*/
|
|
||||||
ReceivedMessage getMessage();
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package cz.moneta.test.harness.messaging;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Message format for IBM MQ.
|
|
||||||
* Defines how messages are encoded and transmitted.
|
|
||||||
*/
|
|
||||||
public enum MqMessageFormat {
|
|
||||||
/**
|
|
||||||
* JSON format - JMS TextMessage with plain JSON string.
|
|
||||||
* Default format for IBM MQ.
|
|
||||||
*/
|
|
||||||
JSON,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XML format - JMS TextMessage with XML string.
|
|
||||||
* XML is decoded and can be queried using XPath.
|
|
||||||
*/
|
|
||||||
XML,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EBCDIC format - JMS BytesMessage with EBCDIC IBM-870 encoding.
|
|
||||||
* Used for mainframe systems (Czech/Slovak characters).
|
|
||||||
*/
|
|
||||||
EBCDIC_870,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UTF-8 format - JMS BytesMessage with UTF-8 (CCSID 1208) encoding.
|
|
||||||
* Used for binary data with explicit UTF-8 encoding.
|
|
||||||
*/
|
|
||||||
UTF8_1208
|
|
||||||
}
|
|
||||||
@ -1,386 +0,0 @@
|
|||||||
package cz.moneta.test.harness.messaging;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.xpath.XPath;
|
|
||||||
import javax.xml.xpath.XPathConstants;
|
|
||||||
import javax.xml.xpath.XPathFactory;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a received message from a messaging system.
|
|
||||||
* Body is always normalized to a String regardless of source and wire format.
|
|
||||||
* <p>
|
|
||||||
* For Kafka: Avro GenericRecord is automatically converted to JSON.
|
|
||||||
* For IBM MQ (JSON): JSON string from JMS TextMessage.
|
|
||||||
* For IBM MQ (XML): XML string from JMS TextMessage.
|
|
||||||
* For IBM MQ (EBCDIC): byte[] from JMS BytesMessage decoded from IBM-870.
|
|
||||||
*/
|
|
||||||
public class ReceivedMessage {
|
|
||||||
|
|
||||||
private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
|
|
||||||
private static final Pattern JSON_PATH_PATTERN = Pattern.compile("^([\\w.]+)\\[([\\d]+)\\](.*)$");
|
|
||||||
|
|
||||||
private final String body;
|
|
||||||
private final MessageContentType contentType;
|
|
||||||
private final Map<String, String> headers;
|
|
||||||
private final long timestamp;
|
|
||||||
private final String source;
|
|
||||||
private final String key;
|
|
||||||
|
|
||||||
public ReceivedMessage(String body, MessageContentType contentType, Map<String, String> headers,
|
|
||||||
long timestamp, String source, String key) {
|
|
||||||
this.body = body;
|
|
||||||
this.contentType = contentType;
|
|
||||||
this.headers = headers != null ? Collections.unmodifiableMap(new HashMap<>(headers)) : new HashMap<>();
|
|
||||||
this.timestamp = timestamp;
|
|
||||||
this.source = source;
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract a JSON value using JSON path (dot/bracket notation).
|
|
||||||
* Supports paths like "items[0].sku" or "nested.field".
|
|
||||||
*
|
|
||||||
* @param path JSON path
|
|
||||||
* @return JsonNode for the extracted value
|
|
||||||
*/
|
|
||||||
public JsonNode extractJson(String path) {
|
|
||||||
if (body == null || StringUtils.isEmpty(path)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
JsonNode root = JSON_MAPPER.readTree(body);
|
|
||||||
return evaluateJsonPath(root, path);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Failed to extract JSON path: " + path, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract a value using XPath (for XML messages).
|
|
||||||
*
|
|
||||||
* @param xpathExpression XPath expression
|
|
||||||
* @return extracted value as string
|
|
||||||
*/
|
|
||||||
public String extractXml(String xpathExpression) {
|
|
||||||
if (body == null || StringUtils.isEmpty(xpathExpression)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
|
||||||
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
|
||||||
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
|
||||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
|
||||||
javax.xml.parsers.DocumentBuilder finalBuilder = builder;
|
|
||||||
|
|
||||||
var document = finalBuilder.parse(new java.io.ByteArrayInputStream(body.getBytes()));
|
|
||||||
document.getDocumentElement().normalize();
|
|
||||||
|
|
||||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
|
||||||
Object result = xpath.evaluate(xpathExpression, document, XPathConstants.NODE);
|
|
||||||
|
|
||||||
if (result instanceof org.w3c.dom.Node domNode) {
|
|
||||||
return domNode.getTextContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Failed to evaluate XPath: " + xpathExpression, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Universal extract method - auto-detects content type and uses appropriate extraction.
|
|
||||||
*
|
|
||||||
* @param expression JSON path or XPath expression
|
|
||||||
* @return extracted value as string
|
|
||||||
*/
|
|
||||||
public String extract(String expression) {
|
|
||||||
return switch (contentType) {
|
|
||||||
case JSON -> extractJson(expression).asText();
|
|
||||||
case XML -> extractXml(expression);
|
|
||||||
case RAW_TEXT -> body;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluate JSON path on a JSON node.
|
|
||||||
* Supports dot notation and bracket notation for arrays.
|
|
||||||
*/
|
|
||||||
private JsonNode evaluateJsonPath(JsonNode node, String path) {
|
|
||||||
if (StringUtils.isEmpty(path)) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] parts = tokenizePath(path);
|
|
||||||
JsonNode current = node;
|
|
||||||
|
|
||||||
for (String part : parts) {
|
|
||||||
if (current == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (part.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (part.contains("[")) {
|
|
||||||
// Array access
|
|
||||||
Matcher matcher = JSON_PATH_PATTERN.matcher(part);
|
|
||||||
if (matcher.matches()) {
|
|
||||||
String arrayName = matcher.group(1);
|
|
||||||
int index = Integer.parseInt(matcher.group(2));
|
|
||||||
String remaining = matcher.group(3);
|
|
||||||
|
|
||||||
if (current.isArray()) {
|
|
||||||
current = index < current.size() ? current.get(index) : null;
|
|
||||||
} else if (current.isObject()) {
|
|
||||||
JsonNode arrayNode = current.get(arrayName);
|
|
||||||
if (arrayNode != null && arrayNode.isArray()) {
|
|
||||||
current = index < arrayNode.size() ? arrayNode.get(index) : null;
|
|
||||||
} else {
|
|
||||||
current = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue with remaining path
|
|
||||||
if (StringUtils.isNotBlank(remaining)) {
|
|
||||||
current = evaluateJsonPath(current, remaining);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
current = current.get(part);
|
|
||||||
}
|
|
||||||
} else if (part.contains(".")) {
|
|
||||||
// Navigate through object properties
|
|
||||||
String[] segments = part.split("\\.");
|
|
||||||
for (String segment : segments) {
|
|
||||||
if (StringUtils.isEmpty(segment)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
current = current.get(segment);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
current = current.get(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tokenize JSON path into segments.
|
|
||||||
*/
|
|
||||||
private String[] tokenizePath(String path) {
|
|
||||||
if (StringUtils.isEmpty(path)) {
|
|
||||||
return new String[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
java.util.List<String> tokens = new java.util.ArrayList<>();
|
|
||||||
StringBuilder current = new StringBuilder();
|
|
||||||
boolean inBracket = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < path.length(); i++) {
|
|
||||||
char c = path.charAt(i);
|
|
||||||
if (c == '[') {
|
|
||||||
inBracket = true;
|
|
||||||
current.append(c);
|
|
||||||
} else if (c == ']') {
|
|
||||||
inBracket = false;
|
|
||||||
current.append(c);
|
|
||||||
} else if (c == '.' && !inBracket) {
|
|
||||||
if (current.length() > 0) {
|
|
||||||
tokens.add(current.toString());
|
|
||||||
current.setLength(0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
current.append(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current.length() > 0) {
|
|
||||||
tokens.add(current.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokens.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the message key (Kafka message key, null for IBM MQ).
|
|
||||||
*/
|
|
||||||
public String getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a header value (Kafka header or JMS property).
|
|
||||||
*/
|
|
||||||
public String getHeader(String name) {
|
|
||||||
return headers.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all headers.
|
|
||||||
*/
|
|
||||||
public Map<String, String> getHeaders() {
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the message body.
|
|
||||||
*/
|
|
||||||
public String getBody() {
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the message timestamp.
|
|
||||||
*/
|
|
||||||
public long getTimestamp() {
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the content type.
|
|
||||||
*/
|
|
||||||
public MessageContentType getContentType() {
|
|
||||||
return contentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the source (topic or queue name).
|
|
||||||
*/
|
|
||||||
public String getSource() {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deserialize the message body to a Java object.
|
|
||||||
*
|
|
||||||
* @param type target type
|
|
||||||
* @param <T> target type
|
|
||||||
* @return deserialized object
|
|
||||||
*/
|
|
||||||
public <T> T mapTo(Class<T> type) {
|
|
||||||
if (body == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (contentType == MessageContentType.XML) {
|
|
||||||
// XML deserialization using JAXB
|
|
||||||
return mapXmlTo(type);
|
|
||||||
} else {
|
|
||||||
// JSON deserialization using Jackson
|
|
||||||
return JSON_MAPPER.readValue(body, type);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Failed to deserialize message to " + type.getName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deserialize the message body to a Java object for XML.
|
|
||||||
* Uses JAXB-like parsing - simplified for basic XML structures.
|
|
||||||
*/
|
|
||||||
private <T> T mapXmlTo(Class<T> type) {
|
|
||||||
try {
|
|
||||||
// For XML, parse to a simple map structure
|
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
|
||||||
javax.xml.parsers.DocumentBuilder finalBuilder = builder;
|
|
||||||
|
|
||||||
var document = finalBuilder.parse(new java.io.ByteArrayInputStream(body.getBytes()));
|
|
||||||
document.getDocumentElement().normalize();
|
|
||||||
|
|
||||||
Map<String, Object> xmlMap = xmlToMap(document.getDocumentElement());
|
|
||||||
return JSON_MAPPER.convertValue(xmlMap, type);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Failed to deserialize XML message", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert XML element to Map.
|
|
||||||
*/
|
|
||||||
private Map<String, Object> xmlToMap(org.w3c.dom.Element element) {
|
|
||||||
Map<String, Object> result = new HashMap<>();
|
|
||||||
|
|
||||||
for (int i = 0; i < element.getAttributes().getLength(); i++) {
|
|
||||||
org.w3c.dom.NamedNodeMap attributes = element.getAttributes();
|
|
||||||
org.w3c.dom.Node attr = attributes.item(i);
|
|
||||||
result.put("@" + attr.getNodeName(), attr.getNodeValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add children
|
|
||||||
for (int i = 0; i < element.getChildNodes().getLength(); i++) {
|
|
||||||
org.w3c.dom.Node node = element.getChildNodes().item(i);
|
|
||||||
if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
|
|
||||||
org.w3c.dom.Element childElement = (org.w3c.dom.Element) node;
|
|
||||||
String tagName = childElement.getTagName();
|
|
||||||
|
|
||||||
if (childElement.getChildNodes().getLength() == 0) {
|
|
||||||
// Leaf element
|
|
||||||
result.put(tagName, childElement.getTextContent());
|
|
||||||
} else {
|
|
||||||
// Check if all children are elements (complex) or text (simple)
|
|
||||||
boolean hasElement = false;
|
|
||||||
for (int j = 0; j < childElement.getChildNodes().getLength(); j++) {
|
|
||||||
org.w3c.dom.Node childNode = childElement.getChildNodes().item(j);
|
|
||||||
if (childNode.getNodeType() == org.w3c.dom.Node.TEXT_NODE &&
|
|
||||||
StringUtils.isNotBlank(childNode.getTextContent())) {
|
|
||||||
} else if (childNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
|
|
||||||
hasElement = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasElement) {
|
|
||||||
Map<String, Object> childMap = xmlToMap(childElement);
|
|
||||||
if (result.containsKey(tagName)) {
|
|
||||||
// Convert to list if multiple elements with same name
|
|
||||||
java.util.List<Object> list = new java.util.ArrayList<>();
|
|
||||||
if (result.get(tagName) instanceof Map) {
|
|
||||||
list.add(result.get(tagName));
|
|
||||||
}
|
|
||||||
list.add(childMap);
|
|
||||||
result.put(tagName, list);
|
|
||||||
} else {
|
|
||||||
result.put(tagName, childMap);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.put(tagName, childElement.getTextContent());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If element has only text content and no attributes or children, return text
|
|
||||||
if (element.getChildNodes().getLength() == 0) {
|
|
||||||
Map<String, Object> textMap = new HashMap<>();
|
|
||||||
textMap.put("#text", element.getTextContent());
|
|
||||||
return textMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ReceivedMessage{" +
|
|
||||||
"contentType=" + contentType +
|
|
||||||
", source='" + source + '\'' +
|
|
||||||
", key='" + key + '\'' +
|
|
||||||
", body='" + body + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,10 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import cz.moneta.test.harness.endpoints.imq.ImqFirstVisionEndpoint;
|
import cz.moneta.test.harness.endpoints.imq.ImqFirstVisionEndpoint;
|
||||||
import cz.moneta.test.harness.endpoints.imq.ImqFirstVisionQueue;
|
import cz.moneta.test.harness.endpoints.imq.ImqFirstVisionQueue;
|
||||||
import cz.moneta.test.harness.exception.HarnessException;
|
import cz.moneta.test.harness.exception.HarnessException;
|
||||||
import cz.moneta.test.harness.messaging.MessageContentType;
|
import cz.moneta.test.harness.support.messaging.exception.MessagingTimeoutException;
|
||||||
import cz.moneta.test.harness.messaging.MqMessageFormat;
|
|
||||||
import cz.moneta.test.harness.messaging.ReceivedMessage;
|
|
||||||
import cz.moneta.test.harness.messaging.exception.MessagingTimeoutException;
|
|
||||||
import cz.moneta.test.harness.support.util.FileReader;
|
import cz.moneta.test.harness.support.util.FileReader;
|
||||||
import cz.moneta.test.harness.support.util.Template;
|
import cz.moneta.test.harness.support.util.Template;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -381,7 +378,7 @@ public final class ImqRequest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MessageResponse withTimeout(long duration, java.util.concurrent.TimeUnit unit) {
|
public MessageResponse withTimeout(long duration, java.util.concurrent.TimeUnit unit) {
|
||||||
return withTimeout(Duration.of(duration, java.time.temporal.ChronoUnit.MILLIS));
|
return withTimeout(Duration.of(duration, unit.toChronoUnit()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -556,8 +553,8 @@ public final class ImqRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public cz.moneta.test.harness.support.messaging.ReceivedMessage getMessage() {
|
public ReceivedMessage getMessage() {
|
||||||
return cz.moneta.test.harness.support.messaging.ReceivedMessage.fromMessagingReceivedMessage(message);
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -5,15 +5,17 @@ package cz.moneta.test.harness.support.messaging;
|
|||||||
*/
|
*/
|
||||||
public enum MessageContentType {
|
public enum MessageContentType {
|
||||||
/**
|
/**
|
||||||
* JSON content - body is a JSON string, can use dot-path or bracket notation for extraction
|
* JSON content - body is a JSON string.
|
||||||
*/
|
*/
|
||||||
JSON,
|
JSON,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XML content - body is an XML string, can use XPath for extraction
|
* XML content - body is an XML string.
|
||||||
*/
|
*/
|
||||||
XML,
|
XML,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw text content - body is plain text without structured format
|
* Raw text content - body is plain text (e.g., EBCDIC decoded, UTF-8).
|
||||||
*/
|
*/
|
||||||
RAW_TEXT
|
RAW_TEXT
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,31 @@
|
|||||||
package cz.moneta.test.harness.support.messaging;
|
package cz.moneta.test.harness.support.messaging;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message format for IBM MQ messages.
|
* Message format for IBM MQ.
|
||||||
|
* Defines how messages are encoded and transmitted.
|
||||||
*/
|
*/
|
||||||
public enum MqMessageFormat {
|
public enum MqMessageFormat {
|
||||||
/**
|
/**
|
||||||
* JSON format - JMS TextMessage with plain JSON string (UTF-8 default)
|
* JSON format - MQ string message with plain JSON string.
|
||||||
|
* Default format for IBM MQ.
|
||||||
*/
|
*/
|
||||||
JSON,
|
JSON,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XML format - JMS TextMessage with XML string (UTF-8 default)
|
* XML format - MQ string message with XML string.
|
||||||
|
* XML is decoded and can be queried using XPath.
|
||||||
*/
|
*/
|
||||||
XML,
|
XML,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EBCDIC format - JMS BytesMessage with EBCDIC IBM-870 encoding (CZ/SK mainframe)
|
* EBCDIC format - MQ bytes message with EBCDIC IBM-870 encoding.
|
||||||
|
* Used for mainframe systems (Czech/Slovak characters).
|
||||||
*/
|
*/
|
||||||
EBCDIC_870,
|
EBCDIC_870,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UTF-8 format - JMS BytesMessage with UTF-8 IBM CCSID 1208 encoding
|
* UTF-8 format - MQ bytes message with UTF-8 (CCSID 1208) encoding.
|
||||||
|
* Used for binary data with explicit UTF-8 encoding.
|
||||||
*/
|
*/
|
||||||
UTF8_1208
|
UTF8_1208
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,36 +2,32 @@ package cz.moneta.test.harness.support.messaging;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
import javax.xml.xpath.XPathExpressionException;
|
import javax.xml.xpath.XPathConstants;
|
||||||
import javax.xml.xpath.XPathFactory;
|
import javax.xml.xpath.XPathFactory;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a received message from a messaging system (IBM MQ or Kafka).
|
* Represents a received message from a messaging system.
|
||||||
|
* Body is always normalized to a String regardless of source and wire format.
|
||||||
* <p>
|
* <p>
|
||||||
* Provides unified API for accessing message content regardless of source system.
|
* For Kafka: Avro GenericRecord is automatically converted to JSON.
|
||||||
* Body is always normalized to a String, with content type detection for proper extraction.
|
* For IBM MQ (JSON): JSON string from MQ string message.
|
||||||
* </p>
|
* For IBM MQ (XML): XML string from MQ string message.
|
||||||
|
* For IBM MQ (EBCDIC): byte[] from MQ message decoded from IBM-870.
|
||||||
*/
|
*/
|
||||||
public class ReceivedMessage {
|
public class ReceivedMessage {
|
||||||
|
|
||||||
private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
|
private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
|
||||||
private static final XmlMapper XML_MAPPER = new XmlMapper();
|
private static final Pattern JSON_PATH_PATTERN = Pattern.compile("^([\\w.]+)\\[([\\d]+)\\](.*)$");
|
||||||
|
|
||||||
private final String body;
|
private final String body;
|
||||||
private final MessageContentType contentType;
|
private final MessageContentType contentType;
|
||||||
@ -40,80 +36,75 @@ public class ReceivedMessage {
|
|||||||
private final String source;
|
private final String source;
|
||||||
private final String key;
|
private final String key;
|
||||||
|
|
||||||
private ReceivedMessage(Builder builder) {
|
public ReceivedMessage(String body, MessageContentType contentType, Map<String, String> headers,
|
||||||
this.body = builder.body;
|
long timestamp, String source, String key) {
|
||||||
this.contentType = builder.contentType;
|
this.body = body;
|
||||||
this.headers = builder.headers != null ? Collections.unmodifiableMap(new HashMap<>(builder.headers)) : Collections.emptyMap();
|
this.contentType = contentType;
|
||||||
this.timestamp = builder.timestamp;
|
this.headers = headers != null ? Collections.unmodifiableMap(new HashMap<>(headers)) : new HashMap<>();
|
||||||
this.source = builder.source;
|
this.timestamp = timestamp;
|
||||||
this.key = builder.key;
|
this.source = source;
|
||||||
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new builder for ReceivedMessage.
|
* Extract a JSON value using JSON path (dot/bracket notation).
|
||||||
*/
|
* Supports paths like "items[0].sku" or "nested.field".
|
||||||
public static Builder builder() {
|
|
||||||
return new Builder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts a value from the message body using JSON dot-path or bracket notation.
|
|
||||||
* <p>
|
|
||||||
* Supports paths like:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@code "field"} - top-level field</li>
|
|
||||||
* <li>{@code "parent.child"} - nested field</li>
|
|
||||||
* <li>{@code "items[0]"} - array element</li>
|
|
||||||
* <li>{@code "items[0].name"} - nested field in array element</li>
|
|
||||||
* </ul>
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @param path the JSON path expression
|
* @param path JSON path
|
||||||
* @return the extracted value as JsonNode
|
* @return JsonNode for the extracted value
|
||||||
*/
|
*/
|
||||||
public JsonNode extractJson(String path) {
|
public JsonNode extractJson(String path) {
|
||||||
if (contentType != MessageContentType.JSON) {
|
if (body == null || StringUtils.isEmpty(path)) {
|
||||||
throw new IllegalStateException("JSON extraction is only supported for JSON content type, got: " + contentType);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
JsonNode rootNode = JSON_MAPPER.readTree(body);
|
JsonNode root = JSON_MAPPER.readTree(body);
|
||||||
return extractNode(path, rootNode);
|
return evaluateJsonPath(root, path);
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Failed to parse JSON body: " + body, e);
|
throw new RuntimeException("Failed to extract JSON path: " + path, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts a value from XML message body using XPath expression.
|
* Extract a value using XPath (for XML messages).
|
||||||
*
|
*
|
||||||
* @param xpath the XPath expression
|
* @param xpathExpression XPath expression
|
||||||
* @return the extracted value as String
|
* @return extracted value as string
|
||||||
*/
|
*/
|
||||||
public String extractXml(String xpath) {
|
public String extractXml(String xpathExpression) {
|
||||||
if (contentType != MessageContentType.XML) {
|
if (body == null || StringUtils.isEmpty(xpathExpression)) {
|
||||||
throw new IllegalStateException("XML extraction is only supported for XML content type, got: " + contentType);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||||
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
|
||||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
Document doc = builder.parse(new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)));
|
javax.xml.parsers.DocumentBuilder finalBuilder = builder;
|
||||||
XPath xPath = XPathFactory.newInstance().newXPath();
|
|
||||||
return xPath.evaluate(xpath, doc);
|
var document = finalBuilder.parse(new java.io.ByteArrayInputStream(body.getBytes()));
|
||||||
} catch (XPathExpressionException e) {
|
document.getDocumentElement().normalize();
|
||||||
throw new RuntimeException("Failed to evaluate XPath: " + xpath, e);
|
|
||||||
|
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
|
Object result = xpath.evaluate(xpathExpression, document, XPathConstants.NODE);
|
||||||
|
|
||||||
|
if (result instanceof org.w3c.dom.Node domNode) {
|
||||||
|
return domNode.getTextContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Failed to parse XML body: " + body, e);
|
throw new RuntimeException("Failed to evaluate XPath: " + xpathExpression, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts a value from the message body. Auto-detects content type and uses appropriate extraction method.
|
* Universal extract method - auto-detects content type and uses appropriate extraction.
|
||||||
*
|
*
|
||||||
* @param expression the path expression (JSON path for JSON, XPath for XML)
|
* @param expression JSON path or XPath expression
|
||||||
* @return the extracted value as String
|
* @return extracted value as string
|
||||||
*/
|
*/
|
||||||
public String extract(String expression) {
|
public String extract(String expression) {
|
||||||
return switch (contentType) {
|
return switch (contentType) {
|
||||||
@ -124,181 +115,272 @@ public class ReceivedMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the message body as a String.
|
* Evaluate JSON path on a JSON node.
|
||||||
*
|
* Supports dot notation and bracket notation for arrays.
|
||||||
* @return the body content
|
|
||||||
*/
|
*/
|
||||||
public String getBody() {
|
private JsonNode evaluateJsonPath(JsonNode node, String path) {
|
||||||
return body;
|
if (StringUtils.isEmpty(path)) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] parts = tokenizePath(path);
|
||||||
|
JsonNode current = node;
|
||||||
|
|
||||||
|
for (String part : parts) {
|
||||||
|
if (current == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part.contains("[")) {
|
||||||
|
// Array access
|
||||||
|
Matcher matcher = JSON_PATH_PATTERN.matcher(part);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
String arrayName = matcher.group(1);
|
||||||
|
int index = Integer.parseInt(matcher.group(2));
|
||||||
|
String remaining = matcher.group(3);
|
||||||
|
|
||||||
|
if (current.isArray()) {
|
||||||
|
current = index < current.size() ? current.get(index) : null;
|
||||||
|
} else if (current.isObject()) {
|
||||||
|
JsonNode arrayNode = current.get(arrayName);
|
||||||
|
if (arrayNode != null && arrayNode.isArray()) {
|
||||||
|
current = index < arrayNode.size() ? arrayNode.get(index) : null;
|
||||||
|
} else {
|
||||||
|
current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue with remaining path
|
||||||
|
if (StringUtils.isNotBlank(remaining)) {
|
||||||
|
current = evaluateJsonPath(current, remaining);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current = current.get(part);
|
||||||
|
}
|
||||||
|
} else if (part.contains(".")) {
|
||||||
|
// Navigate through object properties
|
||||||
|
String[] segments = part.split("\\.");
|
||||||
|
for (String segment : segments) {
|
||||||
|
if (StringUtils.isEmpty(segment)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current = current.get(segment);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current = current.get(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the message content type.
|
* Tokenize JSON path into segments.
|
||||||
*
|
|
||||||
* @return the content type
|
|
||||||
*/
|
*/
|
||||||
public MessageContentType getContentType() {
|
private String[] tokenizePath(String path) {
|
||||||
return contentType;
|
if (StringUtils.isEmpty(path)) {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
java.util.List<String> tokens = new java.util.ArrayList<>();
|
||||||
|
StringBuilder current = new StringBuilder();
|
||||||
|
boolean inBracket = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < path.length(); i++) {
|
||||||
|
char c = path.charAt(i);
|
||||||
|
if (c == '[') {
|
||||||
|
inBracket = true;
|
||||||
|
current.append(c);
|
||||||
|
} else if (c == ']') {
|
||||||
|
inBracket = false;
|
||||||
|
current.append(c);
|
||||||
|
} else if (c == '.' && !inBracket) {
|
||||||
|
if (current.length() > 0) {
|
||||||
|
tokens.add(current.toString());
|
||||||
|
current.setLength(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current.length() > 0) {
|
||||||
|
tokens.add(current.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a header value by name.
|
* Get the message key (Kafka message key, null for IBM MQ).
|
||||||
*
|
|
||||||
* @param name the header name
|
|
||||||
* @return the header value, or null if not present
|
|
||||||
*/
|
|
||||||
public String getHeader(String name) {
|
|
||||||
return headers.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all headers.
|
|
||||||
*
|
|
||||||
* @return unmodifiable map of headers
|
|
||||||
*/
|
|
||||||
public Map<String, String> getHeaders() {
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the message timestamp.
|
|
||||||
*
|
|
||||||
* @return timestamp in milliseconds
|
|
||||||
*/
|
|
||||||
public long getTimestamp() {
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the source (topic name for Kafka, queue name for IBM MQ).
|
|
||||||
*
|
|
||||||
* @return the source name
|
|
||||||
*/
|
|
||||||
public String getSource() {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the message key (Kafka only, null for IBM MQ).
|
|
||||||
*
|
|
||||||
* @return the message key or null
|
|
||||||
*/
|
*/
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes the message body into a Java object.
|
* Get a header value (Kafka header or JMS property).
|
||||||
* <p>
|
*/
|
||||||
* For JSON content: uses Jackson ObjectMapper.readValue
|
public String getHeader(String name) {
|
||||||
* For XML content: uses Jackson XmlMapper
|
return headers.get(name);
|
||||||
* </p>
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all headers.
|
||||||
|
*/
|
||||||
|
public Map<String, String> getHeaders() {
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message body.
|
||||||
|
*/
|
||||||
|
public String getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message timestamp.
|
||||||
|
*/
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the content type.
|
||||||
|
*/
|
||||||
|
public MessageContentType getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the source (topic or queue name).
|
||||||
|
*/
|
||||||
|
public String getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize the message body to a Java object.
|
||||||
*
|
*
|
||||||
* @param type the target class
|
* @param type target type
|
||||||
* @param <T> the target type
|
* @param <T> target type
|
||||||
* @return the deserialized object
|
* @return deserialized object
|
||||||
*/
|
*/
|
||||||
public <T> T mapTo(Class<T> type) {
|
public <T> T mapTo(Class<T> type) {
|
||||||
try {
|
if (body == null) {
|
||||||
if (contentType == MessageContentType.XML) {
|
|
||||||
return XML_MAPPER.readValue(body, type);
|
|
||||||
} else {
|
|
||||||
return JSON_MAPPER.readValue(body, type);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Failed to deserialize message body to " + type.getName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder for ReceivedMessage.
|
|
||||||
*/
|
|
||||||
public static class Builder {
|
|
||||||
private String body;
|
|
||||||
private MessageContentType contentType = MessageContentType.JSON;
|
|
||||||
private Map<String, String> headers;
|
|
||||||
private long timestamp = System.currentTimeMillis();
|
|
||||||
private String source;
|
|
||||||
private String key;
|
|
||||||
|
|
||||||
public Builder body(String body) {
|
|
||||||
this.body = body;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder contentType(MessageContentType contentType) {
|
|
||||||
this.contentType = contentType;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder headers(Map<String, String> headers) {
|
|
||||||
this.headers = headers;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder timestamp(long timestamp) {
|
|
||||||
this.timestamp = timestamp;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder source(String source) {
|
|
||||||
this.source = source;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder key(String key) {
|
|
||||||
this.key = key;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReceivedMessage build() {
|
|
||||||
return new ReceivedMessage(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts a node from JSON using dot/bracket notation.
|
|
||||||
*/
|
|
||||||
private static JsonNode extractNode(String path, JsonNode rootNode) {
|
|
||||||
Pattern arrayPattern = Pattern.compile("(.*?)\\[([0-9]+)\\]");
|
|
||||||
return Arrays.stream(path.split("\\."))
|
|
||||||
.filter(StringUtils::isNotEmpty)
|
|
||||||
.reduce(rootNode,
|
|
||||||
(node, part) -> {
|
|
||||||
Matcher matcher = arrayPattern.matcher(part);
|
|
||||||
if (matcher.find()) {
|
|
||||||
return node.path(matcher.group(1)).path(Integer.parseInt(matcher.group(2)));
|
|
||||||
} else {
|
|
||||||
return node.path(part);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(n1, n2) -> n1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a cz.moneta.test.harness.messaging.ReceivedMessage to this class.
|
|
||||||
*
|
|
||||||
* @param other the message to convert
|
|
||||||
* @return converted message
|
|
||||||
*/
|
|
||||||
public static ReceivedMessage fromMessagingReceivedMessage(
|
|
||||||
cz.moneta.test.harness.messaging.ReceivedMessage other) {
|
|
||||||
if (other == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
cz.moneta.test.harness.support.messaging.MessageContentType contentType =
|
|
||||||
switch (other.getContentType()) {
|
try {
|
||||||
case JSON -> cz.moneta.test.harness.support.messaging.MessageContentType.JSON;
|
if (contentType == MessageContentType.XML) {
|
||||||
case XML -> cz.moneta.test.harness.support.messaging.MessageContentType.XML;
|
// XML deserialization using JAXB
|
||||||
case RAW_TEXT -> cz.moneta.test.harness.support.messaging.MessageContentType.RAW_TEXT;
|
return mapXmlTo(type);
|
||||||
};
|
} else {
|
||||||
return builder()
|
// JSON deserialization using Jackson
|
||||||
.body(other.getBody())
|
return JSON_MAPPER.readValue(body, type);
|
||||||
.contentType(contentType)
|
}
|
||||||
.headers(other.getHeaders())
|
} catch (Exception e) {
|
||||||
.timestamp(other.getTimestamp())
|
throw new RuntimeException("Failed to deserialize message to " + type.getName(), e);
|
||||||
.source(other.getSource())
|
}
|
||||||
.key(other.getKey())
|
}
|
||||||
.build();
|
|
||||||
|
/**
|
||||||
|
* Deserialize the message body to a Java object for XML.
|
||||||
|
* Uses JAXB-like parsing - simplified for basic XML structures.
|
||||||
|
*/
|
||||||
|
private <T> T mapXmlTo(Class<T> type) {
|
||||||
|
try {
|
||||||
|
// For XML, parse to a simple map structure
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
javax.xml.parsers.DocumentBuilder finalBuilder = builder;
|
||||||
|
|
||||||
|
var document = finalBuilder.parse(new java.io.ByteArrayInputStream(body.getBytes()));
|
||||||
|
document.getDocumentElement().normalize();
|
||||||
|
|
||||||
|
Map<String, Object> xmlMap = xmlToMap(document.getDocumentElement());
|
||||||
|
return JSON_MAPPER.convertValue(xmlMap, type);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to deserialize XML message", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert XML element to Map.
|
||||||
|
*/
|
||||||
|
private Map<String, Object> xmlToMap(org.w3c.dom.Element element) {
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < element.getAttributes().getLength(); i++) {
|
||||||
|
org.w3c.dom.NamedNodeMap attributes = element.getAttributes();
|
||||||
|
org.w3c.dom.Node attr = attributes.item(i);
|
||||||
|
result.put("@" + attr.getNodeName(), attr.getNodeValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add children
|
||||||
|
for (int i = 0; i < element.getChildNodes().getLength(); i++) {
|
||||||
|
org.w3c.dom.Node node = element.getChildNodes().item(i);
|
||||||
|
if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
|
||||||
|
org.w3c.dom.Element childElement = (org.w3c.dom.Element) node;
|
||||||
|
String tagName = childElement.getTagName();
|
||||||
|
|
||||||
|
if (childElement.getChildNodes().getLength() == 0) {
|
||||||
|
// Leaf element
|
||||||
|
result.put(tagName, childElement.getTextContent());
|
||||||
|
} else {
|
||||||
|
// Check if all children are elements (complex) or text (simple)
|
||||||
|
boolean hasElement = false;
|
||||||
|
for (int j = 0; j < childElement.getChildNodes().getLength(); j++) {
|
||||||
|
org.w3c.dom.Node childNode = childElement.getChildNodes().item(j);
|
||||||
|
if (childNode.getNodeType() == org.w3c.dom.Node.TEXT_NODE &&
|
||||||
|
StringUtils.isNotBlank(childNode.getTextContent())) {
|
||||||
|
} else if (childNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
|
||||||
|
hasElement = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasElement) {
|
||||||
|
Map<String, Object> childMap = xmlToMap(childElement);
|
||||||
|
if (result.containsKey(tagName)) {
|
||||||
|
// Convert to list if multiple elements with same name
|
||||||
|
java.util.List<Object> list = new java.util.ArrayList<>();
|
||||||
|
if (result.get(tagName) instanceof Map) {
|
||||||
|
list.add(result.get(tagName));
|
||||||
|
}
|
||||||
|
list.add(childMap);
|
||||||
|
result.put(tagName, list);
|
||||||
|
} else {
|
||||||
|
result.put(tagName, childMap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.put(tagName, childElement.getTextContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If element has only text content and no attributes or children, return text
|
||||||
|
if (element.getChildNodes().getLength() == 0) {
|
||||||
|
Map<String, Object> textMap = new HashMap<>();
|
||||||
|
textMap.put("#text", element.getTextContent());
|
||||||
|
return textMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ReceivedMessage{" +
|
||||||
|
"contentType=" + contentType +
|
||||||
|
", source='" + source + '\'' +
|
||||||
|
", key='" + key + '\'' +
|
||||||
|
", body='" + body + '\'' +
|
||||||
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package cz.moneta.test.harness.messaging.exception;
|
package cz.moneta.test.harness.support.messaging.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown when connection to messaging system fails.
|
* Exception thrown when connection to messaging system fails.
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package cz.moneta.test.harness.messaging.exception;
|
package cz.moneta.test.harness.support.messaging.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown when destination (topic/queue) does not exist or is inaccessible.
|
* Exception thrown when destination (topic/queue) does not exist or is inaccessible.
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package cz.moneta.test.harness.messaging.exception;
|
package cz.moneta.test.harness.support.messaging.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base exception for all messaging-related errors.
|
* Base exception for all messaging-related errors.
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package cz.moneta.test.harness.messaging.exception;
|
package cz.moneta.test.harness.support.messaging.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown when schema validation fails or schema is not found.
|
* Exception thrown when schema validation fails or schema is not found.
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package cz.moneta.test.harness.messaging.exception;
|
package cz.moneta.test.harness.support.messaging.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown when message receiving times out.
|
* Exception thrown when message receiving times out.
|
||||||
@ -1,25 +1,19 @@
|
|||||||
package cz.moneta.test.harness.support.messaging.kafka;
|
package cz.moneta.test.harness.support.messaging.kafka;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
import cz.moneta.test.harness.endpoints.kafka.KafkaEndpoint;
|
import cz.moneta.test.harness.endpoints.kafka.KafkaEndpoint;
|
||||||
import cz.moneta.test.harness.support.util.FileReader;
|
import cz.moneta.test.harness.support.util.FileReader;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fluent builder for creating and sending Kafka messages.
|
* Fluent builder for creating and sending Kafka messages.
|
||||||
@ -69,6 +63,8 @@ public class KafkaRequest {
|
|||||||
* @return KafkaReceiveFilterPhase for filter configuration
|
* @return KafkaReceiveFilterPhase for filter configuration
|
||||||
*/
|
*/
|
||||||
KafkaReceiveFilterPhase fromTopic(String topic);
|
KafkaReceiveFilterPhase fromTopic(String topic);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,6 +183,20 @@ public class KafkaRequest {
|
|||||||
* Phase 2b: Configure filter for receiving.
|
* Phase 2b: Configure filter for receiving.
|
||||||
*/
|
*/
|
||||||
public interface KafkaReceiveFilterPhase {
|
public interface KafkaReceiveFilterPhase {
|
||||||
|
/**
|
||||||
|
* Specifies the starting point of consumption at the start of partitions.
|
||||||
|
*
|
||||||
|
* @return KafkaReceiveFilterPhase for filter configuration
|
||||||
|
*/
|
||||||
|
KafkaReceiveFilterPhase startFromBeginning();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the starting point of consumption at the end of partitions
|
||||||
|
*
|
||||||
|
* @return KafkaReceiveFilterPhase for filter configuration
|
||||||
|
*/
|
||||||
|
KafkaReceiveFilterPhase startFromEnd();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the filter predicate for receiving messages.
|
* Specifies the filter predicate for receiving messages.
|
||||||
*
|
*
|
||||||
@ -229,7 +239,8 @@ public class KafkaRequest {
|
|||||||
// Receive configuration
|
// Receive configuration
|
||||||
private Predicate<ReceivedMessage> filter;
|
private Predicate<ReceivedMessage> filter;
|
||||||
private Duration timeout;
|
private Duration timeout;
|
||||||
|
//default true
|
||||||
|
private boolean startFromBeginning = true;
|
||||||
// Response (after receive)
|
// Response (after receive)
|
||||||
private List<ReceivedMessage> messages;
|
private List<ReceivedMessage> messages;
|
||||||
|
|
||||||
@ -363,6 +374,18 @@ public class KafkaRequest {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KafkaReceiveFilterPhase startFromBeginning() {
|
||||||
|
this.startFromBeginning = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KafkaReceiveFilterPhase startFromEnd() {
|
||||||
|
this.startFromBeginning = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KafkaAwaitingPhase receiveWhere(Predicate<ReceivedMessage> filter) {
|
public KafkaAwaitingPhase receiveWhere(Predicate<ReceivedMessage> filter) {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
@ -372,7 +395,7 @@ public class KafkaRequest {
|
|||||||
@Override
|
@Override
|
||||||
public MessageResponse withTimeout(long duration, TimeUnit unit) {
|
public MessageResponse withTimeout(long duration, TimeUnit unit) {
|
||||||
this.timeout = Duration.of(duration, unit.toChronoUnit());
|
this.timeout = Duration.of(duration, unit.toChronoUnit());
|
||||||
messages = endpoint.receive(topic, filter, timeout);
|
messages = endpoint.receive(topic, filter, timeout, startFromBeginning);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
BIN
test-harness/src/main/resources/keystores/imq.jks
Normal file
BIN
test-harness/src/main/resources/keystores/imq.jks
Normal file
Binary file not shown.
@ -1,4 +1,5 @@
|
|||||||
|
Hello World!!!
|
||||||
|
Hello World Too!!!
|
||||||
# Automated tests
|
# Automated tests
|
||||||
|
|
||||||
This repo contains automated tests for all squads.
|
This repo contains automated tests for all squads.
|
||||||
|
|||||||
@ -73,24 +73,6 @@
|
|||||||
</activation>
|
</activation>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
|
||||||
<version>3.9.0</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>install</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>copy-dependencies</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<outputDirectory>
|
|
||||||
${project.build.directory}/lib</outputDirectory>
|
|
||||||
<includeScope>runtime</includeScope>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.13.0</version>
|
<version>3.13.0</version>
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import cz.moneta.test.dsl.fortelight.ForteLight;
|
|||||||
import cz.moneta.test.dsl.greenscreen.GreenScreen;
|
import cz.moneta.test.dsl.greenscreen.GreenScreen;
|
||||||
import cz.moneta.test.dsl.hypos.Hypos;
|
import cz.moneta.test.dsl.hypos.Hypos;
|
||||||
import cz.moneta.test.dsl.ib.Ib;
|
import cz.moneta.test.dsl.ib.Ib;
|
||||||
|
import cz.moneta.test.dsl.payment_engine_mq.PaeMqBuilder;
|
||||||
import cz.moneta.test.dsl.ilods.Ilods;
|
import cz.moneta.test.dsl.ilods.Ilods;
|
||||||
import cz.moneta.test.dsl.imq.ImqFirstVision;
|
import cz.moneta.test.dsl.imq.ImqFirstVision;
|
||||||
import cz.moneta.test.dsl.kafka.Kafka;
|
import cz.moneta.test.dsl.kafka.Kafka;
|
||||||
@ -142,7 +143,6 @@ public class Harness extends BaseStoreAccessor {
|
|||||||
return new Ufo(this, SECOND_BANKER_TOKEN);
|
return new Ufo(this, SECOND_BANKER_TOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public Oauth2Web withOauth2Web() {
|
public Oauth2Web withOauth2Web() {
|
||||||
return new Oauth2Web(this);
|
return new Oauth2Web(this);
|
||||||
}
|
}
|
||||||
@ -191,6 +191,10 @@ public class Harness extends BaseStoreAccessor {
|
|||||||
return new AresApiBuilder(this);
|
return new AresApiBuilder(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PaeMqBuilder withPaeMq() {
|
||||||
|
return new PaeMqBuilder(this);
|
||||||
|
}
|
||||||
|
|
||||||
public Sb withSB() {
|
public Sb withSB() {
|
||||||
return new Sb(this);
|
return new Sb(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -152,6 +152,7 @@ public interface CustomerPage extends SmartAutoFlow<CustomerPage>, StoreAccessor
|
|||||||
@TypeInto(NAME)
|
@TypeInto(NAME)
|
||||||
CustomerPage typeName(String name);
|
CustomerPage typeName(String name);
|
||||||
|
|
||||||
|
@Wait(value = PHONE_NUMBER, until = Until.VISIBLE)
|
||||||
@TypeInto(PHONE_NUMBER)
|
@TypeInto(PHONE_NUMBER)
|
||||||
CustomerPage typePhoneNumber(String phoneNumber);
|
CustomerPage typePhoneNumber(String phoneNumber);
|
||||||
|
|
||||||
@ -331,6 +332,7 @@ public interface CustomerPage extends SmartAutoFlow<CustomerPage>, StoreAccessor
|
|||||||
@Click(value = STAY_TYPE_CHOOSE, jsClick = true)
|
@Click(value = STAY_TYPE_CHOOSE, jsClick = true)
|
||||||
CustomerPage chooseStayType(StayType stayType);
|
CustomerPage chooseStayType(StayType stayType);
|
||||||
|
|
||||||
|
@Wait(value = BUSINESSMAN_PHONE_NUMBER, until = Until.VISIBLE)
|
||||||
@TypeInto(BUSINESSMAN_PHONE_NUMBER)
|
@TypeInto(BUSINESSMAN_PHONE_NUMBER)
|
||||||
CustomerPage typeBusinessmanPhoneNumber(String phoneNumber);
|
CustomerPage typeBusinessmanPhoneNumber(String phoneNumber);
|
||||||
|
|
||||||
@ -355,6 +357,7 @@ public interface CustomerPage extends SmartAutoFlow<CustomerPage>, StoreAccessor
|
|||||||
@Click(NUMBER_OF_EMPLOYEES_FIELD)
|
@Click(NUMBER_OF_EMPLOYEES_FIELD)
|
||||||
CustomerPage chooseNoOfEmployees();
|
CustomerPage chooseNoOfEmployees();
|
||||||
|
|
||||||
|
@Wait (value = BUSINESSMAN_SILENT_COMPANION, until = Until.CLICKABLE)
|
||||||
@Click(BUSINESSMAN_SILENT_COMPANION)
|
@Click(BUSINESSMAN_SILENT_COMPANION)
|
||||||
CustomerPage clickBusinessmanSilentCompanion();
|
CustomerPage clickBusinessmanSilentCompanion();
|
||||||
|
|
||||||
|
|||||||
@ -62,6 +62,7 @@ public interface NewCalculationPage extends SmartAutoFlow<NewCalculationPage>, S
|
|||||||
String VEHICLE_CAR_INSURANCE_CUSTOMER_BIRTHDATE = "//label//span[contains(text(), 'Datum narození')]/../following-sibling::div/input";
|
String VEHICLE_CAR_INSURANCE_CUSTOMER_BIRTHDATE = "//label//span[contains(text(), 'Datum narození')]/../following-sibling::div/input";
|
||||||
String VEHICLE_CAR_INSURANCE_CUSTOMER_PIN = "//label//span[contains(text(), 'Rodné číslo')]/../following-sibling::input";
|
String VEHICLE_CAR_INSURANCE_CUSTOMER_PIN = "//label//span[contains(text(), 'Rodné číslo')]/../following-sibling::input";
|
||||||
String VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY = "//label/span/span[contains(text(), 'Občanství')]/../../following-sibling::div/div/div/input";
|
String VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY = "//label/span/span[contains(text(), 'Občanství')]/../../following-sibling::div/div/div/input";
|
||||||
|
String VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_TEXTBOX = "//label/span/span[contains(text(), 'Občanství')]/../../../div/div/div";
|
||||||
String VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_FIELD = "//label/span/span[contains(text(), 'Občanství')]/../../following-sibling::div/div/button[1]";
|
String VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_FIELD = "//label/span/span[contains(text(), 'Občanství')]/../../following-sibling::div/div/button[1]";
|
||||||
String VEHICLE_CAR_INSURANCE_CUSTOMER_ADDRESS = "//span[contains(text(),'Trvalé bydliště')]/../../following-sibling::div/div/div/input";
|
String VEHICLE_CAR_INSURANCE_CUSTOMER_ADDRESS = "//span[contains(text(),'Trvalé bydliště')]/../../following-sibling::div/div/div/input";
|
||||||
String VEHICLE_CAR_INSURANCE_CUSTOMER_ADDRESS_FIELDS = "//span[contains(text(),'Trvalé bydliště')]/../../following-sibling::div/div/button[1]";
|
String VEHICLE_CAR_INSURANCE_CUSTOMER_ADDRESS_FIELDS = "//span[contains(text(),'Trvalé bydliště')]/../../following-sibling::div/div/button[1]";
|
||||||
@ -253,8 +254,12 @@ public interface NewCalculationPage extends SmartAutoFlow<NewCalculationPage>, S
|
|||||||
@TypeInto(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY, clear = true)
|
@TypeInto(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY, clear = true)
|
||||||
NewCalculationPage typeVehicleInsuranceCustomerNationality(String nationality);
|
NewCalculationPage typeVehicleInsuranceCustomerNationality(String nationality);
|
||||||
|
|
||||||
@Wait(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_FIELD)
|
@Wait(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_TEXTBOX)
|
||||||
@Click(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_FIELD, jsClick = true)
|
@Click(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_TEXTBOX, andWait = @Wait(explicitWaitSeconds = 1))
|
||||||
|
NewCalculationPage clickVehicleInsuranceCustomerNationalityTextbox();
|
||||||
|
|
||||||
|
@Wait(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_FIELD, until = Until.VISIBLE)
|
||||||
|
@Click(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_FIELD)
|
||||||
NewCalculationPage clickVehicleInsuranceCustomerNationality();
|
NewCalculationPage clickVehicleInsuranceCustomerNationality();
|
||||||
|
|
||||||
@Wait(VEHICLE_CAR_INSURANCE_CUSTOMER_ADDRESS)
|
@Wait(VEHICLE_CAR_INSURANCE_CUSTOMER_ADDRESS)
|
||||||
@ -271,19 +276,19 @@ public interface NewCalculationPage extends SmartAutoFlow<NewCalculationPage>, S
|
|||||||
|
|
||||||
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
|
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
|
||||||
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_VOLUME_AGRO)
|
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_VOLUME_AGRO)
|
||||||
NewCalculationPage typeVehicleInsuranceVehicleVolume(String volume);
|
NewCalculationPage typeVehicleInsuranceVehicleVolume(int volume);
|
||||||
|
|
||||||
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
|
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
|
||||||
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_NUMBER_OF_SEATS)
|
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_NUMBER_OF_SEATS)
|
||||||
NewCalculationPage typeVehicleInsuranceVehicleNumberOfSeats(String numberOfSeats);
|
NewCalculationPage typeVehicleInsuranceVehicleNumberOfSeats(int numberOfSeats);
|
||||||
|
|
||||||
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
|
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
|
||||||
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_POWER_AGRO, andWait = @Wait(explicitWaitSeconds = 2))
|
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_POWER_AGRO, andWait = @Wait(explicitWaitSeconds = 2))
|
||||||
NewCalculationPage typeVehicleInsuranceVehiclePower(String power);
|
NewCalculationPage typeVehicleInsuranceVehiclePower(int power);
|
||||||
|
|
||||||
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
|
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
|
||||||
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_WEIGHT_AGRO)
|
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_WEIGHT_AGRO)
|
||||||
NewCalculationPage typeVehicleInsuranceVehicleWeight(String weight);
|
NewCalculationPage typeVehicleInsuranceVehicleWeight(int weight);
|
||||||
|
|
||||||
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
|
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
|
||||||
@Click(VEHICLE_CAR_INSURANCE_VEHICLE_FUEL_AGRO)
|
@Click(VEHICLE_CAR_INSURANCE_VEHICLE_FUEL_AGRO)
|
||||||
|
|||||||
@ -2,10 +2,7 @@ package cz.moneta.test.dsl.auto.smartauto;
|
|||||||
|
|
||||||
import cz.moneta.test.dsl.auto.smartauto.shared.BankCode;
|
import cz.moneta.test.dsl.auto.smartauto.shared.BankCode;
|
||||||
import cz.moneta.test.dsl.auto.smartauto.shared.CommonElements;
|
import cz.moneta.test.dsl.auto.smartauto.shared.CommonElements;
|
||||||
import cz.moneta.test.harness.support.web.CheckElementPresent;
|
import cz.moneta.test.harness.support.web.*;
|
||||||
import cz.moneta.test.harness.support.web.Click;
|
|
||||||
import cz.moneta.test.harness.support.web.TypeInto;
|
|
||||||
import cz.moneta.test.harness.support.web.Wait;
|
|
||||||
|
|
||||||
public interface OthersPage extends SmartAutoFlow<OthersPage> {
|
public interface OthersPage extends SmartAutoFlow<OthersPage> {
|
||||||
|
|
||||||
@ -45,12 +42,14 @@ public interface OthersPage extends SmartAutoFlow<OthersPage> {
|
|||||||
@TypeInto(APPROVAL_MESSAGE)
|
@TypeInto(APPROVAL_MESSAGE)
|
||||||
OthersPage typeApprovalMessage(String approvalMessage);
|
OthersPage typeApprovalMessage(String approvalMessage);
|
||||||
|
|
||||||
|
@Wait(value = VEHICLE_PAGE, until = Until.CLICKABLE)
|
||||||
@Click(value = VEHICLE_PAGE, jsClick = true)
|
@Click(value = VEHICLE_PAGE, jsClick = true)
|
||||||
VehiclePage clickVehiclePage();
|
VehiclePage clickVehiclePage();
|
||||||
|
|
||||||
@Click(value = CommonElements.SAVE_CALCULATION_BUTTON, andWait = @Wait(value = CommonElements.SUCCESSFUL_SAVED_CALCULATION_MESSAGE), jsClick = true)
|
@Click(value = CommonElements.SAVE_CALCULATION_BUTTON, andWait = @Wait(value = CommonElements.SUCCESSFUL_SAVED_CALCULATION_MESSAGE), jsClick = true)
|
||||||
OthersPage clickSaveCalculation();
|
OthersPage clickSaveCalculation();
|
||||||
|
|
||||||
|
@Wait(value = DUPLICATE_APPLICATION, until = Until.CLICKABLE)
|
||||||
@Click(value = DUPLICATE_APPLICATION, jsClick = true)
|
@Click(value = DUPLICATE_APPLICATION, jsClick = true)
|
||||||
OthersPage clickDuplicateApplication();
|
OthersPage clickDuplicateApplication();
|
||||||
|
|
||||||
|
|||||||
@ -7,10 +7,10 @@ import cz.moneta.test.harness.support.web.*;
|
|||||||
public interface SavedCalculationsPage extends SmartAutoFlow<SavedCalculationsPage>, StoreAccessor, CalendarAccessor {
|
public interface SavedCalculationsPage extends SmartAutoFlow<SavedCalculationsPage>, StoreAccessor, CalendarAccessor {
|
||||||
|
|
||||||
String HEADING_SAVED_CALCULATIONS = "//h1[contains(text(), 'Kalkulace')]";
|
String HEADING_SAVED_CALCULATIONS = "//h1[contains(text(), 'Kalkulace')]";
|
||||||
String FIRST_APPLICATION_DIV = "/html/body/div[1]/div[1]/div/div/div[1]/div[2]/div[1]/div/div[1]";
|
String FIRST_APPLICATION_DIV = "//h2/span[contains(text(), 'Dnes')]/../../div[1]";
|
||||||
String CALCULATION_NAME = FIRST_APPLICATION_DIV + "/div[2]/div[contains(text(), 'TestDuplikace')]";
|
String CALCULATION_NAME = FIRST_APPLICATION_DIV + "/div/div/div/div[contains(text(), 'TestDuplikace')]";
|
||||||
String CALCULATION_STATUS = FIRST_APPLICATION_DIV + "//span[contains(text(), 'Rozpracovaná žádost')]";
|
String CALCULATION_STATUS = FIRST_APPLICATION_DIV + "//span[contains(text(), 'Rozpracovaná žádost')]";
|
||||||
String CALCULATION_DATE = FIRST_APPLICATION_DIV + "/div[3]/div[2]";
|
String CALCULATION_DATE = FIRST_APPLICATION_DIV + "/div/div/div[3]/div[2]";
|
||||||
String DATE_FROM = "//label[contains(., 'Datum od')]/following-sibling::div/button";
|
String DATE_FROM = "//label[contains(., 'Datum od')]/following-sibling::div/button";
|
||||||
String DATE_TO = "//label[contains(., 'Datum do')]/following-sibling::div/button";
|
String DATE_TO = "//label[contains(., 'Datum do')]/following-sibling::div/button";
|
||||||
String SEARCH_BUTTON = "//button[@testid='bbutton' and span[text()='Zobrazit']]";
|
String SEARCH_BUTTON = "//button[@testid='bbutton' and span[text()='Zobrazit']]";
|
||||||
|
|||||||
@ -145,6 +145,7 @@ public interface VehiclePage extends SmartAutoFlow<VehiclePage>, StoreAccessor {
|
|||||||
@Click(BUTTON_SEARCH)
|
@Click(BUTTON_SEARCH)
|
||||||
VehiclePage clickSearchWithVin();
|
VehiclePage clickSearchWithVin();
|
||||||
|
|
||||||
|
@Wait(value = BUTTON_TO_QUEUE, until = Until.CLICKABLE)
|
||||||
@Click(value = BUTTON_TO_QUEUE, jsClick = true)
|
@Click(value = BUTTON_TO_QUEUE, jsClick = true)
|
||||||
VehiclePage clickToQueue();
|
VehiclePage clickToQueue();
|
||||||
|
|
||||||
|
|||||||
@ -9,9 +9,9 @@ public class CalculationData {
|
|||||||
private Brand brand;
|
private Brand brand;
|
||||||
private Model model;
|
private Model model;
|
||||||
private FilterFuel fuel;
|
private FilterFuel fuel;
|
||||||
private String volume;
|
private int volume;
|
||||||
private String power;
|
private int power;
|
||||||
private String weight;
|
private int weight;
|
||||||
private int price;
|
private int price;
|
||||||
private String vin;
|
private String vin;
|
||||||
private Vat vat;
|
private Vat vat;
|
||||||
@ -25,7 +25,7 @@ public class CalculationData {
|
|||||||
private Subsidy subsidy;
|
private Subsidy subsidy;
|
||||||
private ItemType itemType;
|
private ItemType itemType;
|
||||||
private int firstPayment;
|
private int firstPayment;
|
||||||
private String numberOfSeats;
|
private int numberOfSeats;
|
||||||
|
|
||||||
public CalculationData setCustomer(Customer customer) {
|
public CalculationData setCustomer(Customer customer) {
|
||||||
this.customer = customer;
|
this.customer = customer;
|
||||||
@ -117,22 +117,22 @@ public class CalculationData {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CalculationData setVolume(String volume) {
|
public CalculationData setVolume(int volume) {
|
||||||
this.volume = volume;
|
this.volume = volume;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CalculationData setPower(String power) {
|
public CalculationData setPower(int power) {
|
||||||
this.power = power;
|
this.power = power;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CalculationData setWeight(String weight) {
|
public CalculationData setWeight(int weight) {
|
||||||
this.weight = weight;
|
this.weight = weight;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CalculationData setNumberOfSeats(String numberOfSeats) {
|
public CalculationData setNumberOfSeats(int numberOfSeats) {
|
||||||
this.numberOfSeats = numberOfSeats;
|
this.numberOfSeats = numberOfSeats;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,9 @@ package cz.moneta.test.dsl.cagw.api;
|
|||||||
import cz.moneta.test.dsl.Harness;
|
import cz.moneta.test.dsl.Harness;
|
||||||
import cz.moneta.test.dsl.cagw.CaGwBuilder;
|
import cz.moneta.test.dsl.cagw.CaGwBuilder;
|
||||||
import cz.moneta.test.dsl.cagw.api.cbl.CblBuilder;
|
import cz.moneta.test.dsl.cagw.api.cbl.CblBuilder;
|
||||||
|
import cz.moneta.test.dsl.cagw.api.v1.V1Builder;
|
||||||
import cz.moneta.test.dsl.cagw.api.v2.V2Builder;
|
import cz.moneta.test.dsl.cagw.api.v2.V2Builder;
|
||||||
import cz.moneta.test.dsl.cagw.api.v4.V4Builder;
|
import cz.moneta.test.dsl.cagw.api.v4.V4Builder;
|
||||||
import cz.moneta.test.dsl.cagw.api.v1.V1Builder;
|
|
||||||
|
|
||||||
public class ApiBuilder extends CaGwBuilder {
|
public class ApiBuilder extends CaGwBuilder {
|
||||||
|
|
||||||
@ -17,6 +17,10 @@ public class ApiBuilder extends CaGwBuilder {
|
|||||||
return new CblBuilder(harness);
|
return new CblBuilder(harness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public V1Builder v1() {
|
||||||
|
return new V1Builder(harness);
|
||||||
|
}
|
||||||
|
|
||||||
public V2Builder v2() {
|
public V2Builder v2() {
|
||||||
return new V2Builder(harness);
|
return new V2Builder(harness);
|
||||||
}
|
}
|
||||||
@ -25,8 +29,4 @@ public class ApiBuilder extends CaGwBuilder {
|
|||||||
return new V4Builder(harness);
|
return new V4Builder(harness);
|
||||||
}
|
}
|
||||||
|
|
||||||
public V1Builder v1() {
|
|
||||||
return new V1Builder(harness);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -17,6 +17,8 @@ import static cz.moneta.test.dsl.exevido.pages.inheritance.FoldersPage.PAGE_LABE
|
|||||||
public interface LeftMenu<T> {
|
public interface LeftMenu<T> {
|
||||||
|
|
||||||
String PAGE_SA_SMART_MENU = "sasmartmenu";
|
String PAGE_SA_SMART_MENU = "sasmartmenu";
|
||||||
|
String CATEGORY_MY_MESSAGES = "my_link";
|
||||||
|
String SUBCATEGORY_FOR_CHECK = "myForCheck";
|
||||||
String CATEGORY_INCOMING_MESSAGES = "incoming_messages_link";
|
String CATEGORY_INCOMING_MESSAGES = "incoming_messages_link";
|
||||||
String SUBCATEGORY_ALL_INCOMING_MESSAGES_A = "all_incoming_messages";
|
String SUBCATEGORY_ALL_INCOMING_MESSAGES_A = "all_incoming_messages";
|
||||||
String CATEGORY_OUTGOING_MESSAGES = "outgoing_messages_link";
|
String CATEGORY_OUTGOING_MESSAGES = "outgoing_messages_link";
|
||||||
@ -28,6 +30,12 @@ public interface LeftMenu<T> {
|
|||||||
String FOR_PROCESSING_D_REQUEST_MMB_XPATH = CATEGORY_INHERITANCE_MMB_XPATH + "//a[contains(., 'D - Žádost [M] - MMB')]";
|
String FOR_PROCESSING_D_REQUEST_MMB_XPATH = CATEGORY_INHERITANCE_MMB_XPATH + "//a[contains(., 'D - Žádost [M] - MMB')]";
|
||||||
String REFRESH_COUNTERS_BUTTON = "refresh_counters";
|
String REFRESH_COUNTERS_BUTTON = "refresh_counters";
|
||||||
|
|
||||||
|
@Click(value = CATEGORY_MY_MESSAGES, andWait = @Wait(value = LOADER_DIV, until = Until.GONE))
|
||||||
|
IncomingMessagesPage clickMyMessages();
|
||||||
|
|
||||||
|
@Click(value = SUBCATEGORY_FOR_CHECK, andWait = @Wait(value = LOADER_DIV, until = Until.GONE))
|
||||||
|
OutgoingMessagesPage clickForCheckMessages();
|
||||||
|
|
||||||
@Click(value = CATEGORY_INCOMING_MESSAGES, andWait = @Wait(value = LOADER_DIV, until = Until.GONE))
|
@Click(value = CATEGORY_INCOMING_MESSAGES, andWait = @Wait(value = LOADER_DIV, until = Until.GONE))
|
||||||
IncomingMessagesPage clickIncomingMessages();
|
IncomingMessagesPage clickIncomingMessages();
|
||||||
|
|
||||||
|
|||||||
@ -140,7 +140,7 @@ public interface DetailIncomingMessagePage extends ExevidoWebFlow<DetailIncoming
|
|||||||
DetailIncomingMessagePage saveFolderIssueNumber();
|
DetailIncomingMessagePage saveFolderIssueNumber();
|
||||||
|
|
||||||
@Click(value = REMOVE_FOLDER_ISSUE_NUMBER, by = Lookup.XPATH, isStringDynamicXpath = true)
|
@Click(value = REMOVE_FOLDER_ISSUE_NUMBER, by = Lookup.XPATH, isStringDynamicXpath = true)
|
||||||
@Click(CONFIRM_BUTTON)
|
@Click(value = CONFIRM_BUTTON, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
DetailIncomingMessagePage removeFolderIssueNumber(String folderIssueNumber);
|
DetailIncomingMessagePage removeFolderIssueNumber(String folderIssueNumber);
|
||||||
|
|
||||||
@CheckElementContent(value = MESSAGE_ID_SPAN)
|
@CheckElementContent(value = MESSAGE_ID_SPAN)
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
package cz.moneta.test.dsl.exevido.pages;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.exevido.ExevidoWebFlow;
|
||||||
|
import cz.moneta.test.dsl.exevido.components.ExevidoPanels;
|
||||||
|
import cz.moneta.test.harness.support.web.*;
|
||||||
|
|
||||||
|
import static cz.moneta.test.dsl.exevido.pages.DetailIncomingMessagePage.PAGE_LABEL;
|
||||||
|
|
||||||
|
@Wait(value = PAGE_LABEL)
|
||||||
|
public interface DetailOutgoingMessagePage extends ExevidoWebFlow<DetailOutgoingMessagePage> {
|
||||||
|
|
||||||
|
String PAGE_LABEL = "outgoing_message_label";
|
||||||
|
String SEND_REPLY_BUTTON_XPATH = "//button[@title='Vytvoří ke zprávě odpověď a odešle']";
|
||||||
|
String RETURN_TO_PROCESSING_BUTTON_XPATH = "//button[@title='Vrátí zprávu ke zpracování']";
|
||||||
|
String FOR_CHECK_REASON_INPUT = "forCheckReason";
|
||||||
|
String ADD_FOR_REASON_BUTTON = "addForReasonButton";
|
||||||
|
|
||||||
|
@Click(value = SEND_REPLY_BUTTON_XPATH, by = Lookup.XPATH, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
IncomingMessagesPage clickSendReply();
|
||||||
|
|
||||||
|
@Click(value = RETURN_TO_PROCESSING_BUTTON_XPATH, by = Lookup.XPATH, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
DetailOutgoingMessagePage clickReturnToProcessing();
|
||||||
|
|
||||||
|
@TypeInto(FOR_CHECK_REASON_INPUT)
|
||||||
|
DetailOutgoingMessagePage fillReason(String reason);
|
||||||
|
|
||||||
|
@Click(value = ADD_FOR_REASON_BUTTON, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
IncomingMessagesPage clickAddReason();
|
||||||
|
|
||||||
|
}
|
||||||
@ -43,7 +43,6 @@ public interface IncomingMessagesPage extends ExevidoWebFlow<IncomingMessagesPag
|
|||||||
@CustomAction
|
@CustomAction
|
||||||
default DetailIncomingMessagePage clickIncomingMessageRow(int timeout) {
|
default DetailIncomingMessagePage clickIncomingMessageRow(int timeout) {
|
||||||
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
|
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
|
||||||
endpoint.sendKeysOneAtATime(Key.ENTER);
|
|
||||||
endpoint.waitForElementAndRefresh(INCOMING_MESSAGE_ROW, Lookup.ID, endpoint::refeshPage, timeout, 2);
|
endpoint.waitForElementAndRefresh(INCOMING_MESSAGE_ROW, Lookup.ID, endpoint::refeshPage, timeout, 2);
|
||||||
endpoint.click(() -> INCOMING_MESSAGE_ROW, Lookup.ID);
|
endpoint.click(() -> INCOMING_MESSAGE_ROW, Lookup.ID);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -12,8 +12,9 @@ import static cz.moneta.test.dsl.exevido.pages.NewIncomingMessagePage.PAGE_LABEL
|
|||||||
@Wait(PAGE_LABEL_B)
|
@Wait(PAGE_LABEL_B)
|
||||||
public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessagePage>, StoreAccessor {
|
public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessagePage>, StoreAccessor {
|
||||||
|
|
||||||
String MESSAGE_ID_KEY = "MESSAGE_ID";
|
String INCOMING_MESSAGE_ID_KEY = "INCOMING_MESSAGE_ID";
|
||||||
String PAGE_LABEL_B = "outgoing_message_label";
|
String PAGE_LABEL_B = "outgoing_message_label";
|
||||||
|
String ANSWER_BUTTON = "answer";
|
||||||
String SUBJECT_INPUT = "subject";
|
String SUBJECT_INPUT = "subject";
|
||||||
String SENDER_XPATH = "//iq-select2[@id='_selectId']//input";
|
String SENDER_XPATH = "//iq-select2[@id='_selectId']//input";
|
||||||
String FILE_UPLOAD_XPATH = "(//input[@type='file' and @multiple='multiple'])";
|
String FILE_UPLOAD_XPATH = "(//input[@type='file' and @multiple='multiple'])";
|
||||||
@ -28,6 +29,8 @@ public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessag
|
|||||||
String ITEM_TYPE_OF_MESSAGE = "//*[starts-with(@id,'item_') and @title= '%s']";
|
String ITEM_TYPE_OF_MESSAGE = "//*[starts-with(@id,'item_') and @title= '%s']";
|
||||||
String SENDER_ITEM = "item_0";
|
String SENDER_ITEM = "item_0";
|
||||||
String DELEGATE_BUTTON = "delegate_button_id";
|
String DELEGATE_BUTTON = "delegate_button_id";
|
||||||
|
String CREATE_COPY_BUTTON = "create_copy";
|
||||||
|
String CONFIRM_ATTACHMENT_BUTTON = "//app-actis-button//button[normalize-space()='Potvrdit']";
|
||||||
String DROPDOWN_CREATE_DUPLICATE_BUTTON = "//app-actis-button[@buttonid='create_copy']/following-sibling::button";
|
String DROPDOWN_CREATE_DUPLICATE_BUTTON = "//app-actis-button[@buttonid='create_copy']/following-sibling::button";
|
||||||
String SEND_TO_ANOTHER_DATA_BOX_BUTTON = "//app-actis-button//button[contains(., 'Do jiné datové schránky')]";
|
String SEND_TO_ANOTHER_DATA_BOX_BUTTON = "//app-actis-button//button[contains(., 'Do jiné datové schránky')]";
|
||||||
String UNIVERSAL_SINGLE_SELECT = "singleSelect";
|
String UNIVERSAL_SINGLE_SELECT = "singleSelect";
|
||||||
@ -35,6 +38,13 @@ public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessag
|
|||||||
String UNIVERSAL_SUBMIT_SINGLE_SELECT_BUTTON = "submitSingleSelect";
|
String UNIVERSAL_SUBMIT_SINGLE_SELECT_BUTTON = "submitSingleSelect";
|
||||||
String CONFIRM_BUTTON = "//button[normalize-space()='Potvrdit']";
|
String CONFIRM_BUTTON = "//button[normalize-space()='Potvrdit']";
|
||||||
String CHANGE_MESSAGE_TYPE = "change_message_type";
|
String CHANGE_MESSAGE_TYPE = "change_message_type";
|
||||||
|
String FIELD_VALIDATION_LABEL = "//b[text()='Kontrola polí']";
|
||||||
|
String FOLDER_FILE_NUMBER_XPATH = "//iq-select2[@id='folderFileNumber']//input";
|
||||||
|
String FOLDER_FILE_NUMBER_ITEM_0 = "(//iq-select2[@id='folderFileNumber']//div[@id='item_0'])";
|
||||||
|
String SAVE_CHECKED_FIELD = "save_checked_field";
|
||||||
|
|
||||||
|
@Click(value = ANSWER_BUTTON, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
NewOutgoingMessagePage clickAnswer();
|
||||||
|
|
||||||
@TypeInto(SUBJECT_INPUT)
|
@TypeInto(SUBJECT_INPUT)
|
||||||
NewIncomingMessagePage fillSubject(String subject);
|
NewIncomingMessagePage fillSubject(String subject);
|
||||||
@ -83,7 +93,7 @@ public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessag
|
|||||||
default NewIncomingMessagePage storeMessageId() {
|
default NewIncomingMessagePage storeMessageId() {
|
||||||
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
|
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
|
||||||
String messageId = endpoint.getText(MESSAGE_ID_SPAN).replaceAll("ID:(\\d+)", "$1");
|
String messageId = endpoint.getText(MESSAGE_ID_SPAN).replaceAll("ID:(\\d+)", "$1");
|
||||||
store(MESSAGE_ID_KEY, messageId);
|
store(INCOMING_MESSAGE_ID_KEY, messageId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +106,12 @@ public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessag
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Click(CREATE_COPY_BUTTON)
|
||||||
|
NewIncomingMessagePage clickCreateCopy();
|
||||||
|
|
||||||
|
@Click(value = CONFIRM_ATTACHMENT_BUTTON, by = Lookup.XPATH, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
NewIncomingMessagePage clickConfirmAttachment();
|
||||||
|
|
||||||
@Click(value = DROPDOWN_CREATE_DUPLICATE_BUTTON, by = Lookup.XPATH)
|
@Click(value = DROPDOWN_CREATE_DUPLICATE_BUTTON, by = Lookup.XPATH)
|
||||||
@Click(value = SEND_TO_ANOTHER_DATA_BOX_BUTTON, by = Lookup.XPATH)
|
@Click(value = SEND_TO_ANOTHER_DATA_BOX_BUTTON, by = Lookup.XPATH)
|
||||||
NewIncomingMessagePage sendToAnotherDataBox();
|
NewIncomingMessagePage sendToAnotherDataBox();
|
||||||
@ -114,4 +130,18 @@ public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessag
|
|||||||
|
|
||||||
@Click(CHANGE_MESSAGE_TYPE)
|
@Click(CHANGE_MESSAGE_TYPE)
|
||||||
NewIncomingMessagePage clickChangeMessageType();
|
NewIncomingMessagePage clickChangeMessageType();
|
||||||
|
|
||||||
|
@CustomAction
|
||||||
|
default NewIncomingMessagePage clickFolderFileNumber() {
|
||||||
|
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
|
||||||
|
endpoint.scrollIntoView(FIELD_VALIDATION_LABEL, Lookup.XPATH);
|
||||||
|
endpoint.click(() -> FOLDER_FILE_NUMBER_XPATH, Lookup.XPATH);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Click(value = FOLDER_FILE_NUMBER_ITEM_0, by = Lookup.XPATH, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
NewIncomingMessagePage clickFirstFolderFile();
|
||||||
|
|
||||||
|
@Click(value = SAVE_CHECKED_FIELD, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
NewIncomingMessagePage clickSaveCheckedField();
|
||||||
}
|
}
|
||||||
@ -13,9 +13,13 @@ import static cz.moneta.test.dsl.exevido.pages.NewOutgoingMessagePage.PAGE_LABEL
|
|||||||
@Wait(PAGE_LABEL_B)
|
@Wait(PAGE_LABEL_B)
|
||||||
public interface NewOutgoingMessagePage extends ExevidoWebFlow<NewOutgoingMessagePage>, StoreAccessor {
|
public interface NewOutgoingMessagePage extends ExevidoWebFlow<NewOutgoingMessagePage>, StoreAccessor {
|
||||||
|
|
||||||
String MESSAGE_ID_KEY = "MESSAGE_ID";
|
String OUTGOING_MESSAGE_ID_KEY = "OUTGOING_MESSAGE_ID";
|
||||||
String PDF_VIEWER_CONTENT_KEY = "PDF_VIEWER_CONTENT";
|
String PDF_VIEWER_CONTENT_KEY = "PDF_VIEWER_CONTENT";
|
||||||
String PAGE_LABEL_B = "outgoing_message_label";
|
String PAGE_LABEL_B = "outgoing_message_label";
|
||||||
|
String INSPECTION_BUTTON = "//button[normalize-space()='Kontrola']";
|
||||||
|
String SELECT_REVIEWER_INPUT = "//iq-select2[@id='singleSelect']//input[@type='text']";
|
||||||
|
String SELECT_REVIEWER = "//div[contains(@class,'select2-dropdown-item') and contains(@title, '%s')]";
|
||||||
|
String SUBMIT_SINGLE_SELECT = "submitSingleSelect";
|
||||||
String SAVE_CONCEPT_BUTTON = "save_concept";
|
String SAVE_CONCEPT_BUTTON = "save_concept";
|
||||||
String RECIPIENT_XPATH = "//iq-select2[@id='recipient_id']//input";
|
String RECIPIENT_XPATH = "//iq-select2[@id='recipient_id']//input";
|
||||||
String MULTIPLE_RECIPIENT_XPATH = "//input[@placeholder='Vyberte id příjemce']";
|
String MULTIPLE_RECIPIENT_XPATH = "//input[@placeholder='Vyberte id příjemce']";
|
||||||
@ -31,6 +35,7 @@ public interface NewOutgoingMessagePage extends ExevidoWebFlow<NewOutgoingMessag
|
|||||||
String TEMPLATE_FOOTER = "document-footer";
|
String TEMPLATE_FOOTER = "document-footer";
|
||||||
String PDF_TEMPLATE_GENERATING_BUTTON = "IncomingMessagesActionButton";
|
String PDF_TEMPLATE_GENERATING_BUTTON = "IncomingMessagesActionButton";
|
||||||
String EMPTY_TEMPLATE = "//ul[@id='pdf_templates_firstLevel']/li//li/a[text()='Prazdná šablona' or text()='Prázdná šablona MMB']";
|
String EMPTY_TEMPLATE = "//ul[@id='pdf_templates_firstLevel']/li//li/a[text()='Prazdná šablona' or text()='Prázdná šablona MMB']";
|
||||||
|
String APPLICATION_TEMPLATE = "//ul[@id='pdf_templates_secondLevel']//a[text()='Přihláška']";
|
||||||
String EDIT_TEMPLATE_BUTTON = "edit_attachment";
|
String EDIT_TEMPLATE_BUTTON = "edit_attachment";
|
||||||
String SAVE_TEMPLATE_XPATH = "//tbody[@id='attachment_table_body']//i[@title='Uložit']/..";
|
String SAVE_TEMPLATE_XPATH = "//tbody[@id='attachment_table_body']//i[@title='Uložit']/..";
|
||||||
String UNPACK_MESSAGE_INFORMATIONS = "unpack_message_informations";
|
String UNPACK_MESSAGE_INFORMATIONS = "unpack_message_informations";
|
||||||
@ -50,7 +55,20 @@ public interface NewOutgoingMessagePage extends ExevidoWebFlow<NewOutgoingMessag
|
|||||||
String BACK_BUTTON = "back_button";
|
String BACK_BUTTON = "back_button";
|
||||||
String PDF_VIEWER = "viewer";
|
String PDF_VIEWER = "viewer";
|
||||||
|
|
||||||
|
@Click(value = INSPECTION_BUTTON, by = Lookup.XPATH)
|
||||||
|
NewOutgoingMessagePage clickInspection();
|
||||||
|
|
||||||
|
@TypeInto(value = SELECT_REVIEWER_INPUT, by = Lookup.XPATH)
|
||||||
|
NewOutgoingMessagePage fillReviewer(String text);
|
||||||
|
|
||||||
|
@Click(value = SELECT_REVIEWER, by = Lookup.XPATH, isStringDynamicXpath = true, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
NewOutgoingMessagePage clickReviewer(String reviewer);
|
||||||
|
|
||||||
|
@Click(value = SUBMIT_SINGLE_SELECT, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
NewOutgoingMessagePage clickSubmitSingleSelect();
|
||||||
|
|
||||||
@TypeInto(value = RECIPIENT_XPATH, by = Lookup.XPATH, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
@TypeInto(value = RECIPIENT_XPATH, by = Lookup.XPATH, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
@KeyPress(value = Key.ENTER)
|
||||||
NewOutgoingMessagePage fillRecipient(String recipient);
|
NewOutgoingMessagePage fillRecipient(String recipient);
|
||||||
|
|
||||||
@TypeInto(value = MULTIPLE_RECIPIENT_XPATH, by = Lookup.XPATH, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
@TypeInto(value = MULTIPLE_RECIPIENT_XPATH, by = Lookup.XPATH, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
@ -93,6 +111,10 @@ public interface NewOutgoingMessagePage extends ExevidoWebFlow<NewOutgoingMessag
|
|||||||
andWait = @Wait(value = TEMPLATE_CREATING_ANNOUNCEMENT_XPATH, by = Lookup.XPATH, until = Until.GONE))
|
andWait = @Wait(value = TEMPLATE_CREATING_ANNOUNCEMENT_XPATH, by = Lookup.XPATH, until = Until.GONE))
|
||||||
NewOutgoingMessagePage clickEmptyTemplateMmb();
|
NewOutgoingMessagePage clickEmptyTemplateMmb();
|
||||||
|
|
||||||
|
@Click(value = APPLICATION_TEMPLATE, by = Lookup.XPATH, jsClick = true, andWait = @Wait(value = TEMPLATE_CREATING_ANNOUNCEMENT_XPATH, by = Lookup.XPATH, until = Until.GONE))
|
||||||
|
@Wait(value = GENERATE_PDF, by = Lookup.XPATH, until = Until.GONE)
|
||||||
|
NewOutgoingMessagePage clickApplication();
|
||||||
|
|
||||||
@Click(value = EDIT_TEMPLATE_BUTTON, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
@Click(value = EDIT_TEMPLATE_BUTTON, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
NewOutgoingMessagePage clickEditTemplate();
|
NewOutgoingMessagePage clickEditTemplate();
|
||||||
|
|
||||||
@ -179,7 +201,7 @@ public interface NewOutgoingMessagePage extends ExevidoWebFlow<NewOutgoingMessag
|
|||||||
|
|
||||||
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
|
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
|
||||||
String messageId = endpoint.getText(MESSAGE_ID_SPAN).replaceAll("ID:(\\d+)", "$1");
|
String messageId = endpoint.getText(MESSAGE_ID_SPAN).replaceAll("ID:(\\d+)", "$1");
|
||||||
store(MESSAGE_ID_KEY, messageId);
|
store(OUTGOING_MESSAGE_ID_KEY, messageId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,34 @@
|
|||||||
package cz.moneta.test.dsl.exevido.pages;
|
package cz.moneta.test.dsl.exevido.pages;
|
||||||
|
|
||||||
import cz.moneta.test.dsl.exevido.ExevidoWebFlow;
|
import cz.moneta.test.dsl.exevido.ExevidoWebFlow;
|
||||||
import cz.moneta.test.harness.support.web.Click;
|
import cz.moneta.test.dsl.exevido.components.ExevidoPanels;
|
||||||
import cz.moneta.test.harness.support.web.Lookup;
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
import cz.moneta.test.harness.support.web.Wait;
|
import cz.moneta.test.harness.endpoints.exevido.ExevidoEndpoint;
|
||||||
|
import cz.moneta.test.harness.support.web.*;
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.exevido.pages.OutgoingMessagesPage.PAGE_LABEL_XPATH;
|
import static cz.moneta.test.dsl.exevido.pages.OutgoingMessagesPage.PAGE_LABEL_XPATH;
|
||||||
|
|
||||||
@Wait(value = PAGE_LABEL_XPATH, by = Lookup.XPATH)
|
@Wait(value = PAGE_LABEL_XPATH, by = Lookup.XPATH)
|
||||||
public interface OutgoingMessagesPage extends ExevidoWebFlow<OutgoingMessagesPage> {
|
public interface OutgoingMessagesPage extends ExevidoWebFlow<OutgoingMessagesPage>, StoreAccessor {
|
||||||
|
|
||||||
String PAGE_LABEL_XPATH = "//b[contains(text(), 'Odchozí zprávy dle stavu')]";
|
String PAGE_LABEL_XPATH = "//b[contains(text(), 'Odchozí zprávy dle stavu')]";
|
||||||
String CREATE_NEW_OUTGOING_MESSAGE_BUTTON = "create_new_outgoing_message";
|
String CREATE_NEW_OUTGOING_MESSAGE_BUTTON = "create_new_outgoing_message";
|
||||||
|
String ID_MESSAGE_INPUT = "text_message_id";
|
||||||
|
String OUTGOING_MESSAGE_ROW = "outgoing_message_0_row";
|
||||||
|
|
||||||
@Click(CREATE_NEW_OUTGOING_MESSAGE_BUTTON)
|
@Click(CREATE_NEW_OUTGOING_MESSAGE_BUTTON)
|
||||||
NewOutgoingMessagePage clickCreateNewOutgoingMessage();
|
NewOutgoingMessagePage clickCreateNewOutgoingMessage();
|
||||||
|
|
||||||
|
@TypeInto(value = ID_MESSAGE_INPUT, clear = true)
|
||||||
|
@KeyPress(value = Key.ENTER, andWait = @Wait(value = ExevidoPanels.LOADER_DIV, until = Until.GONE))
|
||||||
|
OutgoingMessagesPage searchByMessageId(String id);
|
||||||
|
|
||||||
|
@CustomAction
|
||||||
|
default DetailOutgoingMessagePage clickOutgoingMessageRow(int timeout) {
|
||||||
|
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
|
||||||
|
endpoint.waitForElementAndRefresh(OUTGOING_MESSAGE_ROW, Lookup.ID, endpoint::refeshPage, timeout, 2);
|
||||||
|
endpoint.click(() -> OUTGOING_MESSAGE_ROW, Lookup.ID);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package cz.moneta.test.dsl.exevido.tasks;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.Harness;
|
||||||
|
import cz.moneta.test.dsl.exevido.pages.IncomingMessagesPage;
|
||||||
|
import cz.moneta.test.dsl.exevido.pages.NewIncomingMessagePage;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class CreateNewIncomingMessageTasks {
|
||||||
|
|
||||||
|
private final Harness harness;
|
||||||
|
|
||||||
|
public CreateNewIncomingMessageTasks(Harness harness) {
|
||||||
|
this.harness = harness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Function<IncomingMessagesPage, NewIncomingMessagePage> forInheritance(String subject, String sender, String attachment) {
|
||||||
|
return start -> start
|
||||||
|
.clickCreateNewIncomingMessage()
|
||||||
|
.fillSubject(subject)
|
||||||
|
.fillSender(sender)
|
||||||
|
.fillTypeMessage("D - Žádost [M] - MMB")
|
||||||
|
.uploadAttachment(attachment)
|
||||||
|
.clickSave()
|
||||||
|
.acceptAlertIfVisible()
|
||||||
|
.storeMessageId();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,4 +17,16 @@ public class ExevidoTasks {
|
|||||||
public SelectDataBoxTasks selectDataBox() {
|
public SelectDataBoxTasks selectDataBox() {
|
||||||
return new SelectDataBoxTasks(harness);
|
return new SelectDataBoxTasks(harness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CreateNewIncomingMessageTasks createNewIncomingMessageTasks() {
|
||||||
|
return new CreateNewIncomingMessageTasks(harness);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncomingMessageTasks incomingMessageTasks() {
|
||||||
|
return new IncomingMessageTasks(harness);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutgoingMessageTasks outgoingMessageTasks() {
|
||||||
|
return new OutgoingMessageTasks(harness);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package cz.moneta.test.dsl.exevido.tasks;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.Harness;
|
||||||
|
import cz.moneta.test.dsl.exevido.pages.NewIncomingMessagePage;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class IncomingMessageTasks {
|
||||||
|
|
||||||
|
private final Harness harness;
|
||||||
|
|
||||||
|
public IncomingMessageTasks(Harness harness) {
|
||||||
|
this.harness = harness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Function<NewIncomingMessagePage, NewIncomingMessagePage> selectFirstFolderFileAndSave() {
|
||||||
|
return start -> start
|
||||||
|
.clickFolderFileNumber()
|
||||||
|
.clickFirstFolderFile()
|
||||||
|
.clickSaveCheckedField();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package cz.moneta.test.dsl.exevido.tasks;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.Harness;
|
||||||
|
import cz.moneta.test.dsl.exevido.pages.NewOutgoingMessagePage;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class OutgoingMessageTasks {
|
||||||
|
|
||||||
|
private final Harness harness;
|
||||||
|
|
||||||
|
public OutgoingMessageTasks(Harness harness) {
|
||||||
|
this.harness = harness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Function<NewOutgoingMessagePage, NewOutgoingMessagePage> assignReviewerAndSubmit(String reviewer) {
|
||||||
|
return start -> start
|
||||||
|
.fillReviewer(reviewer)
|
||||||
|
.clickReviewer(reviewer)
|
||||||
|
.clickSubmitSingleSelect();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,10 +3,10 @@ package cz.moneta.test.dsl.imq;
|
|||||||
import cz.moneta.test.dsl.Harness;
|
import cz.moneta.test.dsl.Harness;
|
||||||
import cz.moneta.test.harness.endpoints.imq.ImqFirstVisionEndpoint;
|
import cz.moneta.test.harness.endpoints.imq.ImqFirstVisionEndpoint;
|
||||||
import cz.moneta.test.harness.endpoints.imq.ImqFirstVisionQueue;
|
import cz.moneta.test.harness.endpoints.imq.ImqFirstVisionQueue;
|
||||||
import cz.moneta.test.harness.messaging.ReceivedMessage;
|
import cz.moneta.test.harness.support.messaging.ReceivedMessage;
|
||||||
import cz.moneta.test.harness.messaging.exception.MessagingTimeoutException;
|
import cz.moneta.test.harness.support.messaging.exception.MessagingTimeoutException;
|
||||||
import cz.moneta.test.harness.support.messaging.ImqRequest;
|
import cz.moneta.test.harness.support.messaging.ImqRequest;
|
||||||
import cz.moneta.test.harness.messaging.MqMessageFormat;
|
import cz.moneta.test.harness.support.messaging.MqMessageFormat;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
package cz.moneta.test.dsl.monetaapiportal;
|
|
||||||
|
|
||||||
import cz.moneta.test.harness.support.web.Wait;
|
|
||||||
import cz.moneta.test.harness.support.web.WebFlow;
|
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.monetaapiportal.LoginPage.PAGE_LOGO;
|
|
||||||
|
|
||||||
@Wait(value = PAGE_LOGO)
|
|
||||||
public interface LoginPage extends WebFlow<LoginPage> {
|
|
||||||
|
|
||||||
String PAGE_LOGO = "provider-name";
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package cz.moneta.test.dsl.monetaapiportal;
|
package cz.moneta.test.dsl.monetaapiportal;
|
||||||
|
|
||||||
import cz.moneta.test.dsl.Harness;
|
import cz.moneta.test.dsl.Harness;
|
||||||
|
import cz.moneta.test.dsl.monetaapiportal.pages.LoginPage;
|
||||||
import cz.moneta.test.harness.endpoints.monetaapiportal.MonetaApiPortalEndpoint;
|
import cz.moneta.test.harness.endpoints.monetaapiportal.MonetaApiPortalEndpoint;
|
||||||
import cz.moneta.test.harness.support.web.Builders;
|
import cz.moneta.test.harness.support.web.Builders;
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
package cz.moneta.test.dsl.monetaapiportal.pages;
|
||||||
|
|
||||||
|
import cz.moneta.test.harness.support.web.Lookup;
|
||||||
|
import cz.moneta.test.harness.support.web.Wait;
|
||||||
|
import cz.moneta.test.harness.support.web.WebFlow;
|
||||||
|
|
||||||
|
import static cz.moneta.test.dsl.monetaapiportal.pages.LoginPage.MONETA_LOGO;
|
||||||
|
|
||||||
|
@Wait(value = MONETA_LOGO, waitSecondsForElement = 60, by = Lookup.XPATH)
|
||||||
|
public interface LoginPage extends WebFlow<LoginPage> {
|
||||||
|
|
||||||
|
String MONETA_LOGO = "//div[@class='header-nav-brand']";
|
||||||
|
|
||||||
|
}
|
||||||
@ -36,8 +36,8 @@ public interface DashboardPage extends NewIbPageFlow<DashboardPage>, HorizontalM
|
|||||||
String BANNER_SU_EUR = "//span[starts-with(text(), 'EUR spořicí účet s úrokem')]";
|
String BANNER_SU_EUR = "//span[starts-with(text(), 'EUR spořicí účet s úrokem')]";
|
||||||
String CARDS_BTN_XPATH = "//li[@data-testid='cards-link']";
|
String CARDS_BTN_XPATH = "//li[@data-testid='cards-link']";
|
||||||
String RTV_CARD = "//small[contains(., '%s')]";
|
String RTV_CARD = "//small[contains(., '%s')]";
|
||||||
String PENSION_CARD_XPATH = "//div[contains(@class,'productCard__header')][.//span[contains(., 'Penze')] and .//small[contains(., 'Doplňkové penzijní spoření')]]";
|
String PENSION_CARD_XPATH = "//small[contains(., 'Doplňkové penzijní spoření')]";
|
||||||
String PENSION_CARD_SAVED_TEXT_XPATH = "//div[contains(@class,'productCard__ballance__ledger')]//small[normalize-space(.)='Naspořeno']";
|
String PENSION_CARD_SAVED_TEXT_XPATH = "//*[@data-testid='TextComponent']//small[normalize-space(.)='Naspořeno']";
|
||||||
String USE_MOBILE_KEY_BUTTON_XPATH = "//button[@data-testid='buttonUseMobileKey']";
|
String USE_MOBILE_KEY_BUTTON_XPATH = "//button[@data-testid='buttonUseMobileKey']";
|
||||||
String CHECK_BOX_MOBILE_KEY_XPATH = "//span[@class='f-checkbox__indicator']";
|
String CHECK_BOX_MOBILE_KEY_XPATH = "//span[@class='f-checkbox__indicator']";
|
||||||
String CONFIRMATION_MOBILE_KEY_XPATH = "//button[@data-testid='confirmButton']";
|
String CONFIRMATION_MOBILE_KEY_XPATH = "//button[@data-testid='confirmButton']";
|
||||||
|
|||||||
@ -76,6 +76,7 @@ public interface SavingsPage extends NewIbPageFlow<SavingsPage>, StoreAccessor,
|
|||||||
@CheckElementPresent(RTV_DEPOSIT_BLUE_ALERT_TEXT_XPATH)
|
@CheckElementPresent(RTV_DEPOSIT_BLUE_ALERT_TEXT_XPATH)
|
||||||
SavingsPage checkRtvDepositBlueAlertText();
|
SavingsPage checkRtvDepositBlueAlertText();
|
||||||
|
|
||||||
|
@Wait(explicitWaitSeconds = 2)//wait z dôvodu, že pri rýchlom storne práve založenej TRN dochádza k častým pádom
|
||||||
@Click(value = RTV_SERVICING_STORNO_BUTTON)
|
@Click(value = RTV_SERVICING_STORNO_BUTTON)
|
||||||
RtvServicingPage clickOnStornoButton();
|
RtvServicingPage clickOnStornoButton();
|
||||||
|
|
||||||
|
|||||||
@ -144,6 +144,7 @@ public interface RtvServicingPage extends NewIbPageFlow<RtvServicingPage> {
|
|||||||
@Click(RTV_SERVICING_CANCEL_CONTINUE_BUTTON_XPATH)
|
@Click(RTV_SERVICING_CANCEL_CONTINUE_BUTTON_XPATH)
|
||||||
RtvServicingPage clickOnContinueRtvServicingCancelButton();
|
RtvServicingPage clickOnContinueRtvServicingCancelButton();
|
||||||
|
|
||||||
|
@Wait(explicitWaitSeconds = 4)//wait z dôvodu, že pri rýchlom storne práve založenej TRN dochádza k častým pádom
|
||||||
@Click(RTV_SERVICING_STORNO_BUTTON_ON_VICTORY)
|
@Click(RTV_SERVICING_STORNO_BUTTON_ON_VICTORY)
|
||||||
RtvServicingPage clickOnRtvServicingStornoButtonOnVictory();
|
RtvServicingPage clickOnRtvServicingStornoButtonOnVictory();
|
||||||
}
|
}
|
||||||
@ -11,7 +11,7 @@ public interface CardsSettingsPage extends NewIbPageFlow<CardsSettingsPage> {
|
|||||||
String CREDIT_CARDS_TAB_XPATH = "//span[@data-testid='credit-cards-tab' and text()='Kreditní']";
|
String CREDIT_CARDS_TAB_XPATH = "//span[@data-testid='credit-cards-tab' and text()='Kreditní']";
|
||||||
String NO_CREDIT_CARDS_XPATH = "//div[@data-testid='TextComponent' and text()='Momentálně nemáte žádné kreditní karty.']";
|
String NO_CREDIT_CARDS_XPATH = "//div[@data-testid='TextComponent' and text()='Momentálně nemáte žádné kreditní karty.']";
|
||||||
String DEBIT_CARDS_TAB_XPATH = "//span[@data-testid='debit-cards-tab' and text()='Debetní']";
|
String DEBIT_CARDS_TAB_XPATH = "//span[@data-testid='debit-cards-tab' and text()='Debetní']";
|
||||||
String DEBIT_CARDS_TO_THE_ACCOUNT_XPATH = "//span[@data-testid='TextComponent']/small[normalize-space(.)='Debetní karty k účtu']";
|
String DEBIT_CARDS_TO_THE_ACCOUNT_XPATH = "//td[h2//small[normalize-space()='Debetní karty k účtu']]";
|
||||||
String CARDS_TO_THE_ACCOUNT_XPATH = "//h5[@class='t-title t-title--h5 u-mb--0 u-mr--0' and text()='Karty k účtu (2)']";
|
String CARDS_TO_THE_ACCOUNT_XPATH = "//h5[@class='t-title t-title--h5 u-mb--0 u-mr--0' and text()='Karty k účtu (2)']";
|
||||||
String CARD_DETAIL_BUTTON_XPATH = "//div[@class='c-card u-p--xSmall u-pb--0 item-row']";
|
String CARD_DETAIL_BUTTON_XPATH = "//div[@class='c-card u-p--xSmall u-pb--0 item-row']";
|
||||||
String CARD_DETAIL_TITLE_XPATH = "//h3[@class='t-title t-title--h5 u-pl--large' and text()='Informace o kartě, nastavení']";
|
String CARD_DETAIL_TITLE_XPATH = "//h3[@class='t-title t-title--h5 u-pl--large' and text()='Informace o kartě, nastavení']";
|
||||||
@ -63,7 +63,7 @@ public interface CardsSettingsPage extends NewIbPageFlow<CardsSettingsPage> {
|
|||||||
String CARD_BLOCKING_VICTORY_TITLE_XPATH = "//h2[@class='t-title t-title--h4 styles_title__NAx0Q' and contains(., 'Kartu udržíme pod zámkem do')]";
|
String CARD_BLOCKING_VICTORY_TITLE_XPATH = "//h2[@class='t-title t-title--h4 styles_title__NAx0Q' and contains(., 'Kartu udržíme pod zámkem do')]";
|
||||||
String CARD_BLOCKING_VICTORY_TEXT_XPATH = "//p[@data-testid='TextComponent' and contains(normalize-space(.), 'Po tomto datu ji opět odblokujeme a vás informujeme SMS na číslo +420 702 111 111.') and contains(normalize-space(.), 'Můžete ji do té doby kdykoli odblokovat nebo trvale zablokovat.')]";
|
String CARD_BLOCKING_VICTORY_TEXT_XPATH = "//p[@data-testid='TextComponent' and contains(normalize-space(.), 'Po tomto datu ji opět odblokujeme a vás informujeme SMS na číslo +420 702 111 111.') and contains(normalize-space(.), 'Můžete ji do té doby kdykoli odblokovat nebo trvale zablokovat.')]";
|
||||||
String BACK_BUTTON_ON_VICTORY_SCREEN_XPATH = "//button[@data-testid='card-block-victoryNext' and text()='Zpět na kartu']";
|
String BACK_BUTTON_ON_VICTORY_SCREEN_XPATH = "//button[@data-testid='card-block-victoryNext' and text()='Zpět na kartu']";
|
||||||
String UNBLOCK_BUTTON_XPATH = "//button[@class='c-btn c-btn--small c-btn--border c-btn--primary c-compact-buttons__button' and text()='Odblokovat kartu']";
|
String UNBLOCK_BUTTON_XPATH = "//button[@type='button' and text()='Odblokovat kartu']";
|
||||||
String CARD_BLOCKING_TYPES_ON_UNBLOCK_SCREEN_XPATH = "//span[@class='f-radio__text' and contains(., 'Odblokovat') or contains(., 'Zablokovat a vydat novou') or contains(., 'Zablokovat a zrušit')]";
|
String CARD_BLOCKING_TYPES_ON_UNBLOCK_SCREEN_XPATH = "//span[@class='f-radio__text' and contains(., 'Odblokovat') or contains(., 'Zablokovat a vydat novou') or contains(., 'Zablokovat a zrušit')]";
|
||||||
String CARD_UNBLOCKING_VICTORY_TITLE_XPATH = "//h2[@class='t-title t-title--h4 styles_title__NAx0Q' and contains(., 'Karta je znovu aktivní')]";
|
String CARD_UNBLOCKING_VICTORY_TITLE_XPATH = "//h2[@class='t-title t-title--h4 styles_title__NAx0Q' and contains(., 'Karta je znovu aktivní')]";
|
||||||
String CARD_UNBLOCKING_VICTORY_TEXT_XPATH = "//p[@data-testid='TextComponent' and contains(., 'Můžete s ní začít okamžitě platit.')]";
|
String CARD_UNBLOCKING_VICTORY_TEXT_XPATH = "//p[@data-testid='TextComponent' and contains(., 'Můžete s ní začít okamžitě platit.')]";
|
||||||
@ -76,6 +76,8 @@ public interface CardsSettingsPage extends NewIbPageFlow<CardsSettingsPage> {
|
|||||||
String CREDIT_LIMIT_INCREASE_MODAL_XPATH = "//h2[@class='t-title t-title--h3 c-modal__title' and text()='Na této funkci pracujeme']";
|
String CREDIT_LIMIT_INCREASE_MODAL_XPATH = "//h2[@class='t-title t-title--h3 c-modal__title' and text()='Na této funkci pracujeme']";
|
||||||
String CREDIT_LIMIT_INCREASE_CLOSE_MODAL_BUTTON_XPATH = "//button[@class='c-btn c-btn--border c-btn--primary' and text()='Zavřít']";
|
String CREDIT_LIMIT_INCREASE_CLOSE_MODAL_BUTTON_XPATH = "//button[@class='c-btn c-btn--border c-btn--primary' and text()='Zavřít']";
|
||||||
String CREDIT_CARD_XPATH = "//small[normalize-space(.)='MoneyCard Smart']";
|
String CREDIT_CARD_XPATH = "//small[normalize-space(.)='MoneyCard Smart']";
|
||||||
|
String CANCEL_ACCOUNT = "//button[@data-testid='account-close' and text()='Zrušit tento běžný účet']";
|
||||||
|
String ACCOUNT_NUMBER = "//th[span[@data-testid='TextComponent' and text()='Číslo účtu']]";
|
||||||
|
|
||||||
@Click(CREDIT_CARDS_TAB_XPATH)
|
@Click(CREDIT_CARDS_TAB_XPATH)
|
||||||
CardsSettingsPage clickOnCreditCardsTab();
|
CardsSettingsPage clickOnCreditCardsTab();
|
||||||
@ -83,14 +85,14 @@ public interface CardsSettingsPage extends NewIbPageFlow<CardsSettingsPage> {
|
|||||||
@CheckElementPresent(NO_CREDIT_CARDS_XPATH)
|
@CheckElementPresent(NO_CREDIT_CARDS_XPATH)
|
||||||
CardsSettingsPage checkNoCreditCards();
|
CardsSettingsPage checkNoCreditCards();
|
||||||
|
|
||||||
@Click(DEBIT_CARDS_TAB_XPATH)
|
@Click(value = DEBIT_CARDS_TAB_XPATH, andWait = @Wait(explicitWaitSeconds = 1))
|
||||||
CardsSettingsPage clickOnDebitCardsTab();
|
CardsSettingsPage clickOnDebitCardsTab();
|
||||||
|
|
||||||
@Wait(value = DEBIT_CARDS_TO_THE_ACCOUNT_XPATH, until = Until.CLICKABLE)
|
@Wait(value = DEBIT_CARDS_TO_THE_ACCOUNT_XPATH, until = Until.CLICKABLE)
|
||||||
@Click(DEBIT_CARDS_TO_THE_ACCOUNT_XPATH)
|
@Click(value = DEBIT_CARDS_TO_THE_ACCOUNT_XPATH, andWait = @Wait(explicitWaitSeconds = 1))
|
||||||
CardsSettingsPage clickOnDebitCardsToTheAccount();
|
CardsSettingsPage clickOnDebitCardsToTheAccount();
|
||||||
|
|
||||||
@Wait(value = CARDS_TO_THE_ACCOUNT_XPATH, until = Until.CLICKABLE)
|
@Wait(value = CANCEL_ACCOUNT, until = Until.VISIBLE)
|
||||||
@Click(CARDS_TO_THE_ACCOUNT_XPATH)
|
@Click(CARDS_TO_THE_ACCOUNT_XPATH)
|
||||||
CardsSettingsPage clickOnCardsToTheAccount();
|
CardsSettingsPage clickOnCardsToTheAccount();
|
||||||
|
|
||||||
@ -98,7 +100,7 @@ public interface CardsSettingsPage extends NewIbPageFlow<CardsSettingsPage> {
|
|||||||
@Click(CARD_DETAIL_BUTTON_XPATH)
|
@Click(CARD_DETAIL_BUTTON_XPATH)
|
||||||
CardsSettingsPage clickOnCardDetail();
|
CardsSettingsPage clickOnCardDetail();
|
||||||
|
|
||||||
@Wait(value = CARD_DETAIL_TITLE_XPATH, until = Until.CLICKABLE)
|
@Wait(ACCOUNT_NUMBER)
|
||||||
@CheckElementPresent(CARD_DETAIL_TITLE_XPATH)
|
@CheckElementPresent(CARD_DETAIL_TITLE_XPATH)
|
||||||
CardsSettingsPage checkCardDetailTitle();
|
CardsSettingsPage checkCardDetailTitle();
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
package cz.moneta.test.dsl.oauth2.web;
|
|
||||||
|
|
||||||
import cz.moneta.test.harness.support.web.*;
|
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.oauth2.web.EchoPage.ECHO_TEXT;
|
|
||||||
|
|
||||||
@Wait(value = ECHO_TEXT, waitSecondsForElement = 40, by = Lookup.XPATH)
|
|
||||||
public interface EchoPage extends WebFlow<Oauth2WebTransitions> {
|
|
||||||
|
|
||||||
String ECHO_TEXT = "//pre[contains(text(),'Test echo service: OK')]";
|
|
||||||
}
|
|
||||||
@ -4,7 +4,6 @@ import cz.moneta.test.dsl.Harness;
|
|||||||
import cz.moneta.test.harness.endpoints.oauth2.web.Oauth2WebEndpoint;
|
import cz.moneta.test.harness.endpoints.oauth2.web.Oauth2WebEndpoint;
|
||||||
import cz.moneta.test.harness.support.web.Builders;
|
import cz.moneta.test.harness.support.web.Builders;
|
||||||
|
|
||||||
@Deprecated() // Needs completely review - If you want to work with this, please contact Harness admin firstly.
|
|
||||||
public class Oauth2Web {
|
public class Oauth2Web {
|
||||||
|
|
||||||
private final Harness harness;
|
private final Harness harness;
|
||||||
@ -13,21 +12,18 @@ public class Oauth2Web {
|
|||||||
this.harness = harness;
|
this.harness = harness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated() // Will be reviewed in the API Lab team.
|
||||||
public Oauth2WebTransitions onOauth2WebTransitions() {
|
public Oauth2WebTransitions onOauth2WebTransitions() {
|
||||||
harness.getEndpoint(Oauth2WebEndpoint.class).openApplication();
|
harness.getEndpoint(Oauth2WebEndpoint.class).openApplication();
|
||||||
return Builders.newWebFlowBuilder(Oauth2WebTransitions.class, harness.getEndpoint(Oauth2WebEndpoint.class), harness);
|
return Builders.newWebFlowBuilder(Oauth2WebTransitions.class, harness.getEndpoint(Oauth2WebEndpoint.class), harness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated() // Will be reviewed in the API Lab team.
|
||||||
public Oauth2WebTransitionsKyc onOauth2WebTransitionsKyc() {
|
public Oauth2WebTransitionsKyc onOauth2WebTransitionsKyc() {
|
||||||
harness.getEndpoint(Oauth2WebEndpoint.class).openApplication();
|
harness.getEndpoint(Oauth2WebEndpoint.class).openApplication();
|
||||||
return Builders.newWebFlowBuilder(Oauth2WebTransitionsKyc.class, harness.getEndpoint(Oauth2WebEndpoint.class), harness);
|
return Builders.newWebFlowBuilder(Oauth2WebTransitionsKyc.class, harness.getEndpoint(Oauth2WebEndpoint.class), harness);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Oauth2WebEcho onOauth2WebEcho() {
|
|
||||||
harness.getEndpoint(Oauth2WebEndpoint.class).openApplication();
|
|
||||||
return Builders.newWebFlowBuilder(Oauth2WebEcho.class, harness.getEndpoint(Oauth2WebEndpoint.class), harness);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Oauth2WebFederatedLogin onOauth2WebFederatedLogin() {
|
public Oauth2WebFederatedLogin onOauth2WebFederatedLogin() {
|
||||||
harness.getEndpoint(Oauth2WebEndpoint.class).openApplication();
|
harness.getEndpoint(Oauth2WebEndpoint.class).openApplication();
|
||||||
return Builders.newWebFlowBuilder(Oauth2WebFederatedLogin.class, harness.getEndpoint(Oauth2WebEndpoint.class), harness);
|
return Builders.newWebFlowBuilder(Oauth2WebFederatedLogin.class, harness.getEndpoint(Oauth2WebEndpoint.class), harness);
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
package cz.moneta.test.dsl.oauth2.web;
|
|
||||||
|
|
||||||
import cz.moneta.test.harness.context.StoreAccessor;
|
|
||||||
import cz.moneta.test.harness.endpoints.oauth2.web.Oauth2WebEndpoint;
|
|
||||||
import cz.moneta.test.harness.support.web.CustomAction;
|
|
||||||
import cz.moneta.test.harness.support.web.WebFlow;
|
|
||||||
|
|
||||||
public interface Oauth2WebEcho extends WebFlow<Oauth2WebEcho>, StoreAccessor {
|
|
||||||
String ECHO_PAGE_URL = "api/echo";
|
|
||||||
|
|
||||||
@CustomAction
|
|
||||||
default EchoPage callEcho() {
|
|
||||||
Oauth2WebEndpoint endpoint = getEndpoint(Oauth2WebEndpoint.class);
|
|
||||||
endpoint.changePath(ECHO_PAGE_URL);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +1,13 @@
|
|||||||
package cz.moneta.test.dsl.oauth2.web;
|
package cz.moneta.test.dsl.oauth2.web;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.oauth2.web.pages.FederatedLoginPage;
|
||||||
import cz.moneta.test.harness.context.StoreAccessor;
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
import cz.moneta.test.harness.endpoints.oauth2.web.Oauth2WebEndpoint;
|
import cz.moneta.test.harness.endpoints.oauth2.web.Oauth2WebEndpoint;
|
||||||
import cz.moneta.test.harness.support.web.CustomAction;
|
import cz.moneta.test.harness.support.web.CustomAction;
|
||||||
import cz.moneta.test.harness.support.web.WebFlow;
|
import cz.moneta.test.harness.support.web.WebFlow;
|
||||||
|
|
||||||
public interface Oauth2WebFederatedLogin extends WebFlow<Oauth2WebFederatedLogin>, StoreAccessor {
|
public interface Oauth2WebFederatedLogin extends WebFlow<Oauth2WebFederatedLogin>, StoreAccessor {
|
||||||
String FEDERATED_LOGIN_PAGE_URL = "oauth2/react/#/login/?client_name=Test&state=1234&scope=ALL&return_url=https.seznam.cz";
|
String FEDERATED_LOGIN_PAGE_URL = "#/login/?client_name=Test&state=1234&scope=ALL&return_url=https.seznam.cz";
|
||||||
|
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default FederatedLoginPage callFederatedLogin() {
|
default FederatedLoginPage callFederatedLogin() {
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
package cz.moneta.test.dsl.oauth2.web;
|
package cz.moneta.test.dsl.oauth2.web.pages;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.oauth2.web.Oauth2WebTransitions;
|
||||||
import cz.moneta.test.harness.support.web.Lookup;
|
import cz.moneta.test.harness.support.web.Lookup;
|
||||||
import cz.moneta.test.harness.support.web.Wait;
|
import cz.moneta.test.harness.support.web.Wait;
|
||||||
import cz.moneta.test.harness.support.web.WebFlow;
|
import cz.moneta.test.harness.support.web.WebFlow;
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.oauth2.web.FederatedLoginPage.MONETA_LOGO_IMG;
|
import static cz.moneta.test.dsl.oauth2.web.pages.FederatedLoginPage.MONETA_LOGO_IMG;
|
||||||
|
|
||||||
@Wait(value = MONETA_LOGO_IMG, waitSecondsForElement = 40, by = Lookup.XPATH)
|
@Wait(value = MONETA_LOGO_IMG, waitSecondsForElement = 40, by = Lookup.XPATH)
|
||||||
public interface FederatedLoginPage extends WebFlow<Oauth2WebTransitions> {
|
public interface FederatedLoginPage extends WebFlow<Oauth2WebTransitions> {
|
||||||
|
|
||||||
String MONETA_LOGO_IMG = "//img[@alt='MONETA logo']";
|
String MONETA_LOGO_IMG = "//img[@alt='MONETA Money Bank Logo']";
|
||||||
}
|
}
|
||||||
@ -35,54 +35,27 @@ public class FileForInputPreparation {
|
|||||||
try {
|
try {
|
||||||
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
|
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
|
||||||
while (line != null) {
|
while (line != null) {
|
||||||
if (line.contains("#LASTFIELD#")) {
|
if (lastField != null) {
|
||||||
line = line.replace("#LASTFIELD#", String.valueOf(lastField + 1));
|
line = line.replace("#LASTFIELD#", String.valueOf(lastField + 1));
|
||||||
}
|
}
|
||||||
if (line.contains("#DATETIME#")) {
|
|
||||||
line = line.replace("#DATETIME#", DateUtils.getFormattedTodayDateTime("yyyy-MM-dd'T'hh:mm:ss"));
|
line = line.replace("#DATETIME#", DateUtils.getFormattedTodayDateTime("yyyy-MM-dd'T'hh:mm:ss"));
|
||||||
}
|
|
||||||
if (line.contains("#YYYYMMDD#")) {
|
|
||||||
line = line.replace("#YYYYMMDD#", DateUtils.getFormattedTodayDate("yyyyMMdd"));
|
line = line.replace("#YYYYMMDD#", DateUtils.getFormattedTodayDate("yyyyMMdd"));
|
||||||
}
|
|
||||||
if (line.contains("#YYMMDD#")) {
|
|
||||||
line = line.replace("#YYMMDD#", DateUtils.getFormattedTodayDate("yyMMdd"));
|
line = line.replace("#YYMMDD#", DateUtils.getFormattedTodayDate("yyMMdd"));
|
||||||
}
|
|
||||||
if (line.contains("#YYYY-MM-DD#")) {
|
|
||||||
line = line.replace("#YYYY-MM-DD#", DateUtils.getFormattedTodayDate("yyyy-MM-dd"));
|
line = line.replace("#YYYY-MM-DD#", DateUtils.getFormattedTodayDate("yyyy-MM-dd"));
|
||||||
}
|
|
||||||
if (line.contains("#REF#")) {
|
|
||||||
line = line.replace("#REF#", String.valueOf(data.getTrxReference()));
|
line = line.replace("#REF#", String.valueOf(data.getTrxReference()));
|
||||||
}
|
|
||||||
if (line.contains("#IBAN#")) {
|
|
||||||
line = line.replace("#IBAN#", String.valueOf(data.getIban()));
|
line = line.replace("#IBAN#", String.valueOf(data.getIban()));
|
||||||
}
|
|
||||||
if (line.contains("#RANDOM#")) {
|
|
||||||
line = line.replace("#RANDOM#", String.valueOf(data.getRandom()));
|
line = line.replace("#RANDOM#", String.valueOf(data.getRandom()));
|
||||||
}
|
|
||||||
if (line.contains("#AMOUNT#")) {
|
|
||||||
line = line.replace("#AMOUNT#", String.valueOf(data.getAmount()));
|
line = line.replace("#AMOUNT#", String.valueOf(data.getAmount()));
|
||||||
}
|
|
||||||
if (line.contains("#AMOUNT1#")) {
|
|
||||||
line = line.replace("#AMOUNT1#", String.valueOf(data.getAmount1()));
|
line = line.replace("#AMOUNT1#", String.valueOf(data.getAmount1()));
|
||||||
}
|
|
||||||
if (line.contains("#CREDITOR#")) {
|
|
||||||
line = line.replace("#CREDITOR#", String.valueOf(data.getCreditorAcc()));
|
line = line.replace("#CREDITOR#", String.valueOf(data.getCreditorAcc()));
|
||||||
}
|
|
||||||
if (line.contains("#DEBTOR#")) {
|
|
||||||
line = line.replace("#DEBTOR#", String.valueOf(data.getDebtorAcc()));
|
line = line.replace("#DEBTOR#", String.valueOf(data.getDebtorAcc()));
|
||||||
}
|
|
||||||
if (line.contains("#BANKCODE#")) {
|
|
||||||
line = line.replace("#BANKCODE#", String.valueOf(data.getBankCode()));
|
line = line.replace("#BANKCODE#", String.valueOf(data.getBankCode()));
|
||||||
}
|
|
||||||
if (line.contains("#MESSAGEID#")) {
|
|
||||||
line = line.replace("#MESSAGEID#", String.valueOf(data.getMessageId()));
|
line = line.replace("#MESSAGEID#", String.valueOf(data.getMessageId()));
|
||||||
}
|
|
||||||
if (line.contains("#FEETYPE#")) {
|
|
||||||
line = line.replace("#FEETYPE#", String.valueOf(data.getFeeType()));
|
line = line.replace("#FEETYPE#", String.valueOf(data.getFeeType()));
|
||||||
}
|
|
||||||
if (line.contains("#HDTYPE#")) {
|
|
||||||
line = line.replace("#HDTYPE#", String.valueOf(data.getHdType()));
|
line = line.replace("#HDTYPE#", String.valueOf(data.getHdType()));
|
||||||
}
|
line = line.replace("#UETR#", String.valueOf(data.getUetr()));
|
||||||
|
line = line.replace("#CREATE_DATE#", DateUtils.getFormattedTodayDateTime("yyyy-MM-dd'T'hh:mm:ss") + "+00:00");
|
||||||
|
line = line.replace("#CREATE_DATETIME#", DateUtils.getFormattedTodayDateTime("yyyy-MM-dd'T'hh:mm:ss") + "+01:00");
|
||||||
|
|
||||||
writer.write(line);
|
writer.write(line);
|
||||||
writer.newLine();
|
writer.newLine();
|
||||||
|
|||||||
@ -13,6 +13,8 @@ import static cz.moneta.test.dsl.payment_engine.parts_of_menu.menu_search.Paymen
|
|||||||
|
|
||||||
@Wait({ID, SEARCH_BUTTON})
|
@Wait({ID, SEARCH_BUTTON})
|
||||||
public interface PaymentEngineSearchPage extends WebFlow<PaymentEngineSearchPage>, StoreAccessor {
|
public interface PaymentEngineSearchPage extends WebFlow<PaymentEngineSearchPage>, StoreAccessor {
|
||||||
|
|
||||||
|
String ADVANCED_FILTER = "//div[label[text()='Rozšířený filtr'] and @class=' xcheckbox-wrap']/a";
|
||||||
String ID = "//div[@id='Vyhledávání']//input[@name='field1#id']";
|
String ID = "//div[@id='Vyhledávání']//input[@name='field1#id']";
|
||||||
String DEBTOR_ACC = "//div[@id='Vyhledávání']//input[@name='field1#orAccIdent']";
|
String DEBTOR_ACC = "//div[@id='Vyhledávání']//input[@name='field1#orAccIdent']";
|
||||||
String SETTLEMENT_FROM = "//input[@name='field1#settDate']//following-sibling::input";
|
String SETTLEMENT_FROM = "//input[@name='field1#settDate']//following-sibling::input";
|
||||||
@ -28,6 +30,7 @@ public interface PaymentEngineSearchPage extends WebFlow<PaymentEngineSearchPage
|
|||||||
String REASON_IMG = REASON + "/following-sibling::img";
|
String REASON_IMG = REASON + "/following-sibling::img";
|
||||||
String REASON_FILLED = "//input[@name='field1#queueReason' and not(@value='')]";
|
String REASON_FILLED = "//input[@name='field1#queueReason' and not(@value='')]";
|
||||||
String SELECTION_DIV = "//div[text()='%s']";
|
String SELECTION_DIV = "//div[text()='%s']";
|
||||||
|
String UETR_INPUT = "//input[@name='field1#uetr']";
|
||||||
String SEARCH_BUTTON = "//div[@id = 'Vyhledávání']//button[text() = 'Hledat']/../..";
|
String SEARCH_BUTTON = "//div[@id = 'Vyhledávání']//button[text() = 'Hledat']/../..";
|
||||||
String SEARCH_FORM_BUTTON = "//button[@class='x-btn-text grid-filter-collapse']";
|
String SEARCH_FORM_BUTTON = "//button[@class='x-btn-text grid-filter-collapse']";
|
||||||
String CHECK_SELECTED_TRANSACTION_DATA_PATH = "//*[contains(@class,'x-grid3-row-selected')]//*[contains(text(),'%s')]";
|
String CHECK_SELECTED_TRANSACTION_DATA_PATH = "//*[contains(@class,'x-grid3-row-selected')]//*[contains(text(),'%s')]";
|
||||||
@ -36,7 +39,7 @@ public interface PaymentEngineSearchPage extends WebFlow<PaymentEngineSearchPage
|
|||||||
String TRANSACTION_FILES = "//a[text()='Soubory']";
|
String TRANSACTION_FILES = "//a[text()='Soubory']";
|
||||||
String TRANSACTION_LIFE_CYCLE = "//a[text()='Životní cyklus']";
|
String TRANSACTION_LIFE_CYCLE = "//a[text()='Životní cyklus']";
|
||||||
String CLOSE_TAB_BUTTON = "//a[@class='x-tab-strip-close']";
|
String CLOSE_TAB_BUTTON = "//a[@class='x-tab-strip-close']";
|
||||||
String TRANSACTION_ID_KEY = "TRANSACTION_ID_KEY";
|
String TRANSACTION_ID_KEY = "TRANSACTION_ID";
|
||||||
String TRANSACTION_ID_XPATH = "//div[@class='x-panel-body x-panel-body-noheader x-border-layout-ct']//div[contains(@class,'x-grid3-row-selected')]//div[@class='x-grid3-cell-inner x-grid3-col-2']";
|
String TRANSACTION_ID_XPATH = "//div[@class='x-panel-body x-panel-body-noheader x-border-layout-ct']//div[contains(@class,'x-grid3-row-selected')]//div[@class='x-grid3-cell-inner x-grid3-col-2']";
|
||||||
String EQUIVALENT_AMOUNT_KEY = "EQUIVALENT_AMOUNT_KEY";
|
String EQUIVALENT_AMOUNT_KEY = "EQUIVALENT_AMOUNT_KEY";
|
||||||
String EQUIVALENT_AMOUNT_EUR_XPATH = "//div[@class='x-grid3-scroller']//div[text()='EUR']/../following-sibling::td[contains(@class, 'x-grid3-td-11')]/div";
|
String EQUIVALENT_AMOUNT_EUR_XPATH = "//div[@class='x-grid3-scroller']//div[text()='EUR']/../following-sibling::td[contains(@class, 'x-grid3-td-11')]/div";
|
||||||
@ -48,6 +51,9 @@ public interface PaymentEngineSearchPage extends WebFlow<PaymentEngineSearchPage
|
|||||||
@TypeInto(value = ID, clear = true)
|
@TypeInto(value = ID, clear = true)
|
||||||
PaymentEngineSearchPage typeId(String id);
|
PaymentEngineSearchPage typeId(String id);
|
||||||
|
|
||||||
|
@Click(ADVANCED_FILTER)
|
||||||
|
PaymentEngineSearchPage clickAdvancedFilter();
|
||||||
|
|
||||||
@Wait(value = DEBTOR_ACC, until = Until.VISIBLE)
|
@Wait(value = DEBTOR_ACC, until = Until.VISIBLE)
|
||||||
@TypeInto(DEBTOR_ACC)
|
@TypeInto(DEBTOR_ACC)
|
||||||
PaymentEngineSearchPage typeDebtorAcc(String debtorAcc);
|
PaymentEngineSearchPage typeDebtorAcc(String debtorAcc);
|
||||||
@ -74,6 +80,9 @@ public interface PaymentEngineSearchPage extends WebFlow<PaymentEngineSearchPage
|
|||||||
@Click(value = SELECTION_DIV, isStringDynamicXpath = true, andWait = @Wait(value = REASON_FILLED, until = Until.PRESENT_IN_DOM, explicitWaitSeconds = 1))
|
@Click(value = SELECTION_DIV, isStringDynamicXpath = true, andWait = @Wait(value = REASON_FILLED, until = Until.PRESENT_IN_DOM, explicitWaitSeconds = 1))
|
||||||
PaymentEngineSearchPage selectReason(String reason);
|
PaymentEngineSearchPage selectReason(String reason);
|
||||||
|
|
||||||
|
@TypeInto(UETR_INPUT)
|
||||||
|
PaymentEngineSearchPage fillUetr(String uetr);
|
||||||
|
|
||||||
@Wait(value = SEARCH_BUTTON, until = Until.VISIBLE)
|
@Wait(value = SEARCH_BUTTON, until = Until.VISIBLE)
|
||||||
@Click(value = SEARCH_BUTTON, andWait = @Wait(value = AJAX_LOADING, until = Until.GONE))
|
@Click(value = SEARCH_BUTTON, andWait = @Wait(value = AJAX_LOADING, until = Until.GONE))
|
||||||
PaymentEngineSearchPage clickSearch();
|
PaymentEngineSearchPage clickSearch();
|
||||||
@ -121,6 +130,6 @@ public interface PaymentEngineSearchPage extends WebFlow<PaymentEngineSearchPage
|
|||||||
PaymentEngineSearchPageLifeCycle clickLifeCycle();
|
PaymentEngineSearchPageLifeCycle clickLifeCycle();
|
||||||
|
|
||||||
@CheckElementContent(value = FRONT_LABEL, isStringDynamicXpath = true)
|
@CheckElementContent(value = FRONT_LABEL, isStringDynamicXpath = true)
|
||||||
PaymentEngineSearchPage checkExpectedFrontValue(String transactionId, String expectedFrontValue);
|
PaymentEngineSearchPage checkExpectedFrontValueByTransactionId(String transactionId, String expectedFrontValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -997,4 +997,14 @@ public class PaymentEngineTasks {
|
|||||||
harness.withPaymentEngine().closePaymentEngine();
|
harness.withPaymentEngine().closePaymentEngine();
|
||||||
harness.log("Previous Authorization For Direct Debit was not found.");
|
harness.log("Previous Authorization For Direct Debit was not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Function<PaymentEngineHomePage, PaymentEngineSearchPage> checkTransactionStateByUetr(String uetr) {
|
||||||
|
return start -> start
|
||||||
|
.search()
|
||||||
|
.clickAdvancedFilter()
|
||||||
|
.fillUetr(uetr)
|
||||||
|
.clickSearch()
|
||||||
|
.storeSelectedTransactionId()
|
||||||
|
.waitForStatus(this.harness, TransactionReasonPAE.INGOING_ARCHIV);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package cz.moneta.test.dsl.payment_engine_mq;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum MessagingType {
|
||||||
|
MT("MT"),
|
||||||
|
MX("MX"),
|
||||||
|
T2("T2"),
|
||||||
|
MT101("MT101"),
|
||||||
|
RESP("RESPONS");
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
MessagingType(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
package cz.moneta.test.dsl.payment_engine_mq;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.Harness;
|
||||||
|
import cz.moneta.test.harness.constants.HarnessConfigConstants;
|
||||||
|
import cz.moneta.test.harness.endpoints.payment_engine.PaeMqEndpoint;
|
||||||
|
import cz.moneta.test.harness.support.auth.AuthSupport;
|
||||||
|
import cz.moneta.test.harness.support.auth.Credentials;
|
||||||
|
import cz.moneta.test.harness.support.rest.RawRestRequest;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class PaeMqBuilder {
|
||||||
|
private final Harness harness;
|
||||||
|
|
||||||
|
public PaeMqBuilder(Harness harness) {
|
||||||
|
this.harness = harness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RawRestRequest.Request prepareRequest(MessagingType messagingType) {
|
||||||
|
PaeMqEndpoint endpoint = harness.getEndpoint(PaeMqEndpoint.class);
|
||||||
|
String environment = harness.getConfig(HarnessConfigConstants.ENVIRONMENT_TYPE);
|
||||||
|
String qmgr = resolveQueueManager(environment);
|
||||||
|
String path = preparePath(messagingType, qmgr, environment);
|
||||||
|
RawRestRequest.Request request = RawRestRequest.jsonBuilder(endpoint)
|
||||||
|
.withPath(path)
|
||||||
|
.withHeader("Authorization", getTokenFromCredentials());
|
||||||
|
return addDefaultHeaders(request, qmgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RawRestRequest.Request addDefaultHeaders(RawRestRequest.Request request, String qmgr) {
|
||||||
|
return request
|
||||||
|
.withHeader("Content-Type", "text/plain")
|
||||||
|
.withHeader("ibm-mq-rest-csrf-token", "blank")
|
||||||
|
.withHeader("ibm-mq-md-persistence", "persistent")
|
||||||
|
.withHeader("ibm-mq-md-replyto", "REPLYQ")
|
||||||
|
.withHeader("ibm-mq-md-replytoqmgr", qmgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTokenFromCredentials() {
|
||||||
|
Credentials cred = AuthSupport.getCredentials("pae-mq", harness);
|
||||||
|
return "Basic " + Base64.getEncoder().encodeToString((cred.getUsername() + ":" + cred.getPassword()).getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String preparePath(MessagingType messagingType, String qmgr, String environment) {
|
||||||
|
String envPae = environment.equals("tst1") ? "TST" : "UAT";
|
||||||
|
return String.format("qmgr/%s/queue/SAA.PAYHUB.%s.IN.%s/message", qmgr, messagingType.getValue(), envPae);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveQueueManager(String environment) {
|
||||||
|
return environment.equals("tst1") ? "MSWIFTT" : "MSWIFTU";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,62 +0,0 @@
|
|||||||
package cz.moneta.test.dsl.ufo.operations.client;
|
|
||||||
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.shared.topmenu.XXX702_SharedTopMenu;
|
|
||||||
import cz.moneta.test.harness.support.web.*;
|
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.ufo.operations.client.ApplicationListPage.LOAD_ALL_BUTTON;
|
|
||||||
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
|
||||||
|
|
||||||
@Wait(LOAD_ALL_BUTTON)
|
|
||||||
public interface ApplicationListPage extends WebFlow<ApplicationListPage>, XXX702_SharedTopMenu<ApplicationListPage> {
|
|
||||||
String LOAD_ALL_BUTTON = "XXX702_T001_B027";
|
|
||||||
String DETAIL_BUTTON = "XXX702_T001_P045-1";
|
|
||||||
String LOAD_BUTTON = "XXX702_T001_B026";
|
|
||||||
String COPY_BUTTON = "XXX702_T001_B034";
|
|
||||||
String FINISH_BUTTON = "XXX702_T001_B029";
|
|
||||||
String DECISION_BUTTON = "XXX702_T001_B030";
|
|
||||||
String STORNO_BUTTON = "XXX702_T001_B028";
|
|
||||||
String CLIENT_DETAIL = "//button [contains(@title, '[XXX702_T001_I006]')]";
|
|
||||||
|
|
||||||
@CheckElementContent("XXX702_T001_L303-1")
|
|
||||||
ApplicationListPage assertFirstApplicationProductType(String firstApplicationProductType);
|
|
||||||
|
|
||||||
@CheckElementContent("XXX702_T001_L305-1")
|
|
||||||
ApplicationListPage assertFirstApplicationRequestedAmount(String firstApplicationRequestedAmount);
|
|
||||||
|
|
||||||
@CheckElementContent("XXX702_T001_L306-1")
|
|
||||||
ApplicationListPage assertFirstApplicationApprovedAmount(String firstApplicationApprovedAmount);
|
|
||||||
|
|
||||||
@Wait(explicitWaitSeconds = 1) // There is a moment when list is full of some random items, can't think of better way to track it
|
|
||||||
@CheckElementContent("XXX702_T001_L285-1")
|
|
||||||
ApplicationListPage assertFirstApplicationState(String firstApplicationState);
|
|
||||||
|
|
||||||
@CheckElementContent("XXX702_T001_L310-1")
|
|
||||||
ApplicationListPage assertFirstApplicationChannel(String channel);
|
|
||||||
|
|
||||||
@CheckElementPresent(DETAIL_BUTTON)
|
|
||||||
ApplicationListPage assertApplicationDetailButton();
|
|
||||||
|
|
||||||
@CheckElementPresent(LOAD_BUTTON)
|
|
||||||
ApplicationListPage assertApplicationLoadButton();
|
|
||||||
|
|
||||||
@CheckElementPresent(LOAD_ALL_BUTTON)
|
|
||||||
ApplicationListPage assertApplicationLoadAllButton();
|
|
||||||
|
|
||||||
@CheckElementPresent(COPY_BUTTON)
|
|
||||||
ApplicationListPage assertApplicationCopyButton();
|
|
||||||
|
|
||||||
@CheckElementPresent(FINISH_BUTTON)
|
|
||||||
ApplicationListPage assertApplicationFinishButton();
|
|
||||||
|
|
||||||
@CheckElementPresent(DECISION_BUTTON)
|
|
||||||
ApplicationListPage assertApplicationDecisionButton();
|
|
||||||
|
|
||||||
@CheckElementPresent(STORNO_BUTTON)
|
|
||||||
ApplicationListPage assertApplicationStornoButton();
|
|
||||||
|
|
||||||
@Wait(value = LOAD_IMG_DIV_CLASS, until = Until.GONE, by = Lookup.CLASSNAME)
|
|
||||||
@Click(value = CLIENT_DETAIL, by = Lookup.XPATH)
|
|
||||||
STS701_S002_ClientDetailPage clickClientDetail();
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,21 +1,19 @@
|
|||||||
package cz.moneta.test.dsl.ufo.operations.client.clientDetail;
|
package cz.moneta.test.dsl.ufo.operations.client.clientDetail;
|
||||||
|
|
||||||
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
import cz.moneta.test.dsl.ufo.operations.shared.topmenu.XXX702_SharedTopMenu;
|
||||||
import cz.moneta.test.harness.support.web.*;
|
import cz.moneta.test.harness.support.web.*;
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_AdcProductsPanel.ADC_PRODUCT;
|
import static cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_AdcProductsPanel.ADC_PRODUCT;
|
||||||
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
||||||
|
|
||||||
@Wait(value = ADC_PRODUCT)
|
@Wait(value = ADC_PRODUCT)
|
||||||
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE)
|
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE)
|
||||||
public interface STS701_S002_AdcProductsPanel extends STS701_S002_ClientDetailPage, STS701_S002_InfoServiceExpressSettings, STS701_S002_InfoServiceOrderDetail, STS701_S002_InfoServiceOrdersList {
|
public interface STS701_S002_AdcProductsPanel extends XXX702_SharedTopMenu<STS701_S002_AdcProductsPanel>, STS701_S002_InfoServiceExpressSettings, STS701_S002_InfoServiceOrderDetail, STS701_S002_InfoServiceOrdersList {
|
||||||
String ADC_PRODUCT = "STS701_S002_C018";
|
String ADC_PRODUCT = "STS701_S002_C018";
|
||||||
String CANCEL_INTERNET_BANK_BUTTON = "STS701_S002_B048";
|
String CANCEL_INTERNET_BANK_BUTTON = "STS701_S002_B048";
|
||||||
String CANCEL_BANK_CLIENT_BUTTON = "STS701_S002_B060";
|
String CANCEL_BANK_CLIENT_BUTTON = "STS701_S002_B060";
|
||||||
String FIRST_CANCEL_SMART_BANK_XPATH = "(//img[contains(@id, 'STS701_S002_P005') and not(contains(@style,'display: none;'))])[1]";
|
String FIRST_CANCEL_SMART_BANK_XPATH = "(//img[contains(@id, 'STS701_S002_P005') and not(contains(@style,'display: none;'))])[1]";
|
||||||
String FIRST_SMART_BANK_CHECKBOX = FIRST_CANCEL_SMART_BANK_XPATH + "/../../..//input";
|
String FIRST_SMART_BANK_CHECKBOX = FIRST_CANCEL_SMART_BANK_XPATH + "/../../..//input";
|
||||||
String STATUS_MESSAGE_DIV = "XXX702_T001_L107";
|
|
||||||
|
|
||||||
@Click(CANCEL_INTERNET_BANK_BUTTON)
|
@Click(CANCEL_INTERNET_BANK_BUTTON)
|
||||||
@AcceptAlert(waitSecondsForAlert = 5)
|
@AcceptAlert(waitSecondsForAlert = 5)
|
||||||
@ -34,13 +32,6 @@ public interface STS701_S002_AdcProductsPanel extends STS701_S002_ClientDetailPa
|
|||||||
@Click(value = FIRST_SMART_BANK_CHECKBOX, by = Lookup.XPATH)
|
@Click(value = FIRST_SMART_BANK_CHECKBOX, by = Lookup.XPATH)
|
||||||
STS701_S002_AdcProductsPanel clickFirstSmartBank();
|
STS701_S002_AdcProductsPanel clickFirstSmartBank();
|
||||||
|
|
||||||
@CustomAction
|
@CheckElementContent(STATUS_BAR)
|
||||||
default STS701_S002_AdcProductsPanel checkStatusMessage(String expectedStatusMessage) {
|
STS701_S002_AdcProductsPanel checkStatusMessage(String expectedStatusMessage);
|
||||||
UfoEndpoint endpoint = this.getEndpoint(UfoEndpoint.class);
|
|
||||||
endpoint.waitForElementsToLoad(5, Until.VISIBLE, STATUS_MESSAGE_DIV);
|
|
||||||
String fullText = endpoint.getText(STATUS_MESSAGE_DIV);
|
|
||||||
String textWithoutTime = fullText.replaceFirst("^\\d{2}:\\d{2}:\\d{2}", "");
|
|
||||||
Assertions.assertTrue(textWithoutTime.contains(expectedStatusMessage));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -2,7 +2,6 @@ package cz.moneta.test.dsl.ufo.operations.client.clientDetail;
|
|||||||
|
|
||||||
import cz.moneta.test.dsl.ufo.banka.pages.common.pages.TIS701_S004_ConfirmationOfAccountHolding;
|
import cz.moneta.test.dsl.ufo.banka.pages.common.pages.TIS701_S004_ConfirmationOfAccountHolding;
|
||||||
import cz.moneta.test.dsl.ufo.banka.pages.main.client.settings.EVY701_S001_StatementsDistributionPage;
|
import cz.moneta.test.dsl.ufo.banka.pages.main.client.settings.EVY701_S001_StatementsDistributionPage;
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.ApplicationListPage;
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.NewProductsByNameUfoOps;
|
import cz.moneta.test.dsl.ufo.operations.client.NewProductsByNameUfoOps;
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.NewProductsUfoOps;
|
import cz.moneta.test.dsl.ufo.operations.client.NewProductsUfoOps;
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.STO702_S002_ApproveAlreadyReadPage;
|
import cz.moneta.test.dsl.ufo.operations.client.STO702_S002_ApproveAlreadyReadPage;
|
||||||
@ -14,34 +13,23 @@ import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
|||||||
import cz.moneta.test.harness.support.web.*;
|
import cz.moneta.test.harness.support.web.*;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage.*;
|
import static cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage.*;
|
||||||
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
||||||
|
|
||||||
@Wait(LIST_OF_OFFERS)
|
@Wait(LIST_OF_OFFERS)
|
||||||
@Wait(value = LIST_OF_PRODUCTS, by = Lookup.XPATH)
|
@Wait(value = LIST_OF_PRODUCTS, by = Lookup.XPATH)
|
||||||
@Wait(value = {CIF_DIV, RC_DIV})
|
@Wait(value = {CLIENT_CIF_LABEL, CLIENT_RC_LABEL})
|
||||||
@Wait(value = APPLICATIONS_BUTTON, by = Lookup.XPATH)
|
@Wait(value = APPLICATIONS_PANEL_XPATH, by = Lookup.XPATH)
|
||||||
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE, waitSecondsForElement = 80)
|
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE, waitSecondsForElement = 80)
|
||||||
public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS701_S002_ClientDetailPage>, XXX702_SharedTopMenu<STS701_S002_ClientDetailPage> {
|
public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS701_S002_ClientDetailPage>, XXX702_SharedTopMenu<STS701_S002_ClientDetailPage> {
|
||||||
|
|
||||||
String CURRENT_ACCOUNT_NUMBER_KEY = "CURRENT_ACCOUNT_NUMBER";
|
String CURRENT_ACCOUNT_NUMBER_KEY = "CURRENT_ACCOUNT_NUMBER";
|
||||||
String CIF_STORE_KEY = "CIF";
|
|
||||||
String ACTUAL_ADDRESS_KEY = "ACTUAL_ADDRESS";
|
String ACTUAL_ADDRESS_KEY = "ACTUAL_ADDRESS";
|
||||||
String CIF_DIV = "XXX702_T002_L101";
|
|
||||||
String RC_DIV = "XXX702_T001_L009";
|
|
||||||
String CREATE_NEW_BUTTON = "STS701_S002_B001";
|
String CREATE_NEW_BUTTON = "STS701_S002_B001";
|
||||||
String APPLICATIONS_BUTTON = "//button[text()='Žádosti']";
|
|
||||||
String NEW_PRODUCT_GENERAL_XPATH = "//input[@value='%1$s']";
|
String NEW_PRODUCT_GENERAL_XPATH = "//input[@value='%1$s']";
|
||||||
String NEW_PRODUCT_BY_NAME_GENERAL_XPATH = "//table[@id='STS701_S002_G002_UfoTable']//td[text()='%1$s']";
|
String NEW_PRODUCT_BY_NAME_GENERAL_XPATH = "//table[@id='STS701_S002_G002_UfoTable']//td[text()='%1$s']";
|
||||||
String LIST_OF_OFFERS = "STS701_S002_V002";
|
String LIST_OF_OFFERS = "STS701_S002_V002";
|
||||||
String LIST_OF_PRODUCTS = "//fieldset[@id='STS701_S002_Y002']/legend[text()='Produkty']";
|
String LIST_OF_PRODUCTS = "//fieldset[@id='STS701_S002_Y002']/legend[text()='Produkty']";
|
||||||
String BACK_OFFER_MANUAL_BUTTON = "ZAS701_S002_P007";
|
|
||||||
String LIST_CARDS_BUTTON = "STS701_S002_I021";
|
|
||||||
String BACK_LIST_CARDS_BUTTON = "OPK730_S001_B001";
|
|
||||||
String CHANGE_DISTRIBUTION_BUTTON = "STS701_S002_I058";
|
String CHANGE_DISTRIBUTION_BUTTON = "STS701_S002_I058";
|
||||||
String BACK_CHANGE_DISTRIBUTION_BUTTON = "EVY701_S001_B002";
|
String BACK_CHANGE_DISTRIBUTION_BUTTON = "EVY701_S001_B002";
|
||||||
String ACCOUNT_LIST_XPATH = "//button[contains(@title, 'STS701_S002_I029')]";
|
String ACCOUNT_LIST_XPATH = "//button[contains(@title, 'STS701_S002_I029')]";
|
||||||
@ -50,22 +38,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
String ADC_PANEL_XPATH = "//button[contains(@title, 'STS701_S002_I187')]";
|
String ADC_PANEL_XPATH = "//button[contains(@title, 'STS701_S002_I187')]";
|
||||||
String CLIENT_DETAIL_XPATH = "//button[contains(@title, 'STS701_S002_I009')]";
|
String CLIENT_DETAIL_XPATH = "//button[contains(@title, 'STS701_S002_I009')]";
|
||||||
String TREE_CREDIT_CARD_XPATH = "//span[contains(text(), 'Kredit')]";
|
String TREE_CREDIT_CARD_XPATH = "//span[contains(text(), 'Kredit')]";
|
||||||
String CLIENT_CONSENTS_BUTTON = "XXX702_T001_P046";
|
|
||||||
String SALE_BUTTON = "//button[contains(@title, '[XXX702_T001_I010]')]";
|
|
||||||
String SALE_TAB = "XXX702_T001_L337";
|
|
||||||
String CONTACT_INFORMATION = "//button [contains(@title, '[XXX702_T001_I011]')]";
|
|
||||||
String ADDRESS_TABLE = "XXX702_T001_G003_UfoTable";
|
|
||||||
String OFFERS_TABLE = "//button[contains(@title, '[XXX702_T001_I014]')]";
|
|
||||||
String OFFERS_CHECK_BOX = "XXX702_T001_H001_AKT";
|
|
||||||
String DEMAND_TABLE = "//button[contains(@title, '[XXX702_T001_I015]')]";
|
|
||||||
String DEMAND_DESCRIPTION = "XXX702_T001_L269-1";
|
|
||||||
String DEMAND_DESCRIPTION_SECOND_ROW = "XXX702_T001_L269-2";
|
|
||||||
String TASKS_TABLE = "//button[contains(@title, '[XXX702_T001_I016]')]";
|
|
||||||
String TASKS_LABLE = "XXX702_T001_G009_UfoTable_clone";
|
|
||||||
String REQUEST_TABLE = "//button[contains(@title, '[XXX702_T001_I018')]";
|
|
||||||
String REQUEST_RADIO = "XXX702_T001_R008_1";
|
|
||||||
String NOTIFICATION_TABLE = "//button[contains(@title, '[XXX702_T001_I019]')]";
|
|
||||||
String NOTIFICATION_LABEL = "XXX702_T001_L226";
|
|
||||||
String FUTURE_OPPORTUNITY = "//button[contains(@title, '[STS701_S002_I003]')]";
|
String FUTURE_OPPORTUNITY = "//button[contains(@title, '[STS701_S002_I003]')]";
|
||||||
String OPPORTUNITY_TABLE = "STS701_S002_G011_clone";
|
String OPPORTUNITY_TABLE = "STS701_S002_G011_clone";
|
||||||
String RETENTION = "//button[contains(@title, '[STS701_S002_I004]')]";
|
String RETENTION = "//button[contains(@title, '[STS701_S002_I004]')]";
|
||||||
@ -122,7 +94,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
String NUMBER_OF_CARD_DIV = "STS701_S002_L110";
|
String NUMBER_OF_CARD_DIV = "STS701_S002_L110";
|
||||||
String FIRST_CURRENT_ACCOUNT_COMBOBOX = "STS701_S002_C004";
|
String FIRST_CURRENT_ACCOUNT_COMBOBOX = "STS701_S002_C004";
|
||||||
String CHECK_ACCOUNT_STATE = "STS701_S002_L174";
|
String CHECK_ACCOUNT_STATE = "STS701_S002_L174";
|
||||||
String REFRESH_REQUIREMENT_BUTTON = "XXX702_T001_B001";
|
|
||||||
String BANK_BACK_OFFICE_BUTTON = "STS701_S002_I017";
|
String BANK_BACK_OFFICE_BUTTON = "STS701_S002_I017";
|
||||||
String TRANSFER_TO_530 = "STS701_S002_I106";
|
String TRANSFER_TO_530 = "STS701_S002_I106";
|
||||||
String TRANSFER_TO_535 = "STS701_S002_I108";
|
String TRANSFER_TO_535 = "STS701_S002_I108";
|
||||||
@ -133,31 +104,23 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
String INFO_SERVICE_SPAN = "//span[contains(text(), 'InfoServis')]";
|
String INFO_SERVICE_SPAN = "//span[contains(text(), 'InfoServis')]";
|
||||||
String BANK_CLIENT_SPAN = "//span[contains(text(), 'BankKlient')]";
|
String BANK_CLIENT_SPAN = "//span[contains(text(), 'BankKlient')]";
|
||||||
String SMART_BANK_SPAN = "//span[contains(text(), 'Smart Banka')]";
|
String SMART_BANK_SPAN = "//span[contains(text(), 'Smart Banka')]";
|
||||||
String CANCEL_ADC_PRODUCT_DIV = "XXX702_T001_L107";
|
|
||||||
String INTERNET_BANK_DISPO_XPATH_CLIENT_SPAN = "//span[contains(text(), 'Internet Banka heslo/MK - Dispomodel (Aktivní)')]";
|
String INTERNET_BANK_DISPO_XPATH_CLIENT_SPAN = "//span[contains(text(), 'Internet Banka heslo/MK - Dispomodel (Aktivní)')]";
|
||||||
String INTERNET_BANK_DISPO_XPATH = "//*[@id=\"STS701_S002_T001\"]/div/div[3]/div[2]/div[1]/div/span/span";
|
String INTERNET_BANK_DISPO_XPATH = "//*[@id=\"STS701_S002_T001\"]/div/div[3]/div[2]/div[1]/div/span/span";
|
||||||
String SMART_BANK_DISPO_XPATH = "//*[@id=\"STS701_S002_T001\"]/div/div[3]/div[2]/div[2]/div/span/span";
|
String SMART_BANK_DISPO_XPATH = "//*[@id=\"STS701_S002_T001\"]/div/div[3]/div[2]/div[2]/div/span/span";
|
||||||
String DETAIL_OF_ADC_PRODUCT = "STS701_S002_B007";
|
String DETAIL_OF_ADC_PRODUCT = "STS701_S002_B007";
|
||||||
String PLACE_OF_BUSINESS = "STS701_S002_L093";
|
String PLACE_OF_BUSINESS = "STS701_S002_L093";
|
||||||
|
|
||||||
String BACK_BUTTON = "HPO703_S001_S014";
|
|
||||||
String LOANS_BUTTON_XPATH = "//button[contains(@title, '[STS701_S002_I064]')]";
|
String LOANS_BUTTON_XPATH = "//button[contains(@title, '[STS701_S002_I064]')]";
|
||||||
String RC_OF_HOLDER_LABEL = "STS701_S002_L157";
|
String RC_OF_HOLDER_LABEL = "STS701_S002_L157";
|
||||||
String NUMBER_OF_LOANS_ACCOUNT = "STS701_S002_L269";
|
String NUMBER_OF_LOANS_ACCOUNT = "STS701_S002_L269";
|
||||||
String REQUEST_LIST = "//button[contains(@title, '[XXX702_T001_I015]')]";
|
String COMPLAINT_BUTTON = "STS701_S002_I126";
|
||||||
String FIRST_REQUEST_DONE_DIV = "XXX702_T001_L312-1";
|
String COMPLAINTS_AND_OTHER_CLAIMS_BUTTON = "STS701_S002_I139";
|
||||||
String COMPLAINT_BUTTON = "STS701_S002_I158";
|
|
||||||
String PRINT_OF_LETTER = "STS701_S002_I049";
|
String PRINT_OF_LETTER = "STS701_S002_I049";
|
||||||
String CONFIRMATION_ABOUT_ACCOUNT = "STS701_S002_I137";
|
String CONFIRMATION_ABOUT_ACCOUNT = "STS701_S002_I137";
|
||||||
String DATE_IN_REQUIREMENT_DIV = "XXX702_T001_L312-1";
|
|
||||||
String RELATIONSHIP_LABEL = "XXX702_T001_L230";
|
|
||||||
String ACCOUNT_BLOCKING_DIV = "STS701_S002_I156";
|
String ACCOUNT_BLOCKING_DIV = "STS701_S002_I156";
|
||||||
String TRANSACTIONS_SETTINGS = "STS701_S002_I093";
|
String TRANSACTIONS_SETTINGS = "STS701_S002_I093";
|
||||||
String PAYMENTS_THROUGH_MOTO_INTERNET_DIV = "STS701_S002_L145";
|
String PAYMENTS_THROUGH_MOTO_INTERNET_DIV = "STS701_S002_L145";
|
||||||
String DEBIT_CARD_SENDING_ADDRESS_STREET_LABEL = "STS701_S002_L160";
|
String DEBIT_CARD_SENDING_ADDRESS_STREET_LABEL = "STS701_S002_L160";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Click(SENDING_OFFERS_MANUALS)
|
@Click(SENDING_OFFERS_MANUALS)
|
||||||
ZAS701_S002_SendingOffersAndManualsPage clickSendingOffers();
|
ZAS701_S002_SendingOffersAndManualsPage clickSendingOffers();
|
||||||
|
|
||||||
@ -285,7 +248,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
|
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default STS701_S002_ClientDetailPage storeAccountNumber() {
|
default STS701_S002_ClientDetailPage storeAccountNumber() {
|
||||||
|
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
||||||
String accountNumber = endpoint.getText(TREE_ACCOUNT_XPATH, Lookup.XPATH).replaceAll(".*\\((\\d+);.*", "$1");
|
String accountNumber = endpoint.getText(TREE_ACCOUNT_XPATH, Lookup.XPATH).replaceAll(".*\\((\\d+);.*", "$1");
|
||||||
this.store(CURRENT_ACCOUNT_NUMBER_KEY, accountNumber);
|
this.store(CURRENT_ACCOUNT_NUMBER_KEY, accountNumber);
|
||||||
@ -322,30 +284,12 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
@CheckElementPresent(FRAUD_TABLE)
|
@CheckElementPresent(FRAUD_TABLE)
|
||||||
STS701_S002_ClientDetailPage assertFraudTable();
|
STS701_S002_ClientDetailPage assertFraudTable();
|
||||||
|
|
||||||
@CheckElementPresent(NOTIFICATION_LABEL)
|
|
||||||
STS701_S002_ClientDetailPage assertNotice();
|
|
||||||
|
|
||||||
@CheckElementPresent(CREDIT_CARD_CONTRACT_STATE_LABEL)
|
@CheckElementPresent(CREDIT_CARD_CONTRACT_STATE_LABEL)
|
||||||
STS701_S002_ClientDetailPage assertCreditCardContractState();
|
STS701_S002_ClientDetailPage assertCreditCardContractState();
|
||||||
|
|
||||||
@CheckElementPresent(RETENTION_TABLE)
|
@CheckElementPresent(RETENTION_TABLE)
|
||||||
STS701_S002_ClientDetailPage assertRetentionTable();
|
STS701_S002_ClientDetailPage assertRetentionTable();
|
||||||
|
|
||||||
@CheckElementPresent(REQUEST_RADIO)
|
|
||||||
STS701_S002_ClientDetailPage assertRequestRadio();
|
|
||||||
|
|
||||||
@CheckElementPresent(TASKS_LABLE)
|
|
||||||
STS701_S002_ClientDetailPage assetTasksTable();
|
|
||||||
|
|
||||||
@CheckElementPresent(DEMAND_DESCRIPTION)
|
|
||||||
STS701_S002_ClientDetailPage assertDemandDescription();
|
|
||||||
|
|
||||||
@CheckElementPresent(OFFERS_CHECK_BOX)
|
|
||||||
STS701_S002_ClientDetailPage assertOffers();
|
|
||||||
|
|
||||||
@CheckElementPresent(ADDRESS_TABLE)
|
|
||||||
STS701_S002_ClientDetailPage assertAddress();
|
|
||||||
|
|
||||||
@CheckElementPresent(OPPORTUNITY_TABLE)
|
@CheckElementPresent(OPPORTUNITY_TABLE)
|
||||||
STS701_S002_ClientDetailPage assertOpportunityTable();
|
STS701_S002_ClientDetailPage assertOpportunityTable();
|
||||||
|
|
||||||
@ -369,13 +313,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
@CheckElementContent("STS701_S002_L833")
|
@CheckElementContent("STS701_S002_L833")
|
||||||
STS701_S002_ClientDetailPage assertAdcProductList(String adcProductList);
|
STS701_S002_ClientDetailPage assertAdcProductList(String adcProductList);
|
||||||
|
|
||||||
@Wait(value = SALE_TAB, until = Until.VISIBLE)
|
|
||||||
@CheckElementContent("XXX702_T001_L337")
|
|
||||||
STS701_S002_ClientDetailPage assertTabPanelSale(String saleTabPanel);
|
|
||||||
|
|
||||||
@CheckElementContent(RC_DIV)
|
|
||||||
STS701_S002_ClientDetailPage checkClientRc(String rc);
|
|
||||||
|
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default STS701_S002_ClientDetailPage clickTreeCreditCard() {
|
default STS701_S002_ClientDetailPage clickTreeCreditCard() {
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
||||||
@ -405,31 +342,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
@Click(value = FUTURE_OPPORTUNITY, by = Lookup.XPATH)
|
@Click(value = FUTURE_OPPORTUNITY, by = Lookup.XPATH)
|
||||||
STS701_S002_ClientDetailPage clickFutureOpportunity();
|
STS701_S002_ClientDetailPage clickFutureOpportunity();
|
||||||
|
|
||||||
@Click(value = NOTIFICATION_TABLE, by = Lookup.XPATH)
|
|
||||||
STS701_S002_ClientDetailPage clickNotification();
|
|
||||||
|
|
||||||
@Click(value = REQUEST_TABLE, by = Lookup.XPATH)
|
|
||||||
STS701_S002_ClientDetailPage clickRequests();
|
|
||||||
|
|
||||||
@Click(value = TASKS_TABLE, by = Lookup.XPATH)
|
|
||||||
STS701_S002_ClientDetailPage clickTasks();
|
|
||||||
|
|
||||||
@Click(value = DEMAND_TABLE, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, until = Until.GONE, by = Lookup.CLASSNAME))
|
|
||||||
STS701_S002_ClientDetailPage clickDemand();
|
|
||||||
|
|
||||||
@Click(value = OFFERS_TABLE, by = Lookup.XPATH)
|
|
||||||
STS701_S002_ClientDetailPage clickOffers();
|
|
||||||
|
|
||||||
@Click(value = CONTACT_INFORMATION, by = Lookup.XPATH)
|
|
||||||
STS701_S002_ClientDetailPage clickContactInformation();
|
|
||||||
|
|
||||||
@Click(value = SALE_BUTTON, by = Lookup.XPATH)
|
|
||||||
STS701_S002_ClientDetailPage clickSaleButton();
|
|
||||||
|
|
||||||
@Wait(value = CLIENT_CONSENTS_BUTTON, until = Until.CLICKABLE)
|
|
||||||
@Click(CLIENT_CONSENTS_BUTTON)
|
|
||||||
STO704_S001_ClientConsentsPage clickClientConsents();
|
|
||||||
|
|
||||||
@Click(value = CLIENT_DETAIL_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
@Click(value = CLIENT_DETAIL_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
STS701_S002_ClientDetailPage clickClientDetailList();
|
STS701_S002_ClientDetailPage clickClientDetailList();
|
||||||
|
|
||||||
@ -452,18 +364,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
@Click(CREATE_NEW_BUTTON)
|
@Click(CREATE_NEW_BUTTON)
|
||||||
STO702_S002_ApproveAlreadyReadPage confirmAddProduct();
|
STO702_S002_ApproveAlreadyReadPage confirmAddProduct();
|
||||||
|
|
||||||
@Click(value = APPLICATIONS_BUTTON, by = Lookup.XPATH)
|
|
||||||
ApplicationListPage openApplicationList();
|
|
||||||
|
|
||||||
@Click(value = BACK_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
|
||||||
STS701_S002_ClientDetailPage clickBack();
|
|
||||||
|
|
||||||
@Click(LIST_CARDS_BUTTON)
|
|
||||||
STS701_S002_ClientDetailPage clickCards();
|
|
||||||
|
|
||||||
@Click(BACK_LIST_CARDS_BUTTON)
|
|
||||||
STS701_S002_ClientDetailPage clickBackListCards();
|
|
||||||
|
|
||||||
@Wait(value = LOAD_IMG_DIV_CLASS, until = Until.GONE, by = Lookup.CLASSNAME)
|
@Wait(value = LOAD_IMG_DIV_CLASS, until = Until.GONE, by = Lookup.CLASSNAME)
|
||||||
@Click(CHANGE_DISTRIBUTION_BUTTON)
|
@Click(CHANGE_DISTRIBUTION_BUTTON)
|
||||||
STS701_S002_ClientDetailPage clickDistribution();
|
STS701_S002_ClientDetailPage clickDistribution();
|
||||||
@ -501,17 +401,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
@CheckElementContent(CHECK_ACCOUNT_STATE)
|
@CheckElementContent(CHECK_ACCOUNT_STATE)
|
||||||
STS701_S002_ClientDetailPage checkAccountState(String state);
|
STS701_S002_ClientDetailPage checkAccountState(String state);
|
||||||
|
|
||||||
@CheckElementContent(DEMAND_DESCRIPTION)
|
|
||||||
STS701_S002_ClientDetailPage checkDemandDescriptionFirstRow(String description);
|
|
||||||
|
|
||||||
@CheckElementContent(DEMAND_DESCRIPTION_SECOND_ROW)
|
|
||||||
STS701_S002_ClientDetailPage checkDemandDescriptionSecondRow(String description);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Click(value = REFRESH_REQUIREMENT_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, until = Until.GONE, by = Lookup.CLASSNAME))
|
|
||||||
STS701_S002_ClientDetailPage clickRefreshRequirementButton();
|
|
||||||
|
|
||||||
@Wait(value = INTERNET_BANK_DISPO_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
@Wait(value = INTERNET_BANK_DISPO_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
||||||
@Click(value = INTERNET_BANK_DISPO_XPATH, by = Lookup.XPATH)
|
@Click(value = INTERNET_BANK_DISPO_XPATH, by = Lookup.XPATH)
|
||||||
STS701_S002_ClientDetailPage clickIB();
|
STS701_S002_ClientDetailPage clickIB();
|
||||||
@ -545,15 +434,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
@Click(value = ACCOUNT_BENEFITS)
|
@Click(value = ACCOUNT_BENEFITS)
|
||||||
RET701_S003_AccountBenefits clickAccountBenefits();
|
RET701_S003_AccountBenefits clickAccountBenefits();
|
||||||
|
|
||||||
@CustomAction
|
|
||||||
default STS701_S002_ClientDetailPage acceptAlertIsVisible() {
|
|
||||||
UfoEndpoint endpoint = this.getEndpoint(UfoEndpoint.class);
|
|
||||||
if (endpoint.isAlertPresent(10)) {
|
|
||||||
endpoint.acceptAlert(5);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@AcceptAlert(waitSecondsForAlert = 10, expectedAlertText = "Uzavřený účet s debetním zůstatkem")
|
@AcceptAlert(waitSecondsForAlert = 10, expectedAlertText = "Uzavřený účet s debetním zůstatkem")
|
||||||
STS701_S002_ClientDetailPage acceptAlert();
|
STS701_S002_ClientDetailPage acceptAlert();
|
||||||
|
|
||||||
@ -564,6 +444,7 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
default UKO735_S001_ClaimsAndComplaints clickComplaint() {
|
default UKO735_S001_ClaimsAndComplaints clickComplaint() {
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
||||||
endpoint.click(() -> COMPLAINT_BUTTON);
|
endpoint.click(() -> COMPLAINT_BUTTON);
|
||||||
|
endpoint.click(() -> COMPLAINTS_AND_OTHER_CLAIMS_BUTTON);
|
||||||
endpoint.focusToNewPopup(10);
|
endpoint.focusToNewPopup(10);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -602,10 +483,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
@ExecuteJavaScript("navigator.clipboard.writeText(document.getElementById('" + NUMBER_OF_LOANS_ACCOUNT + "').textContent)")
|
@ExecuteJavaScript("navigator.clipboard.writeText(document.getElementById('" + NUMBER_OF_LOANS_ACCOUNT + "').textContent)")
|
||||||
STS701_S002_ClientDetailPage copyLoansNumberToClipboard();
|
STS701_S002_ClientDetailPage copyLoansNumberToClipboard();
|
||||||
|
|
||||||
@Wait(value = CIF_DIV, until = Until.VISIBLE)
|
|
||||||
@ExecuteJavaScript("navigator.clipboard.writeText(document.getElementById('" + CIF_DIV + "').textContent)")
|
|
||||||
STS701_S002_ClientDetailPage copyCifNumberToClipboard();
|
|
||||||
|
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default STS701_S002_AdcProductsPanel clickSmartBank() {
|
default STS701_S002_AdcProductsPanel clickSmartBank() {
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
||||||
@ -615,9 +492,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CheckElementContent(CANCEL_ADC_PRODUCT_DIV)
|
|
||||||
STS701_S002_ClientDetailPage checkCancelAdcProduct(String content);
|
|
||||||
|
|
||||||
@CheckElementContent(PLACE_OF_BUSINESS)
|
@CheckElementContent(PLACE_OF_BUSINESS)
|
||||||
STS701_S002_ClientDetailPage checkPlaceOfBusiness(String place);
|
STS701_S002_ClientDetailPage checkPlaceOfBusiness(String place);
|
||||||
|
|
||||||
@ -642,50 +516,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE)
|
|
||||||
@CustomAction
|
|
||||||
default STS701_S002_ClientDetailPage checkIfStatusBarIsOverwritten(String textInStatusBar) {
|
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
|
||||||
String fullText = endpoint.getText(CANCEL_ADC_PRODUCT_DIV);
|
|
||||||
String textWithoutTime = fullText.replaceFirst("^\\d{2}:\\d{2}:\\d{2}", "").replaceFirst("(ID:).*$", "");
|
|
||||||
Assertions.assertTrue(textWithoutTime.contains(textInStatusBar));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CustomAction
|
|
||||||
default STS701_S002_ClientDetailPage checkDateInRequirement() {
|
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
|
||||||
String dateInReq = endpoint.getText(DATE_IN_REQUIREMENT_DIV);
|
|
||||||
String dateInReqNoTime = dateInReq.replaceFirst("\\s\\d{1,2}:\\d{2}:\\d{2}", "");
|
|
||||||
Assertions.assertTrue(dateInReqNoTime.contains(endpoint.getText(ACTUAL_DATE_DIV)));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CustomAction
|
|
||||||
default STS701_S002_ClientDetailPage checkStatusMessageSendingManuals(String expectedStatusMessage) {
|
|
||||||
UfoEndpoint endpoint = this.getEndpoint(UfoEndpoint.class);
|
|
||||||
endpoint.waitForElementsToLoad(10, Until.VISIBLE, CANCEL_ADC_PRODUCT_DIV);
|
|
||||||
String fullText = endpoint.getText(CANCEL_ADC_PRODUCT_DIV);
|
|
||||||
String textWithoutTime = fullText.replaceFirst("^\\d{2}:\\d{2}:\\d{2}", "");
|
|
||||||
Assertions.assertTrue(textWithoutTime.contains(expectedStatusMessage));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Click(value = REQUEST_LIST, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, until = Until.GONE, by = Lookup.CLASSNAME))
|
|
||||||
STS701_S002_ClientDetailPage clickRequestsList();
|
|
||||||
|
|
||||||
@CustomAction
|
|
||||||
default STS701_S002_ClientDetailPage checkPerformedRequest(String expectedDescription) {
|
|
||||||
UfoEndpoint endpoint = this.getEndpoint(UfoEndpoint.class);
|
|
||||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("H:mm:ss");
|
|
||||||
LocalTime fistTime = LocalTime.parse(endpoint.getText(CANCEL_ADC_PRODUCT_DIV).split(" ")[0], formatter);
|
|
||||||
LocalTime secondTime = LocalTime.parse(endpoint.getText(FIRST_REQUEST_DONE_DIV).split(" ")[1], formatter);
|
|
||||||
long diffInSeconds = Duration.between(fistTime, secondTime).getSeconds();
|
|
||||||
Assertions.assertTrue(diffInSeconds <= 1);
|
|
||||||
Assertions.assertEquals(endpoint.getText(DEMAND_DESCRIPTION), expectedDescription);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default STS701_S002_ClientDetailPage scrollToSendingOffersManuals() {
|
default STS701_S002_ClientDetailPage scrollToSendingOffersManuals() {
|
||||||
UfoEndpoint endpoint = this.getEndpoint(UfoEndpoint.class);
|
UfoEndpoint endpoint = this.getEndpoint(UfoEndpoint.class);
|
||||||
@ -693,13 +523,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CheckElementContent(RELATIONSHIP_LABEL)
|
|
||||||
STS701_S002_ClientDetailPage assertRelationship(String relationship);
|
|
||||||
|
|
||||||
@Wait(value = CIF_DIV, until = Until.VISIBLE)
|
|
||||||
@StoreElementContent(storeKey = CIF_STORE_KEY, value = CIF_DIV)
|
|
||||||
STS701_S002_ClientDetailPage storeCifNumber();
|
|
||||||
|
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default STS701_S002_ClientDetailPage checkInfoServiceProductIsNotPresent() {
|
default STS701_S002_ClientDetailPage checkInfoServiceProductIsNotPresent() {
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package cz.moneta.test.dsl.ufo.operations.client.clientDetail;
|
package cz.moneta.test.dsl.ufo.operations.client.clientDetail;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.ufo.operations.shared.topmenu.XXX702_SharedTopMenu;
|
||||||
import cz.moneta.test.harness.context.StoreAccessor;
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
||||||
import cz.moneta.test.harness.support.web.*;
|
import cz.moneta.test.harness.support.web.*;
|
||||||
@ -10,7 +11,6 @@ import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_D
|
|||||||
public interface STS701_S002_InfoServiceOrdersList extends StoreAccessor {
|
public interface STS701_S002_InfoServiceOrdersList extends StoreAccessor {
|
||||||
|
|
||||||
String CANCEL_INFO_SERVICE_BUTTON = "STS701_S002_B081";
|
String CANCEL_INFO_SERVICE_BUTTON = "STS701_S002_B081";
|
||||||
String CANCEL_INFO_SERVICE_DIV = "XXX702_T001_L107";
|
|
||||||
String ORDER_DETAIL_ACCOUNTS_BUTTON = "STS701_S002_P012-%s";
|
String ORDER_DETAIL_ACCOUNTS_BUTTON = "STS701_S002_P012-%s";
|
||||||
String ORDER_DETAIL_CARDS_BUTTON = "STS701_S002_P014-%s";
|
String ORDER_DETAIL_CARDS_BUTTON = "STS701_S002_P014-%s";
|
||||||
String ORDER_DETAIL_OTHERS_BUTTON = "STS701_S002_P016-%s";
|
String ORDER_DETAIL_OTHERS_BUTTON = "STS701_S002_P016-%s";
|
||||||
@ -28,7 +28,7 @@ public interface STS701_S002_InfoServiceOrdersList extends StoreAccessor {
|
|||||||
endpoint.acceptAlert(5);
|
endpoint.acceptAlert(5);
|
||||||
endpoint.waitForElementsToLoad(5, Lookup.CLASSNAME, Until.GONE, LOAD_IMG_DIV_CLASS);
|
endpoint.waitForElementsToLoad(5, Lookup.CLASSNAME, Until.GONE, LOAD_IMG_DIV_CLASS);
|
||||||
endpoint.sendKeysOneAtATime(Key.PAGE_UP);
|
endpoint.sendKeysOneAtATime(Key.PAGE_UP);
|
||||||
endpoint.checkElementContent(CANCEL_INFO_SERVICE_DIV, "Zrušení objednávek proběhlo v pořádku.");
|
endpoint.checkElementContent(XXX702_SharedTopMenu.STATUS_BAR, "Zrušení objednávek proběhlo v pořádku.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package cz.moneta.test.dsl.ufo.operations.client.product;
|
|||||||
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_AdcProductsPanel;
|
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_AdcProductsPanel;
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
||||||
|
import cz.moneta.test.dsl.ufo.operations.shared.topmenu.XXX702_SharedTopMenu;
|
||||||
import cz.moneta.test.harness.context.StoreAccessor;
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
||||||
import cz.moneta.test.harness.support.web.*;
|
import cz.moneta.test.harness.support.web.*;
|
||||||
@ -10,20 +11,15 @@ import org.junit.Assert;
|
|||||||
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
||||||
|
|
||||||
@Wait(value = ADC739_S001_IBSBPage.CLIENTS_NAME, until = Until.VISIBLE)
|
@Wait(value = ADC739_S001_IBSBPage.CLIENTS_NAME, until = Until.VISIBLE)
|
||||||
public interface ADC739_S001_IBSBPage extends WebFlow<ADC739_S001_IBSBPage>, StoreAccessor {
|
public interface ADC739_S001_IBSBPage extends WebFlow<ADC739_S001_IBSBPage>, XXX702_SharedTopMenu<ADC739_S001_IBSBPage>, StoreAccessor {
|
||||||
|
|
||||||
String DETAIL_EDISPONENT = "ADC739_S001_P001-1";
|
String DETAIL_EDISPONENT = "ADC739_S001_P001-1";
|
||||||
String CLIENTS_NAME = "ADC739_S001_L004-1";
|
String CLIENTS_NAME = "ADC739_S001_L004-1";
|
||||||
String SEND_LOGIN_PASSWORD_SMS = "ADC739_S001_B003";
|
String SEND_LOGIN_PASSWORD_SMS = "ADC739_S001_B003";
|
||||||
String STATUS_BAR = "XXX702_T001_L107";
|
|
||||||
String REQUIREMENT_BUTTON_XPATH = "//*[@id=\"XXX702_T001_V002\"]/div[2]/div/div[5]/div/button";
|
|
||||||
String REFRESH_REQUIREMENT_BUTTON = "XXX702_T001_B001";
|
|
||||||
String REQUIREMENT_DESCRIPTION = "XXX702_T001_L269-1";
|
|
||||||
String SEND_ID_FOR_IB_SMS = "ADC739_S001_B005";
|
String SEND_ID_FOR_IB_SMS = "ADC739_S001_B005";
|
||||||
String PHISING_SMS_BUTTON = "ADC739_S001_B008";
|
String PHISING_SMS_BUTTON = "ADC739_S001_B008";
|
||||||
String BLOCATION_ALL_PROFILES_BUTTON = "ADC739_S001_B001";
|
String BLOCATION_ALL_PROFILES_BUTTON = "ADC739_S001_B001";
|
||||||
String UNBLOCATION_ALL_PROFILES_BUTTON = "ADC739_S001_B019";
|
String UNBLOCATION_ALL_PROFILES_BUTTON = "ADC739_S001_B019";
|
||||||
String DETAIL_OF_CLIENT_BUTTON = "XXX702_T001_B016";
|
|
||||||
String BLOCATION_OF_IB_CANAL_BUTTON = "ADC739_S001_B012";
|
String BLOCATION_OF_IB_CANAL_BUTTON = "ADC739_S001_B012";
|
||||||
String STATE_OF_IB_CANAL = "ADC739_S001_L104";
|
String STATE_OF_IB_CANAL = "ADC739_S001_L104";
|
||||||
String CANAL_IN_ROW_DIV = "ADC739_S001_L077-1";
|
String CANAL_IN_ROW_DIV = "ADC739_S001_L077-1";
|
||||||
@ -44,24 +40,12 @@ public interface ADC739_S001_IBSBPage extends WebFlow<ADC739_S001_IBSBPage>, Sto
|
|||||||
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE)
|
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE)
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default ADC739_S001_IBSBPage checkIfStatusBarIsOverwritten(String textInStatusBar) {
|
default ADC739_S001_IBSBPage checkIfStatusBarIsOverwritten(String textInStatusBar) {
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
String fullText = getStatusBarContent();
|
||||||
String fullText = endpoint.getText(STATUS_BAR);
|
|
||||||
String textWithoutTime = fullText.replaceFirst("^\\d{2}:\\d{2}:\\d{2}", "");
|
String textWithoutTime = fullText.replaceFirst("^\\d{2}:\\d{2}:\\d{2}", "");
|
||||||
Assert.assertTrue(textWithoutTime.contains(textInStatusBar));
|
Assert.assertTrue(textWithoutTime.contains(textInStatusBar));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Wait(value = REQUIREMENT_BUTTON_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
|
||||||
@Click(value = REQUIREMENT_BUTTON_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
|
||||||
ADC739_S001_IBSBPage clickRequirement();
|
|
||||||
|
|
||||||
@Wait(value = REFRESH_REQUIREMENT_BUTTON, until = Until.CLICKABLE)
|
|
||||||
@Click(value = REFRESH_REQUIREMENT_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
|
||||||
ADC739_S001_IBSBPage clickRefreshRequirement();
|
|
||||||
|
|
||||||
@CheckElementContent(REQUIREMENT_DESCRIPTION)
|
|
||||||
ADC739_S001_IBSBPage checkRequirementDescription(String description);
|
|
||||||
|
|
||||||
@Wait(value = SEND_ID_FOR_IB_SMS, until = Until.CLICKABLE)
|
@Wait(value = SEND_ID_FOR_IB_SMS, until = Until.CLICKABLE)
|
||||||
@Click(SEND_ID_FOR_IB_SMS)
|
@Click(SEND_ID_FOR_IB_SMS)
|
||||||
@AcceptAlert(waitSecondsForAlert = 15, expectedAlertText = "Souhlasíte, aby Vám společnost koncernu MONETA Money Bank, a. s. jednorázově zaslala ID k Internet Bance na telefonní číslo mobilního klíče")
|
@AcceptAlert(waitSecondsForAlert = 15, expectedAlertText = "Souhlasíte, aby Vám společnost koncernu MONETA Money Bank, a. s. jednorázově zaslala ID k Internet Bance na telefonní číslo mobilního klíče")
|
||||||
@ -76,10 +60,6 @@ public interface ADC739_S001_IBSBPage extends WebFlow<ADC739_S001_IBSBPage>, Sto
|
|||||||
@Click(value = BLOCATION_ALL_PROFILES_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
@Click(value = BLOCATION_ALL_PROFILES_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
ADC739_S001_IBSBPage clickBlockationAllProfilesButton();
|
ADC739_S001_IBSBPage clickBlockationAllProfilesButton();
|
||||||
|
|
||||||
@Wait(value = DETAIL_OF_CLIENT_BUTTON, until = Until.CLICKABLE)
|
|
||||||
@Click(value = DETAIL_OF_CLIENT_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
|
||||||
STS701_S002_ClientDetailPage clickDetailOfClientButton();
|
|
||||||
|
|
||||||
@Wait(value = UNBLOCATION_ALL_PROFILES_BUTTON, until = Until.CLICKABLE)
|
@Wait(value = UNBLOCATION_ALL_PROFILES_BUTTON, until = Until.CLICKABLE)
|
||||||
@Click(UNBLOCATION_ALL_PROFILES_BUTTON)
|
@Click(UNBLOCATION_ALL_PROFILES_BUTTON)
|
||||||
@AcceptAlert(waitSecondsForAlert = 15, expectedAlertText = "ADC kanál blokován na žádost banky = podezření na podvod! Ověřil si, že nemůže dojít k zneužití údajů klienta (IB a SB)? Opravdu chcete kanál odblokovat?")
|
@AcceptAlert(waitSecondsForAlert = 15, expectedAlertText = "ADC kanál blokován na žádost banky = podezření na podvod! Ověřil si, že nemůže dojít k zneužití údajů klienta (IB a SB)? Opravdu chcete kanál odblokovat?")
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
||||||
|
|
||||||
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
|
import cz.moneta.test.harness.support.web.CheckElementContent;
|
||||||
|
import cz.moneta.test.harness.support.web.CheckElementPresent;
|
||||||
|
import cz.moneta.test.harness.support.web.Wait;
|
||||||
|
import cz.moneta.test.harness.support.web.WebFlow;
|
||||||
|
|
||||||
|
public interface XXX702_Applications<T extends WebFlow<T>> extends WebFlow<T>, StoreAccessor {
|
||||||
|
|
||||||
|
String APPLICATIONS_RADIO = "XXX702_T001_R008_1";
|
||||||
|
|
||||||
|
String LOAD_BUTTON = "XXX702_T001_B026";
|
||||||
|
String LOAD_ALL_BUTTON = "XXX702_T001_B027";
|
||||||
|
String APPLICATION_COPY_BUTTON = "XXX702_T001_B034";
|
||||||
|
String FINISH_APPLICATION_BUTTON = "XXX702_T001_B029";
|
||||||
|
String APPLICATION_DECISION_BUTTON = "XXX702_T001_B030";
|
||||||
|
String STORNO_APPLICATION_BUTTON = "XXX702_T001_B028";
|
||||||
|
|
||||||
|
String FIRST_APPLICATION_DETAIL_BUTTON = "XXX702_T001_P045-1";
|
||||||
|
String FIRST_APPLICATION_STATE_LABEL = "XXX702_T001_L285-1";
|
||||||
|
String FIRST_APPLICATION_REQUESTED_PRODUCT_CODE_LABEL = "XXX702_T001_L303-1";
|
||||||
|
String FIRST_APPLICATION_REQUESTED_AMOUNT_LABEL = "XXX702_T001_L305-1";
|
||||||
|
String FIRST_APPLICATION_APPROVED_AMOUNT_LABEL = "XXX702_T001_L306-1";
|
||||||
|
String FIRST_APPLICATION_CHANNEL_LABEL = "XXX702_T001_L310-1";
|
||||||
|
|
||||||
|
@CheckElementPresent(APPLICATIONS_RADIO)
|
||||||
|
T checkApplicationsRadioPresence();
|
||||||
|
|
||||||
|
@CheckElementPresent(LOAD_BUTTON)
|
||||||
|
T checkApplicationsLoadButtonPresence();
|
||||||
|
|
||||||
|
@CheckElementPresent(LOAD_ALL_BUTTON)
|
||||||
|
T checkApplicationsLoadAllButtonPresence();
|
||||||
|
|
||||||
|
@CheckElementPresent(APPLICATION_COPY_BUTTON)
|
||||||
|
T checkApplicationCopyButtonPresence();
|
||||||
|
|
||||||
|
@CheckElementPresent(FINISH_APPLICATION_BUTTON)
|
||||||
|
T checkApplicationFinishButtonPresence();
|
||||||
|
|
||||||
|
@CheckElementPresent(APPLICATION_DECISION_BUTTON)
|
||||||
|
T checkApplicationDecisionButtonPresence();
|
||||||
|
|
||||||
|
@CheckElementPresent(STORNO_APPLICATION_BUTTON)
|
||||||
|
T checkApplicationStornoButtonPresence();
|
||||||
|
|
||||||
|
|
||||||
|
@CheckElementPresent(FIRST_APPLICATION_DETAIL_BUTTON)
|
||||||
|
T checkApplicationsFirstDetailButtonPresence();
|
||||||
|
|
||||||
|
@Wait(explicitWaitSeconds = 1) // There is a moment when list is full of some random items, can't think of better way to track it
|
||||||
|
@CheckElementContent(FIRST_APPLICATION_STATE_LABEL)
|
||||||
|
T assertFirstApplicationState(String firstApplicationState);
|
||||||
|
|
||||||
|
@CheckElementContent(FIRST_APPLICATION_REQUESTED_PRODUCT_CODE_LABEL)
|
||||||
|
T assertFirstApplicationProductCode(String expectedProductCode);
|
||||||
|
|
||||||
|
@CheckElementContent(FIRST_APPLICATION_REQUESTED_AMOUNT_LABEL)
|
||||||
|
T assertFirstApplicationRequestedAmount(String expectedAmount);
|
||||||
|
|
||||||
|
@CheckElementContent(FIRST_APPLICATION_APPROVED_AMOUNT_LABEL)
|
||||||
|
T assertFirstApplicationApprovedAmount(String expectedAmount);
|
||||||
|
|
||||||
|
@CheckElementContent(FIRST_APPLICATION_CHANNEL_LABEL)
|
||||||
|
T assertFirstApplicationChannel(String channel);
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
||||||
|
|
||||||
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
|
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
||||||
|
import cz.moneta.test.harness.support.web.*;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
|
||||||
|
public interface XXX702_ClientDetail<T extends WebFlow<T>> extends WebFlow<T>, StoreAccessor {
|
||||||
|
|
||||||
|
String CLIENT_CIF_LABEL = "XXX702_T002_L101";
|
||||||
|
String CLIENT_RC_LABEL = "XXX702_T001_L009";
|
||||||
|
String CONSENTS_101_MMB_LABEL = "XXX702_T001_L261";
|
||||||
|
String RELATIONSHIP_LABEL = "XXX702_T001_L230";
|
||||||
|
|
||||||
|
@CheckElementContent(CLIENT_RC_LABEL)
|
||||||
|
T assertClientRc(String rc);
|
||||||
|
|
||||||
|
@CheckElementContent(RELATIONSHIP_LABEL)
|
||||||
|
T assertClientRelationship(String relationship);
|
||||||
|
|
||||||
|
@Wait(value = CLIENT_CIF_LABEL, until = Until.VISIBLE)
|
||||||
|
@ExecuteJavaScript("navigator.clipboard.writeText(document.getElementById('" + CLIENT_CIF_LABEL + "').textContent)")
|
||||||
|
T copyCifNumberToClipboard();
|
||||||
|
|
||||||
|
@Wait(value = CONSENTS_101_MMB_LABEL)
|
||||||
|
@CustomAction
|
||||||
|
default T checkClientConsentsMMBTitle(String expectedTitle) {
|
||||||
|
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
||||||
|
Assertions.assertEquals(expectedTitle, endpoint.getAttribute(CONSENTS_101_MMB_LABEL, "title"));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
||||||
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
|
import cz.moneta.test.harness.support.web.CheckElementPresent;
|
||||||
|
import cz.moneta.test.harness.support.web.WebFlow;
|
||||||
|
|
||||||
|
public interface XXX702_ContactInformations<T extends WebFlow<T>> extends WebFlow<T>, StoreAccessor {
|
||||||
|
|
||||||
|
String ADDRESS_TABLE = "XXX702_T001_G003_UfoTable";
|
||||||
|
|
||||||
|
@CheckElementPresent(ADDRESS_TABLE)
|
||||||
|
STS701_S002_ClientDetailPage checkAddressTablePresence();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
||||||
|
|
||||||
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
|
import cz.moneta.test.harness.support.web.CheckElementPresent;
|
||||||
|
import cz.moneta.test.harness.support.web.WebFlow;
|
||||||
|
|
||||||
|
public interface XXX702_Notices<T extends WebFlow<T>> extends WebFlow<T>, StoreAccessor {
|
||||||
|
|
||||||
|
String NOTICES_TITLE_LABEL = "XXX702_T001_L226";
|
||||||
|
|
||||||
|
@CheckElementPresent(NOTICES_TITLE_LABEL)
|
||||||
|
T checkNoticesTitlePresence();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
||||||
|
|
||||||
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
|
import cz.moneta.test.harness.support.web.CheckElementPresent;
|
||||||
|
import cz.moneta.test.harness.support.web.WebFlow;
|
||||||
|
|
||||||
|
public interface XXX702_Offers<T extends WebFlow<T>> extends WebFlow<T>, StoreAccessor {
|
||||||
|
|
||||||
|
String ACTIVE_OFFERS_CHECKBOX = "XXX702_T001_H001_AKT";
|
||||||
|
|
||||||
|
@CheckElementPresent(ACTIVE_OFFERS_CHECKBOX)
|
||||||
|
T checkActiveOffersCheckboxPresence();
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,22 +1,56 @@
|
|||||||
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.ufo.operations.recorder.CRC710_S001_RecorderMainPage;
|
||||||
import cz.moneta.test.harness.context.StoreAccessor;
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
|
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
||||||
import cz.moneta.test.harness.support.web.*;
|
import cz.moneta.test.harness.support.web.*;
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
||||||
|
|
||||||
public interface XXX702_Requirements<T extends WebFlow<T>> extends WebFlow<T>, StoreAccessor {
|
public interface XXX702_Requirements<T extends WebFlow<T>> extends WebFlow<T>, StoreAccessor {
|
||||||
|
|
||||||
String REQUIREMENT_DATE = "XXX702_T001_L286-1";
|
String FIRST_REQUIREMENT_DESCRIPTION = "XXX702_T001_L269-1";
|
||||||
|
String FIRST_REQUIREMENT_SUBMIT_DATE = "XXX702_T001_L286-1";
|
||||||
|
String FIRST_REQUIREMENT_SOLVE_DATE = "XXX702_T001_L312-1";
|
||||||
|
String FIRST_REQUIREMENT_DETAIL_BUTTON = "XXX702_T001_P035-1";
|
||||||
|
|
||||||
|
String SECOND_REQUIREMENT_DESCRIPTION = "XXX702_T001_L269-2";
|
||||||
|
|
||||||
String REFRESH_REQ_BUTTON = "XXX702_T001_B001";
|
String REFRESH_REQ_BUTTON = "XXX702_T001_B001";
|
||||||
|
|
||||||
@Wait(value = REQUIREMENT_DATE, until = Until.VISIBLE)
|
@CheckElementPresent(FIRST_REQUIREMENT_DESCRIPTION)
|
||||||
@GetElementContent(REQUIREMENT_DATE)
|
T checkFirstRequirementDescriptionPresence();
|
||||||
String getRequirementDate();
|
|
||||||
|
|
||||||
|
@CheckElementContent(FIRST_REQUIREMENT_DESCRIPTION)
|
||||||
|
T assertFirstRequirementDescription(String description);
|
||||||
|
|
||||||
|
@CheckElementContent(FIRST_REQUIREMENT_SOLVE_DATE)
|
||||||
|
T assertFirstRequirementSolveDate(String expectedDate);
|
||||||
|
|
||||||
|
|
||||||
|
@GetElementContent(FIRST_REQUIREMENT_SUBMIT_DATE)
|
||||||
|
String getFirstRequirementSubmitDate();
|
||||||
|
|
||||||
|
@GetElementContent(FIRST_REQUIREMENT_SOLVE_DATE)
|
||||||
|
String getFirstRequirementSolveDate();
|
||||||
|
|
||||||
|
@CustomAction
|
||||||
|
default CRC710_S001_RecorderMainPage clickFirstRequirementDetail() {
|
||||||
|
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
||||||
|
endpoint.waitForElementsToLoad(15, FIRST_REQUIREMENT_DETAIL_BUTTON);
|
||||||
|
endpoint.click(() -> FIRST_REQUIREMENT_DETAIL_BUTTON);
|
||||||
|
endpoint.focusToNewPopup(5);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@CheckElementContent(SECOND_REQUIREMENT_DESCRIPTION)
|
||||||
|
T assertSecondRequirementDescription(String description);
|
||||||
|
|
||||||
|
|
||||||
@Wait(value = REFRESH_REQ_BUTTON, until = Until.VISIBLE)
|
@Wait(value = REFRESH_REQ_BUTTON, until = Until.VISIBLE)
|
||||||
@Click(value = REFRESH_REQ_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
@Click(value = REFRESH_REQ_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
XXX702_Requirements<T> clickRefreshRequirement();
|
XXX702_Requirements<T> clickRefreshRequirements();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
||||||
|
|
||||||
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
|
import cz.moneta.test.harness.support.web.*;
|
||||||
|
|
||||||
|
public interface XXX702_Sale<T extends WebFlow<T>> extends WebFlow<T>, StoreAccessor {
|
||||||
|
|
||||||
|
String EXPRESS_LABEL = "XXX702_T001_L337";
|
||||||
|
|
||||||
|
@CheckElementPresent(EXPRESS_LABEL)
|
||||||
|
T checkExpressLabelPresence();
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,19 +1,68 @@
|
|||||||
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
||||||
|
import cz.moneta.test.dsl.ufo.operations.ufoOperations.STO704_S001_ClientConsentsPage;
|
||||||
import cz.moneta.test.dsl.ufo.operations.ufoOperations.ZKU704_S001_ChangeContactData;
|
import cz.moneta.test.dsl.ufo.operations.ufoOperations.ZKU704_S001_ChangeContactData;
|
||||||
import cz.moneta.test.harness.support.web.*;
|
import cz.moneta.test.harness.support.web.*;
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
||||||
|
|
||||||
public interface XXX702_SharedClientMenu<T extends WebFlow<T>> extends XXX702_Requirements<T> {
|
public interface XXX702_SharedClientMenu<T extends WebFlow<T>> extends XXX702_ClientDetail<T>, XXX702_Sale<T>, XXX702_ContactInformations<T>, XXX702_Offers<T>, XXX702_Requirements<T>, XXX702_Tasks<T>, XXX702_Applications<T>, XXX702_Notices<T> {
|
||||||
|
|
||||||
String REQUIREMENT_BUTTON_XPATH = "//button[contains(@title, '[XXX702_T001_I015]')]";
|
String CLIENT_DETAIL_PANEL_XPATH = "//button [contains(@title, '[XXX702_T001_I006]')]";
|
||||||
|
String SALE_PANEL_XPATH = "//button[contains(@title, '[XXX702_T001_I010]')]";
|
||||||
|
String CONTACT_INFORMATIONS_PANEL_XPATH = "//button [contains(@title, '[XXX702_T001_I011]')]";
|
||||||
|
String OFFERS_PANEL_XPATH = "//button[contains(@title, '[XXX702_T001_I014]')]";
|
||||||
|
String REQUIREMENT_PANEL_XPATH = "//button[contains(@title, '[XXX702_T001_I015]')]";
|
||||||
|
String TASKS_PANEL_XPATH = "//button[contains(@title, '[XXX702_T001_I016]')]";
|
||||||
|
String APPLICATIONS_PANEL_XPATH = "//button[contains(@title, '[XXX702_T001_I018')]";
|
||||||
|
String NOTICES_PANEL_XPATH = "//button[contains(@title, '[XXX702_T001_I019]')]";
|
||||||
|
|
||||||
|
String CLIENT_DETAIL_BUTTON = "XXX702_T001_B016";
|
||||||
|
String CLIENT_CONSENTS_BUTTON = "XXX702_T001_P046";
|
||||||
String CHANGE_CONTACT_DATA_BUTTON = "XXX702_T001_P047";
|
String CHANGE_CONTACT_DATA_BUTTON = "XXX702_T001_P047";
|
||||||
|
|
||||||
@Wait(value = REQUIREMENT_BUTTON_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
|
||||||
@Click(value = REQUIREMENT_BUTTON_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
@Wait(value = CLIENT_DETAIL_PANEL_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
||||||
XXX702_Requirements<T> menuClickRequirements();
|
@Click(value = CLIENT_DETAIL_PANEL_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
|
XXX702_ClientDetail<T> menuClickClientDetailPanel();
|
||||||
|
|
||||||
|
@Wait(value = SALE_PANEL_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
||||||
|
@Click(value = SALE_PANEL_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
|
XXX702_Sale<T> menuClickClientSale();
|
||||||
|
|
||||||
|
@Wait(value = CONTACT_INFORMATIONS_PANEL_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
||||||
|
@Click(value = CONTACT_INFORMATIONS_PANEL_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
|
XXX702_ContactInformations<T> menuClickClientContactInformations();
|
||||||
|
|
||||||
|
@Wait(value = OFFERS_PANEL_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
||||||
|
@Click(value = OFFERS_PANEL_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
|
XXX702_Offers<T> menuClickClientOffers();
|
||||||
|
|
||||||
|
@Wait(value = REQUIREMENT_PANEL_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
||||||
|
@Click(value = REQUIREMENT_PANEL_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
|
XXX702_Requirements<T> menuClickClientRequirements();
|
||||||
|
|
||||||
|
@Wait(value = TASKS_PANEL_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
||||||
|
@Click(value = TASKS_PANEL_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
|
XXX702_Tasks<T> menuClickClientTasks();
|
||||||
|
|
||||||
|
@Wait(value = APPLICATIONS_PANEL_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
||||||
|
@Click(value = APPLICATIONS_PANEL_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
|
XXX702_Applications<T> menuClickClientApplications();
|
||||||
|
|
||||||
|
@Wait(value = NOTICES_PANEL_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
|
||||||
|
@Click(value = NOTICES_PANEL_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
|
XXX702_Notices<T> menuClickClientNotices();
|
||||||
|
|
||||||
|
|
||||||
|
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE)
|
||||||
|
@Click(value = CLIENT_DETAIL_BUTTON)
|
||||||
|
STS701_S002_ClientDetailPage menuClickClientDetailButton();
|
||||||
|
|
||||||
|
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE)
|
||||||
|
@Click(CLIENT_CONSENTS_BUTTON)
|
||||||
|
STO704_S001_ClientConsentsPage menuClickClientConsents();
|
||||||
|
|
||||||
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE)
|
@Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE)
|
||||||
@Click(CHANGE_CONTACT_DATA_BUTTON)
|
@Click(CHANGE_CONTACT_DATA_BUTTON)
|
||||||
|
|||||||
@ -19,6 +19,8 @@ import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_D
|
|||||||
|
|
||||||
public interface XXX702_SharedTopMenu<T extends WebFlow<T>> extends XXX702_SharedClientMenu<T>, XXX702_SharedSearchMenu<T>, StoreAccessor {
|
public interface XXX702_SharedTopMenu<T extends WebFlow<T>> extends XXX702_SharedClientMenu<T>, XXX702_SharedSearchMenu<T>, StoreAccessor {
|
||||||
|
|
||||||
|
String STATUS_BAR = "XXX702_T001_L107";
|
||||||
|
|
||||||
String LOGOUT_BUTTON = "XXX702_T001_B008";
|
String LOGOUT_BUTTON = "XXX702_T001_B008";
|
||||||
|
|
||||||
String ACTUAL_DATE_DIV = "XXX702_T001_L172";
|
String ACTUAL_DATE_DIV = "XXX702_T001_L172";
|
||||||
@ -33,6 +35,20 @@ public interface XXX702_SharedTopMenu<T extends WebFlow<T>> extends XXX702_Share
|
|||||||
String CALCULATOR_BUTTON = "XXX702_T001_P010";
|
String CALCULATOR_BUTTON = "XXX702_T001_P010";
|
||||||
String TASK_MANAGEMENT_BUTTON = "XXX702_T001_P053";
|
String TASK_MANAGEMENT_BUTTON = "XXX702_T001_P053";
|
||||||
|
|
||||||
|
@GetElementContent(STATUS_BAR)
|
||||||
|
String getStatusBarContent();
|
||||||
|
|
||||||
|
@CheckElementContent(STATUS_BAR)
|
||||||
|
T assertStatusBarContent(String expectedText);
|
||||||
|
|
||||||
|
@CustomAction
|
||||||
|
default T checkStatusBarIsEmpty() {
|
||||||
|
String statusBarContent = getEndpoint(UfoEndpoint.class).getText(STATUS_BAR);
|
||||||
|
Assertions.assertTrue(statusBarContent == null || statusBarContent.isEmpty(), "Expected status bar to be empty, but was: " + statusBarContent);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Click(LOGOUT_BUTTON)
|
@Click(LOGOUT_BUTTON)
|
||||||
LogOutPage clickLogout();
|
LogOutPage clickLogout();
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
package cz.moneta.test.dsl.ufo.operations.shared.topmenu;
|
||||||
|
|
||||||
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
|
import cz.moneta.test.harness.support.web.CheckElementPresent;
|
||||||
|
import cz.moneta.test.harness.support.web.WebFlow;
|
||||||
|
|
||||||
|
public interface XXX702_Tasks<T extends WebFlow<T>> extends WebFlow<T>, StoreAccessor {
|
||||||
|
|
||||||
|
String TASKS_TABLE = "XXX702_T001_G009_UfoTable_clone";
|
||||||
|
|
||||||
|
@CheckElementPresent(TASKS_TABLE)
|
||||||
|
T checkTasksTablePresence();
|
||||||
|
|
||||||
|
}
|
||||||
@ -84,7 +84,7 @@ public interface ETS701_S001_ClientDocuments extends WebFlow<ETS701_S001_ClientD
|
|||||||
default ETS701_S001_ClientDocuments checkDistributionAndGetTime() {
|
default ETS701_S001_ClientDocuments checkDistributionAndGetTime() {
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
||||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d.M.yyyy H:mm:ss");
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d.M.yyyy H:mm:ss");
|
||||||
String requirementDate = menuClickRequirements().clickRefreshRequirement().getRequirementDate();
|
String requirementDate = menuClickClientRequirements().clickRefreshRequirements().getFirstRequirementSubmitDate();
|
||||||
endpoint.waitForElementsToLoad(10, CORRESPONDENCE_DATE);
|
endpoint.waitForElementsToLoad(10, CORRESPONDENCE_DATE);
|
||||||
String correspondenceDate = endpoint.getText(CORRESPONDENCE_DATE);
|
String correspondenceDate = endpoint.getText(CORRESPONDENCE_DATE);
|
||||||
LocalDateTime reqDate = LocalDateTime.parse(requirementDate, formatter).withMinute(0).withSecond(0).withNano(0);
|
LocalDateTime reqDate = LocalDateTime.parse(requirementDate, formatter).withMinute(0).withSecond(0).withNano(0);
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
package cz.moneta.test.dsl.ufo.operations.ufoOperations;
|
package cz.moneta.test.dsl.ufo.operations.ufoOperations;
|
||||||
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
||||||
|
import cz.moneta.test.dsl.ufo.operations.shared.topmenu.XXX702_SharedTopMenu;
|
||||||
import cz.moneta.test.harness.support.web.*;
|
import cz.moneta.test.harness.support.web.*;
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
||||||
|
|
||||||
public interface PLK703_S002_DebitCardBlocationPage extends WebFlow<PLK703_S002_DebitCardBlocationPage> {
|
public interface PLK703_S002_DebitCardBlocationPage extends WebFlow<PLK703_S002_DebitCardBlocationPage>, XXX702_SharedTopMenu<PLK703_S002_DebitCardBlocationPage> {
|
||||||
|
|
||||||
String SAVE_BUTTON = "PLK703_S002_B003";
|
String SAVE_BUTTON = "PLK703_S002_B003";
|
||||||
String BACK_DART_BUTTON = "PLK703_S002_B001";
|
String BACK_DART_BUTTON = "PLK703_S002_B001";
|
||||||
@ -18,10 +19,6 @@ public interface PLK703_S002_DebitCardBlocationPage extends WebFlow<PLK703_S002_
|
|||||||
String SUBMIT_SAVE_BUTTON = "PLK703_S002_B003";
|
String SUBMIT_SAVE_BUTTON = "PLK703_S002_B003";
|
||||||
String UNBLOCK_DEBIT_CARD_BUTTON = "PLK703_S002_B004";
|
String UNBLOCK_DEBIT_CARD_BUTTON = "PLK703_S002_B004";
|
||||||
String CONFIRM_BLOCK_BUTTON = "HLA701_S001_B002";
|
String CONFIRM_BLOCK_BUTTON = "HLA701_S001_B002";
|
||||||
String REQUIREMENT_BUTTON_XPATH = "//button[contains(@title, '[XXX702_T001_I015]')]";
|
|
||||||
|
|
||||||
String REFRESH_BUTTON = "XXX702_T001_B001";
|
|
||||||
String REQ_TO_CONTROL = "XXX702_T001_L269-1";
|
|
||||||
String CONFIRM_ALERT_BUTTON = "HLA701_S001_B001";
|
String CONFIRM_ALERT_BUTTON = "HLA701_S001_B001";
|
||||||
String TELEPHONE_NUMBER_TEXTBOX = "PLK703_S002_E007";
|
String TELEPHONE_NUMBER_TEXTBOX = "PLK703_S002_E007";
|
||||||
|
|
||||||
@ -58,21 +55,6 @@ public interface PLK703_S002_DebitCardBlocationPage extends WebFlow<PLK703_S002_
|
|||||||
@Click(value = CONFIRM_BLOCK_BUTTON)
|
@Click(value = CONFIRM_BLOCK_BUTTON)
|
||||||
PLK703_S002_DebitCardBlocationPage clickConfirmBlockButton();
|
PLK703_S002_DebitCardBlocationPage clickConfirmBlockButton();
|
||||||
|
|
||||||
@Wait(value = REQUIREMENT_BUTTON_XPATH,by = Lookup.XPATH, until = Until.CLICKABLE)
|
|
||||||
@Click(value = REQUIREMENT_BUTTON_XPATH,by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, until = Until.GONE, by = Lookup.CLASSNAME))
|
|
||||||
PLK703_S002_DebitCardBlocationPage clickRequirementButton();
|
|
||||||
|
|
||||||
@Wait(value = REFRESH_BUTTON, until = Until.CLICKABLE)
|
|
||||||
@Click(value = REFRESH_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, until = Until.GONE, by = Lookup.CLASSNAME))
|
|
||||||
PLK703_S002_DebitCardBlocationPage clickRefreshButton();
|
|
||||||
|
|
||||||
@Wait(value = REQ_TO_CONTROL, waitSecondsForElement = 30)
|
|
||||||
@CheckElementContent(value = REQ_TO_CONTROL)
|
|
||||||
PLK703_S002_DebitCardBlocationPage assertReqTempBlock(String text);
|
|
||||||
|
|
||||||
@CheckElementContent(value = REQ_TO_CONTROL)
|
|
||||||
PLK703_S002_DebitCardBlocationPage assertReqTempUnblock(String text);
|
|
||||||
|
|
||||||
@Click(CONFIRM_ALERT_BUTTON)
|
@Click(CONFIRM_ALERT_BUTTON)
|
||||||
PLK703_S002_DebitCardBlocationPage clickConfirmAlertButton();
|
PLK703_S002_DebitCardBlocationPage clickConfirmAlertButton();
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package cz.moneta.test.dsl.ufo.operations.ufoOperations;
|
package cz.moneta.test.dsl.ufo.operations.ufoOperations;
|
||||||
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
||||||
|
import cz.moneta.test.dsl.ufo.operations.shared.topmenu.XXX702_SharedTopMenu;
|
||||||
import cz.moneta.test.harness.context.StoreAccessor;
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
||||||
import cz.moneta.test.harness.support.web.*;
|
import cz.moneta.test.harness.support.web.*;
|
||||||
@ -10,7 +11,7 @@ import static cz.moneta.test.dsl.ufo.operations.ufoOperations.PLK708_S001_DataCh
|
|||||||
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
import static cz.moneta.test.dsl.ufo.operations.shared.SharedElements.LOAD_IMG_DIV_CLASS;
|
||||||
|
|
||||||
@Wait(value = PAGE_TITLE, until = Until.VISIBLE)
|
@Wait(value = PAGE_TITLE, until = Until.VISIBLE)
|
||||||
public interface PLK708_S001_DataChangesPage extends WebFlow<PLK708_S001_DataChangesPage>, StoreAccessor {
|
public interface PLK708_S001_DataChangesPage extends WebFlow<PLK708_S001_DataChangesPage>, XXX702_SharedTopMenu<PLK708_S001_DataChangesPage>, StoreAccessor {
|
||||||
|
|
||||||
String PAGE_TITLE = "PLK708el11";
|
String PAGE_TITLE = "PLK708el11";
|
||||||
String ADDRESS_FOR_SENDING_SELECT = "PLK708_S001_C001";
|
String ADDRESS_FOR_SENDING_SELECT = "PLK708_S001_C001";
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package cz.moneta.test.dsl.ufo.operations.ufoOperations;
|
package cz.moneta.test.dsl.ufo.operations.ufoOperations;
|
||||||
|
|
||||||
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.recorder.CRC710_S001_RecorderMainPage;
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.shared.topmenu.XXX702_SharedTopMenu;
|
import cz.moneta.test.dsl.ufo.operations.shared.topmenu.XXX702_SharedTopMenu;
|
||||||
import cz.moneta.test.harness.context.StoreAccessor;
|
import cz.moneta.test.harness.context.StoreAccessor;
|
||||||
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
|
||||||
@ -48,16 +47,10 @@ public interface STO704_S001_ClientConsentsPage extends WebFlow<STO704_S001_Clie
|
|||||||
String SEARCH_HISTORY_BUTTON = "STO704_S001_B006";
|
String SEARCH_HISTORY_BUTTON = "STO704_S001_B006";
|
||||||
String DETAIL_OF_LIST_CHANGE = "STO704_S001_P002-1";
|
String DETAIL_OF_LIST_CHANGE = "STO704_S001_P002-1";
|
||||||
String CONSENT_STATUS_SET = "STO704_S001_L088-1";
|
String CONSENT_STATUS_SET = "STO704_S001_L088-1";
|
||||||
String REQUIREMENT_BUTTON_XPATH = "//*[@id=\"XXX702_T001_V002\"]/div[2]/div/div[5]/div/button";
|
|
||||||
String REFRESH_REQUIREMENT = "XXX702_T001_B001";
|
|
||||||
String CLIENT_CONSENTS = "XXX702_T001_P046";
|
|
||||||
String PRINT_COMBOBOX = "STO704_S001_C010";
|
String PRINT_COMBOBOX = "STO704_S001_C010";
|
||||||
String GENERATE_PRINT = "STO704_S001_B008";
|
String GENERATE_PRINT = "STO704_S001_B008";
|
||||||
String TYPE_OF_CONSENT = "STO704_S001_L077-3";
|
String TYPE_OF_CONSENT = "STO704_S001_L077-3";
|
||||||
String DETAIL_OF_REQUIREMENT = "XXX702_T001_P035-1";
|
|
||||||
String MMB_LABEL = "XXX702_T001_L261";
|
|
||||||
String TODAY_DATE_IN_CHANGES = "STO704_S001_E002";
|
String TODAY_DATE_IN_CHANGES = "STO704_S001_E002";
|
||||||
String TODAY_DATE = "XXX702_T001_L172";
|
|
||||||
String POST_CONSENT = "STO704_S001_L077-4";
|
String POST_CONSENT = "STO704_S001_L077-4";
|
||||||
String IBSB_CONSENT = "STO704_S001_L077-6";
|
String IBSB_CONSENT = "STO704_S001_L077-6";
|
||||||
String SURVEY_CONSENT = "STO704_S001_L077-5";
|
String SURVEY_CONSENT = "STO704_S001_L077-5";
|
||||||
@ -164,17 +157,6 @@ public interface STO704_S001_ClientConsentsPage extends WebFlow<STO704_S001_Clie
|
|||||||
@CheckElementContent(CONSENT_STATUS_SET)
|
@CheckElementContent(CONSENT_STATUS_SET)
|
||||||
STO704_S001_ClientConsentsPage checkConsentsStatusSet(String consent);
|
STO704_S001_ClientConsentsPage checkConsentsStatusSet(String consent);
|
||||||
|
|
||||||
@Wait(value = REQUIREMENT_BUTTON_XPATH, by = Lookup.XPATH, until = Until.VISIBLE)
|
|
||||||
@Click(value = REQUIREMENT_BUTTON_XPATH, by = Lookup.XPATH, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
|
||||||
STO704_S001_ClientConsentsPage clickRequirement();
|
|
||||||
|
|
||||||
@Wait(REFRESH_REQUIREMENT)
|
|
||||||
@Click(value = REFRESH_REQUIREMENT, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
|
||||||
STO704_S001_ClientConsentsPage clickRefreshRequirement();
|
|
||||||
|
|
||||||
@Click(CLIENT_CONSENTS)
|
|
||||||
STO704_S001_ClientConsentsPage clickClientConsents();
|
|
||||||
|
|
||||||
@Select(value = PRINT_COMBOBOX, selectByOrder = true)
|
@Select(value = PRINT_COMBOBOX, selectByOrder = true)
|
||||||
STO704_S001_ClientConsentsPage selectTypeOfPrint(int order);
|
STO704_S001_ClientConsentsPage selectTypeOfPrint(int order);
|
||||||
|
|
||||||
@ -189,15 +171,6 @@ public interface STO704_S001_ClientConsentsPage extends WebFlow<STO704_S001_Clie
|
|||||||
@CheckElementContent(EMAIL_CONSENT)
|
@CheckElementContent(EMAIL_CONSENT)
|
||||||
STO704_S001_ClientConsentsPage checkTypeOfConsentEmail(String consent);
|
STO704_S001_ClientConsentsPage checkTypeOfConsentEmail(String consent);
|
||||||
|
|
||||||
@CustomAction
|
|
||||||
default CRC710_S001_RecorderMainPage clickDetailOfRequirement() {
|
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
|
||||||
endpoint.waitForElementsToLoad(15, DETAIL_OF_REQUIREMENT);
|
|
||||||
endpoint.click(() -> DETAIL_OF_REQUIREMENT);
|
|
||||||
endpoint.focusToNewPopup(5);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@AcceptAlert(waitSecondsForAlert = 10, expectedAlertText = "Souhlasím se zpracováním svých osobních údajů, zejména, informací o bankovních obchodech a údajů vzniklých v průběhu využívání produktů a služeb které sdělím, nebo které oprávněným způsobem získají společnosti koncernu MONETA (MONETA Money Bank, a. s., MONETA Auto, s.r.o., MONETA Leasing, s.r.o. a MONETA Stavební Spořitelna a.s.) pro přípravu nabídky na míru a oslovení s nabídkou produktů nebo služeb. Více na www.moneta.cz v sekci Ochrana osobních údajů.")
|
@AcceptAlert(waitSecondsForAlert = 10, expectedAlertText = "Souhlasím se zpracováním svých osobních údajů, zejména, informací o bankovních obchodech a údajů vzniklých v průběhu využívání produktů a služeb které sdělím, nebo které oprávněným způsobem získají společnosti koncernu MONETA (MONETA Money Bank, a. s., MONETA Auto, s.r.o., MONETA Leasing, s.r.o. a MONETA Stavební Spořitelna a.s.) pro přípravu nabídky na míru a oslovení s nabídkou produktů nebo služeb. Více na www.moneta.cz v sekci Ochrana osobních údajů.")
|
||||||
STO704_S001_ClientConsentsPage acceptAlert();
|
STO704_S001_ClientConsentsPage acceptAlert();
|
||||||
|
|
||||||
@ -269,24 +242,13 @@ public interface STO704_S001_ClientConsentsPage extends WebFlow<STO704_S001_Clie
|
|||||||
@CheckElementContent(OTHER_CHANNELS_MMB_CONSENTS)
|
@CheckElementContent(OTHER_CHANNELS_MMB_CONSENTS)
|
||||||
STO704_S001_ClientConsentsPage checkOtherChannelsMMBConsents(String text);
|
STO704_S001_ClientConsentsPage checkOtherChannelsMMBConsents(String text);
|
||||||
|
|
||||||
@Wait(value = MMB_LABEL)
|
|
||||||
@CustomAction
|
|
||||||
default STO704_S001_ClientConsentsPage checkIfMMBTitleIsShowingExpectedText() {
|
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
|
||||||
String MMB_title = endpoint.getAttribute(MMB_LABEL, "title");
|
|
||||||
String MMB_expected_title = "Telefon - PLATNÝ [XXX702_T001_L261]";
|
|
||||||
Assertions.assertEquals(MMB_expected_title, MMB_title, "The title isn't visible");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Wait(value = TODAY_DATE, until = Until.VISIBLE)
|
|
||||||
@Wait(value = TODAY_DATE_IN_CHANGES, until = Until.VISIBLE)
|
@Wait(value = TODAY_DATE_IN_CHANGES, until = Until.VISIBLE)
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default STO704_S001_ClientConsentsPage checkIfIsSelectedTodayDate() {
|
default STO704_S001_ClientConsentsPage checkIfIsSelectedTodayDate() {
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
||||||
String todayDateInChanges = endpoint.getAttribute(TODAY_DATE_IN_CHANGES, "value");
|
String todayDateInChanges = endpoint.getAttribute(TODAY_DATE_IN_CHANGES, "value");
|
||||||
String todayDate = endpoint.getText(TODAY_DATE);
|
String todayDate = getActualDate();
|
||||||
Assertions.assertEquals(todayDateInChanges, todayDate, "Dates aren't same.");
|
Assertions.assertEquals(todayDate, todayDateInChanges, "Dates aren't same.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,8 +25,6 @@ public interface TRA740_S001_CreateNewTransferPaymentOrderPage extends WebFlow<T
|
|||||||
String AMOUNT_INPUT = "TRA740_S001_E005";
|
String AMOUNT_INPUT = "TRA740_S001_E005";
|
||||||
|
|
||||||
String SEND_BUTTON = "TRA740_S001_B001";
|
String SEND_BUTTON = "TRA740_S001_B001";
|
||||||
String TRANSACTION_SUCCESSFULLY_ESTABLISHED_DIV = "XXX702_T001_L107";
|
|
||||||
String ID_PAYMENT_ORDER_DIV = "XXX702_T001_L107";
|
|
||||||
String VARIABLE_SYMBOL = "TRA740_S001_E007";
|
String VARIABLE_SYMBOL = "TRA740_S001_E007";
|
||||||
String SPECIFICALLY_SYMBOL = "TRA740_S001_E009";
|
String SPECIFICALLY_SYMBOL = "TRA740_S001_E009";
|
||||||
String MESSAGE = "TRA740_S001_M001";
|
String MESSAGE = "TRA740_S001_M001";
|
||||||
@ -65,14 +63,10 @@ public interface TRA740_S001_CreateNewTransferPaymentOrderPage extends WebFlow<T
|
|||||||
@Click(value = SEND_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
@Click(value = SEND_BUTTON, andWait = @Wait(value = LOAD_IMG_DIV_CLASS, by = Lookup.CLASSNAME, until = Until.GONE))
|
||||||
TRA740_S001_CreateNewTransferPaymentOrderPage clickSend();
|
TRA740_S001_CreateNewTransferPaymentOrderPage clickSend();
|
||||||
|
|
||||||
@CheckElementContent(TRANSACTION_SUCCESSFULLY_ESTABLISHED_DIV)
|
|
||||||
TRA740_S001_CreateNewTransferPaymentOrderPage checkTransactionSuccessfullyEstablished(String content);
|
|
||||||
|
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default TRA740_S001_CreateNewTransferPaymentOrderPage saveTaskIDPaymentOrder() {
|
default TRA740_S001_CreateNewTransferPaymentOrderPage saveTaskIDPaymentOrder() {
|
||||||
|
|
||||||
UfoEndpoint endpoint = this.getEndpoint(UfoEndpoint.class);
|
UfoEndpoint endpoint = this.getEndpoint(UfoEndpoint.class);
|
||||||
String establishedTaskText = endpoint.getText(ID_PAYMENT_ORDER_DIV).replaceAll(".*ID: (\\d+)$", "$1");
|
String establishedTaskText = endpoint.getText(STATUS_BAR).replaceAll(".*ID: (\\d+)$", "$1");
|
||||||
this.store(ID_PAYMENT_ORDER_KEY, establishedTaskText);
|
this.store(ID_PAYMENT_ORDER_KEY, establishedTaskText);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,12 +73,8 @@ public interface XCM701_S001_MortgagesPanel extends XCM701_S001_ContactForwardin
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CustomAction
|
@TypeInto(value = PHONE_INPUT, clear = true)
|
||||||
default XCM701_S001_MortgagesPanel checkPhone(String phone) {
|
XCM701_S001_MortgagesPanel fillPhone(String phone);
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
|
||||||
Assertions.assertEquals(phone, endpoint.getAttribute(PHONE_INPUT, "value"));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default XCM701_S001_MortgagesPanel checkEmail(String email) {
|
default XCM701_S001_MortgagesPanel checkEmail(String email) {
|
||||||
|
|||||||
@ -90,12 +90,8 @@ public interface XCM701_S001_OtherPanel extends XCM701_S001_ContactForwardingPag
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CustomAction
|
@TypeInto(value = MOBILE_INPUT, clear = true)
|
||||||
default XCM701_S001_OtherPanel checkMobile(String mobile) {
|
XCM701_S001_OtherPanel fillMobile(String mobile);
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
|
||||||
Assertions.assertEquals(mobile, endpoint.getAttribute(MOBILE_INPUT, "value"));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default XCM701_S001_OtherPanel checkEmail(String email) {
|
default XCM701_S001_OtherPanel checkEmail(String email) {
|
||||||
|
|||||||
@ -77,12 +77,8 @@ public interface XCM701_S001_SMEPanel extends XCM701_S001_ContactForwardingPage
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CustomAction
|
@TypeInto(value = MOBILE_INPUT, clear = true)
|
||||||
default XCM701_S001_SMEPanel checkMobile(String mobile) {
|
XCM701_S001_SMEPanel fillMobile(String mobile);
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
|
||||||
Assertions.assertEquals(mobile, endpoint.getAttribute(MOBILE_INPUT, "value"));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CustomAction
|
@CustomAction
|
||||||
default XCM701_S001_SMEPanel checkEmail(String email) {
|
default XCM701_S001_SMEPanel checkEmail(String email) {
|
||||||
@ -101,7 +97,7 @@ public interface XCM701_S001_SMEPanel extends XCM701_S001_ContactForwardingPage
|
|||||||
@CustomAction
|
@CustomAction
|
||||||
default XCM701_S001_SMEPanel checkInactiveAvailabilityHours() {
|
default XCM701_S001_SMEPanel checkInactiveAvailabilityHours() {
|
||||||
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
|
||||||
Assertions.assertNotNull(endpoint.getAttribute(AVAILABILITY_TIME_INPUT,"readonly"), "Element" + AVAILABILITY_TIME_INPUT + "isn't readonly");
|
Assertions.assertNotNull(endpoint.getAttribute(AVAILABILITY_TIME_INPUT, "readonly"), "Element" + AVAILABILITY_TIME_INPUT + "isn't readonly");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -182,5 +182,10 @@ public class Keys {
|
|||||||
*/
|
*/
|
||||||
public static final String inheritance = "exevido-inheritance";
|
public static final String inheritance = "exevido-inheritance";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User with role exevido.inheritanceController
|
||||||
|
*/
|
||||||
|
public static final String inheritanceController = "exevido-inheritanceController";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,6 +207,9 @@ public class PaymentData {
|
|||||||
@Setter
|
@Setter
|
||||||
private String messageId;
|
private String messageId;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private String uetr;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import cz.moneta.test.dsl.util.task.dataprepare.DataPrepareTasks;
|
|||||||
import cz.moneta.test.dsl.util.task.dmbsib.DmbsibTasks;
|
import cz.moneta.test.dsl.util.task.dmbsib.DmbsibTasks;
|
||||||
import cz.moneta.test.dsl.util.task.firstvision.FirstVisionTasks;
|
import cz.moneta.test.dsl.util.task.firstvision.FirstVisionTasks;
|
||||||
import cz.moneta.test.dsl.util.task.ib.IbTasks;
|
import cz.moneta.test.dsl.util.task.ib.IbTasks;
|
||||||
|
import cz.moneta.test.dsl.util.task.paemq.PaeMqTasks;
|
||||||
import cz.moneta.test.dsl.util.task.ihub.IHubTasks;
|
import cz.moneta.test.dsl.util.task.ihub.IHubTasks;
|
||||||
import cz.moneta.test.dsl.util.task.insurance.InsuranceTasks;
|
import cz.moneta.test.dsl.util.task.insurance.InsuranceTasks;
|
||||||
import cz.moneta.test.dsl.util.task.kasanova.KSNTasks;
|
import cz.moneta.test.dsl.util.task.kasanova.KSNTasks;
|
||||||
@ -187,4 +188,8 @@ public class Tasks {
|
|||||||
public ExevidoTasks exevidoTasks() {
|
public ExevidoTasks exevidoTasks() {
|
||||||
return new ExevidoTasks(harness);
|
return new ExevidoTasks(harness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PaeMqTasks paeMq() {
|
||||||
|
return new PaeMqTasks(harness);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -143,7 +143,8 @@ public class CalculationTypeTasks {
|
|||||||
.typeVehicleInsuranceCustomerSurname(customer.getSurname())
|
.typeVehicleInsuranceCustomerSurname(customer.getSurname())
|
||||||
.typeVehicleInsuranceCustomerBirthdate(customerData.getBirthdate().getValue())
|
.typeVehicleInsuranceCustomerBirthdate(customerData.getBirthdate().getValue())
|
||||||
.typeVehicleInsuranceCustomerPIN(customerData.getPin().getValue())
|
.typeVehicleInsuranceCustomerPIN(customerData.getPin().getValue())
|
||||||
.typeVehicleInsuranceCustomerNationality(customerData.getNationality().getValue())
|
.clickVehicleInsuranceCustomerNationalityTextbox()
|
||||||
|
.clickVehicleInsuranceCustomerNationalityTextbox()
|
||||||
.clickVehicleInsuranceCustomerNationality()
|
.clickVehicleInsuranceCustomerNationality()
|
||||||
.typeVehicleInsuranceCustomerAddress(customer.getAddress())
|
.typeVehicleInsuranceCustomerAddress(customer.getAddress())
|
||||||
.clickVehicleInsuranceCustomerAddress();
|
.clickVehicleInsuranceCustomerAddress();
|
||||||
|
|||||||
@ -0,0 +1,27 @@
|
|||||||
|
package cz.moneta.test.dsl.util.task.paemq;
|
||||||
|
|
||||||
|
import cz.moneta.test.dsl.Harness;
|
||||||
|
import cz.moneta.test.dsl.payment_engine_mq.MessagingType;
|
||||||
|
import cz.moneta.test.harness.support.rest.RawRestRequest;
|
||||||
|
|
||||||
|
public class PaeMqTasks {
|
||||||
|
private final Harness harness;
|
||||||
|
|
||||||
|
public PaeMqTasks(Harness harness) {
|
||||||
|
this.harness = harness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RawRestRequest.Request prepareEmptyRequest(MessagingType messagingType) {
|
||||||
|
return this.harness.withPaeMq().prepareRequest(messagingType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RawRestRequest.Post prepareRequest(MessagingType messagingType, String payload) {
|
||||||
|
return this.harness.withPaeMq().prepareRequest(messagingType)
|
||||||
|
.withPayload(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void uploadFile(MessagingType messagingType, String file) {
|
||||||
|
prepareRequest(messagingType, file).post().andAssertStatus(201);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,13 +1,17 @@
|
|||||||
package cz.moneta.test.dsl.util.task.ufo.operations;
|
package cz.moneta.test.dsl.util.task.ufo.operations;
|
||||||
|
|
||||||
import cz.moneta.test.dsl.Harness;
|
import cz.moneta.test.dsl.Harness;
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.STO702_S002_ApproveAlreadyReadPage;
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.NewProductsByNameUfoOps;
|
import cz.moneta.test.dsl.ufo.operations.client.NewProductsByNameUfoOps;
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.NewProductsUfoOps;
|
import cz.moneta.test.dsl.ufo.operations.client.NewProductsUfoOps;
|
||||||
|
import cz.moneta.test.dsl.ufo.operations.client.STO702_S002_ApproveAlreadyReadPage;
|
||||||
|
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
||||||
import cz.moneta.test.dsl.ufo.operations.search.OPS001_S001_ClientSearchPageUfoOperations;
|
import cz.moneta.test.dsl.ufo.operations.search.OPS001_S001_ClientSearchPageUfoOperations;
|
||||||
import cz.moneta.test.dsl.ufo.operations.ufoOperations.contactForwarding.XCM701_S001_ContactForwardingPage;
|
import cz.moneta.test.dsl.ufo.operations.ufoOperations.contactForwarding.XCM701_S001_ContactForwardingPage;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class ClientDetailsTasks {
|
public class ClientDetailsTasks {
|
||||||
@ -32,4 +36,24 @@ public class ClientDetailsTasks {
|
|||||||
return start -> start.then(harness.tasks().ufo().operations().searchClient().byRc(rcOfExistingClient))
|
return start -> start.then(harness.tasks().ufo().operations().searchClient().byRc(rcOfExistingClient))
|
||||||
.clickContactForwarding();
|
.clickContactForwarding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Function<STS701_S002_ClientDetailPage, STS701_S002_ClientDetailPage> assertFirstRequirementSolveDate() {
|
||||||
|
return start -> start.menuClickClientRequirements()
|
||||||
|
.clickRefreshRequirements()
|
||||||
|
.assertFirstRequirementSolveDate(start.getActualDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Function<STS701_S002_ClientDetailPage, STS701_S002_ClientDetailPage> assertFirstRequirementSolveTime() {
|
||||||
|
return start -> {
|
||||||
|
start.menuClickClientRequirements()
|
||||||
|
.clickRefreshRequirements();
|
||||||
|
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("H:mm:ss");
|
||||||
|
LocalTime statusBarTime = LocalTime.parse(start.getStatusBarContent().split(" ")[0], formatter);
|
||||||
|
LocalTime requirementSolveTime = LocalTime.parse(start.getFirstRequirementSolveDate().split(" ")[1], formatter);
|
||||||
|
Assertions.assertTrue(Duration.between(statusBarTime, requirementSolveTime).getSeconds() <= 1,
|
||||||
|
"Time difference between status bar time and requirement solve time is greater than 1 second");
|
||||||
|
return start;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,9 +32,9 @@ public class CurrentAccountTasks {
|
|||||||
.clickSendButton()
|
.clickSendButton()
|
||||||
.onTransactionsPage()
|
.onTransactionsPage()
|
||||||
.clickBack()
|
.clickBack()
|
||||||
.clickDemand()
|
.menuClickClientRequirements()
|
||||||
.clickRefreshRequirementButton()
|
.clickRefreshRequirements()
|
||||||
.checkDemandDescriptionFirstRow("UFO - Bězný účet - Výpisy - Zaslání přes KC")
|
.assertFirstRequirementDescription("UFO - Bězný účet - Výpisy - Zaslání přes KC")
|
||||||
.clickRefreshClientButton();
|
.clickRefreshClientButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,9 +30,7 @@ public class DebitCardChangesTasks {
|
|||||||
.clickInternetTransactionsOn()
|
.clickInternetTransactionsOn()
|
||||||
.clickSaveSettings()
|
.clickSaveSettings()
|
||||||
.checkPaymentsThroughMotoInternet("Zapnuto - vše")
|
.checkPaymentsThroughMotoInternet("Zapnuto - vše")
|
||||||
.clickDemand()
|
.then(harness.tasks().ufo().operations().clientDetails().assertFirstRequirementSolveDate());
|
||||||
.clickRefreshRequirementButton()
|
|
||||||
.checkDateInRequirement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Function<STS701_S002_ClientDetailPage, STS701_S002_ClientDetailPage> stepsToTurnOffInternetPayments() {
|
public Function<STS701_S002_ClientDetailPage, STS701_S002_ClientDetailPage> stepsToTurnOffInternetPayments() {
|
||||||
@ -41,9 +39,7 @@ public class DebitCardChangesTasks {
|
|||||||
.clickInternetTransactionsOff()
|
.clickInternetTransactionsOff()
|
||||||
.clickSaveSettings()
|
.clickSaveSettings()
|
||||||
.checkPaymentsThroughMotoInternet("Vypnuto - vše")
|
.checkPaymentsThroughMotoInternet("Vypnuto - vše")
|
||||||
.clickDemand()
|
.then(harness.tasks().ufo().operations().clientDetails().assertFirstRequirementSolveDate());
|
||||||
.clickRefreshRequirementButton()
|
|
||||||
.checkDateInRequirement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Function<PLK708_S001_DataChangesPage, STS701_S002_ClientDetailPage> setSendingAddressAndCheckChange(Address address, String postOffice, String requirementFirstRowText) {
|
public Function<PLK708_S001_DataChangesPage, STS701_S002_ClientDetailPage> setSendingAddressAndCheckChange(Address address, String postOffice, String requirementFirstRowText) {
|
||||||
@ -56,9 +52,7 @@ public class DebitCardChangesTasks {
|
|||||||
.checkPostOfficeInput(postOffice)
|
.checkPostOfficeInput(postOffice)
|
||||||
.clickSaveButton()
|
.clickSaveButton()
|
||||||
.checkDebitCardSendingAddressStreetLabel(address.getStreet() + " " + address.getDescriptiveNumber())
|
.checkDebitCardSendingAddressStreetLabel(address.getStreet() + " " + address.getDescriptiveNumber())
|
||||||
.clickDemand()
|
.then(harness.tasks().ufo().operations().clientDetails().assertFirstRequirementSolveDate())
|
||||||
.clickRefreshRequirementButton()
|
.assertFirstRequirementDescription(requirementFirstRowText);
|
||||||
.checkDateInRequirement()
|
|
||||||
.checkDemandDescriptionFirstRow(requirementFirstRowText);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ public class OperationsTasks {
|
|||||||
return new SavingAccountTasks(harness);
|
return new SavingAccountTasks(harness);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GdprTasks GdprTasks() {
|
public GdprTasks gdprTasks() {
|
||||||
return new GdprTasks(harness);
|
return new GdprTasks(harness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ public class PaymentOrderTasks {
|
|||||||
.fillRecipientAccountNumber(accountNumberRecipient)
|
.fillRecipientAccountNumber(accountNumberRecipient)
|
||||||
.fillAmount(amount)
|
.fillAmount(amount)
|
||||||
.clickSend()
|
.clickSend()
|
||||||
.checkTransactionSuccessfullyEstablished("Transakce byla úspěšně založena pod ID:")
|
.assertStatusBarContent("Transakce byla úspěšně založena pod ID:")
|
||||||
.saveTaskIDPaymentOrder()
|
.saveTaskIDPaymentOrder()
|
||||||
.clickHomePage();
|
.clickHomePage();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
package cz.moneta.test.dsl.util.task.ufo.operations;
|
package cz.moneta.test.dsl.util.task.ufo.operations;
|
||||||
|
|
||||||
import cz.moneta.test.dsl.Harness;
|
import cz.moneta.test.dsl.Harness;
|
||||||
import cz.moneta.test.dsl.ufo.operations.client.clientDetail.STS701_S002_ClientDetailPage;
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.search.OPS001_S001_ClientSearchPageUfoOperations;
|
import cz.moneta.test.dsl.ufo.operations.search.OPS001_S001_ClientSearchPageUfoOperations;
|
||||||
import cz.moneta.test.dsl.ufo.operations.search.SearchBy;
|
|
||||||
import cz.moneta.test.dsl.ufo.operations.ufoOperations.*;
|
import cz.moneta.test.dsl.ufo.operations.ufoOperations.*;
|
||||||
import cz.moneta.test.dsl.util.DateUtils;
|
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.random.RandomGenerator;
|
import java.util.random.RandomGenerator;
|
||||||
|
|
||||||
import static cz.moneta.test.dsl.ufo.operations.ufoOperations.PSP701_S004_PrintTemplatePage.ATTACHMENT_PATH;
|
|
||||||
import static cz.moneta.test.dsl.ufo.operations.ufoOperations.UKO720_S001_TaskList.TASK_ID_KEY;
|
import static cz.moneta.test.dsl.ufo.operations.ufoOperations.UKO720_S001_TaskList.TASK_ID_KEY;
|
||||||
import static cz.moneta.test.dsl.ufo.operations.ufoOperations.UKO720_S001_TaskPage.ID_OBJECT_IN_TASK_KEY;
|
import static cz.moneta.test.dsl.ufo.operations.ufoOperations.UKO720_S001_TaskPage.ID_OBJECT_IN_TASK_KEY;
|
||||||
import static cz.moneta.test.dsl.ufo.operations.ufoOperations.taskslist.TypesOfViewFilter.*;
|
import static cz.moneta.test.dsl.ufo.operations.ufoOperations.taskslist.TypesOfViewFilter.*;
|
||||||
@ -97,7 +93,7 @@ public class TasksTasks {
|
|||||||
public Function<UKO720_S001_TaskPage, UKO720_S001_TaskPage> checkClientDetailInfo(String rcOfExistingClient) {
|
public Function<UKO720_S001_TaskPage, UKO720_S001_TaskPage> checkClientDetailInfo(String rcOfExistingClient) {
|
||||||
return start -> start
|
return start -> start
|
||||||
.clickClientDetailInfo()
|
.clickClientDetailInfo()
|
||||||
.checkClientRc(rcOfExistingClient)
|
.assertClientRc(rcOfExistingClient)
|
||||||
.checkPageNotContainsMenuElements()
|
.checkPageNotContainsMenuElements()
|
||||||
.closeSecondWindow();
|
.closeSecondWindow();
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user