jms -> mq

This commit is contained in:
Radek Davidek 2026-04-20 10:17:56 +02:00
parent 70c4540c4a
commit ab7d898b8e
5554 changed files with 439957 additions and 439459 deletions

View File

@ -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>

View File

@ -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;
}
}
} }

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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";

View File

@ -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);
}
}

View File

@ -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"));
}
}

View File

@ -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);
} }

View File

@ -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);
}
} }
} }

View File

@ -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();
}
}

View File

@ -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
}

View File

@ -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();
}

View File

@ -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
}

View File

@ -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 + '\'' +
'}';
}
}

View File

@ -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

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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 + '\'' +
'}';
} }
} }

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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>

View File

@ -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);
} }

View File

@ -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();

View File

@ -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)

View File

@ -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();

View File

@ -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']]";

View File

@ -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();

View File

@ -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;
} }

View File

@ -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);
}
} }

View File

@ -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();

View File

@ -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)

View File

@ -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();
}

View File

@ -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;

View File

@ -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();
} }

View File

@ -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;
} }

View File

@ -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;
}
} }

View File

@ -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();
}
}

View File

@ -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);
}
} }

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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";
}

View File

@ -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;

View File

@ -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']";
}

View File

@ -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']";

View File

@ -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();

View File

@ -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();
} }

View File

@ -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();

View File

@ -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')]";
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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() {

View File

@ -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']";
} }

View File

@ -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();

View File

@ -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);
} }

View File

@ -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);
}
} }

View File

@ -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;
}
}

View File

@ -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";
}
}

View File

@ -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();
}

View File

@ -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;
}
} }

View File

@ -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);

View File

@ -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;
} }

View File

@ -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?")

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
} }

View File

@ -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();
}

View File

@ -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)

View File

@ -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();

View File

@ -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();
}

View File

@ -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);

View File

@ -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();

View File

@ -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";

View File

@ -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;
} }
} }

View File

@ -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;
} }

View File

@ -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) {

View File

@ -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) {

View File

@ -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;
} }
} }

View File

@ -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";
} }
} }

View File

@ -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;

View File

@ -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);
}
} }

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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;
};
}
} }

View File

@ -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();
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }

View File

@ -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();
} }

View File

@ -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