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>
<cxf.version>4.0.3</cxf.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>
<confluent.version>7.6.0</confluent.version>
<assertj.version>3.24.2</assertj.version>
@ -296,12 +295,6 @@
<artifactId>com.ibm.mq.allclient</artifactId>
<version>${ibm.mq.version}</version>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>javax.jms-api</artifactId>
<version>${javax.jms.version}</version>
</dependency>
<!-- Kafka dependencies -->
<dependency>
<groupId>org.apache.kafka</groupId>

View File

@ -1,24 +1,23 @@
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.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
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.SSLContext;
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.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 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.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
* multi-instance Queue Manager, SSL/TLS, and multiple message formats.
* <p>
* 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
* IBM MQ connector using the native com.ibm.mq classes. Supports
* multi-instance Queue Manager connection lists, SSL/TLS, message properties,
* and JSON/XML/UTF-8/EBCDIC payload formats.
*/
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 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 JMSContext jmsContext;
private final String connectionNameList;
private final String channel;
private final String queueManager;
private final String user;
private final String password;
private final SSLSocketFactory sslSocketFactory;
private final String sslCipherSuite;
private MQQueueManager mqQueueManager;
/**
* 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,
String keystorePath, String keystorePassword, String sslCipherSuite) {
this.connectionNameList = connectionNameList;
this.channel = channel;
this.queueManager = queueManager;
this.user = user;
this.password = password;
this.sslCipherSuite = sslCipherSuite;
try {
connectionFactory = new MQConnectionFactory();
connectionFactory.setConnectionNameList(connectionNameList);
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
this.sslSocketFactory = keystorePath != null && !keystorePath.isBlank() && keystorePassword != null
&& !keystorePassword.isBlank() ? getSslSocketFactory(keystorePath, keystorePassword) : null;
connect();
} catch (Exception 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() {
try {
this.jmsContext = connectionFactory.createContext(user, password, JMSContext.AUTO_ACKNOWLEDGE);
this.jmsContext.start();
this.mqQueueManager = new MQQueueManager(queueManager, createConnectionProperties());
LOG.info("Connected to IBM MQ: {}", queueManager);
} catch (Exception e) {
} catch (MQException e) {
throw new MessagingConnectionException(
"Failed to connect to IBM MQ: " + queueManager + " - " + e.getMessage(), e);
}
}
/**
* Send a JSON or XML message as TextMessage.
*/
private void sendTextMessage(String queueName, String payload, Map<String, String> properties) {
javax.jms.Queue queue = getQueue(queueName);
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);
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);
}
}
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);
}
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);
return properties;
}
/**
* Send a message as BytesMessage with specific encoding and CCSID.
* Send a JSON or XML message as MQ string message.
*/
private void sendTextMessage(String queueName, String payload, Map<String, String> properties) {
sendMessage(queueName, payload.getBytes(UTF_8), UTF_8, 1208, CMQC.MQFMT_STRING, properties, "JSON/XML");
}
/**
* Send a message as raw bytes with specific encoding and CCSID.
*/
private void sendBytesMessage(String queueName, String payload, Charset charset, int ccsid,
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();
// Convert payload to bytes using specified charset
byte[] bytes = payload.getBytes(charset);
private void sendMessage(String queueName, byte[] payload, Charset charset, int ccsid, String mqFormat,
Map<String, String> properties, String logFormat) {
MQQueue queue = null;
try {
message.writeBytes(bytes);
message.setIntProperty("CCSID", ccsid);
} catch (JMSException e) {
throw new MessagingDestinationException("Failed to create bytes message", e);
}
int openOptions = CMQC.MQOO_OUTPUT | CMQC.MQOO_FAIL_IF_QUIESCING;
// 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);
}
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);
}
MQPutMessageOptions putOptions = new MQPutMessageOptions();
putOptions.options = CMQC.MQPMO_NO_SYNCPOINT | CMQC.MQPMO_FAIL_IF_QUIESCING;
applyMessageProperties(message, properties);
queue.put(message, putOptions);
} catch (MQException | IOException e) {
throw new MessagingDestinationException("Failed to send message to queue: " + queueName, e);
} finally {
closeQueue(queue, queueName);
}
try {
jmsContext.createProducer().send(queue, message);
} catch (RuntimeException e) {
throw new MessagingDestinationException("Failed to send message to queue: " + queueName, e);
}
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 payload Message payload
* @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) {
switch (format) {
@ -234,56 +209,99 @@ public class IbmMqConnector implements Connector {
* Receive a message from a queue with timeout.
*
* @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 timeout Timeout duration
* @return Received message
*/
public ReceivedMessage receive(String queueName, String messageSelector, MqMessageFormat format,
java.time.Duration timeout) {
long timeoutMs = timeout.toMillis();
public ReceivedMessage receive(String queueName, String messageSelector, MqMessageFormat format, Duration timeout) {
if (messageSelector == null || messageSelector.isBlank()) {
return receiveNext(queueName, format, timeout);
}
javax.jms.Queue queue = getQueue(queueName);
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;
return receiveMatching(queueName, messageSelector, format, timeout);
}
private ReceivedMessage receiveNext(String queueName, MqMessageFormat format, Duration timeout) {
MQQueue queue = null;
try {
while (remainingTime > 0 && !messageFound.get()) {
Message message = consumer.receive(remainingTime);
queue = openQueue(queueName, CMQC.MQOO_INPUT_SHARED | CMQC.MQOO_FAIL_IF_QUIESCING);
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) {
received = decodeMessage(message, queueName, format);
messageFound.set(true);
} else {
// Exponential backoff
pollInterval = Math.min(pollInterval * 2, DEFAULT_MAX_POLL_INTERVAL_MS);
remainingTime -= pollInterval;
}
}
if (received == null) {
queue.get(message, getOptions);
return decodeMessage(message, queueName, format);
} catch (MQException e) {
if (e.reasonCode == CMQC.MQRC_NO_MSG_AVAILABLE) {
throw new MessagingTimeoutException("No message matching filter found on queue '" + queueName
+ "' 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);
} finally {
try {
consumer.close();
} catch (JMSRuntimeException e) {
LOG.warn("Failed to close consumer", e);
closeQueue(queue, queueName);
}
}
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);
}
}
@ -291,7 +309,8 @@ public class IbmMqConnector implements Connector {
* Browse a queue (non-destructive read).
*
* @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 maxMessages Maximum number of messages to browse
* @return List of received messages
@ -299,170 +318,268 @@ public class IbmMqConnector implements Connector {
public List<ReceivedMessage> browse(String queueName, String messageSelector, MqMessageFormat format,
int maxMessages) {
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())
? jmsContext.createBrowser(queue)
: jmsContext.createBrowser(queue, messageSelector)) {
try {
queue = openQueue(queueName, CMQC.MQOO_BROWSE | CMQC.MQOO_FAIL_IF_QUIESCING);
Enumeration<?> enumeration = browser.getEnumeration();
int count = 0;
MQGetMessageOptions browseOptions = new MQGetMessageOptions();
browseOptions.options = CMQC.MQGMO_BROWSE_FIRST | CMQC.MQGMO_NO_SYNCPOINT | CMQC.MQGMO_FAIL_IF_QUIESCING;
while (enumeration.hasMoreElements() && count < maxMessages) {
Message message = (Message) enumeration.nextElement();
if (message != null) {
ReceivedMessage received = decodeMessage(message, queueName, format);
messages.add(received);
count++;
while (messages.size() < maxMessages) {
MQMessage message = new MQMessage();
try {
queue.get(message, browseOptions);
} catch (MQException e) {
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;
} catch (JMSException e) {
} catch (MQException 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) {
long timestamp;
try {
timestamp = jmsMessage.getJMSTimestamp();
} catch (JMSException e) {
timestamp = System.currentTimeMillis();
}
private ReceivedMessage decodeMessage(MQMessage mqMessage, String queueName, MqMessageFormat format) {
long timestamp = mqMessage.putDateTime != null ? mqMessage.putDateTime.getTimeInMillis()
: System.currentTimeMillis();
if (timestamp == 0) {
timestamp = System.currentTimeMillis();
}
Map<String, String> headers = new HashMap<>();
extractMqHeadersAndProperties(mqMessage, headers, queueName);
byte[] data = readMessageBody(mqMessage);
String body;
MessageContentType contentType;
Map<String, String> headers = new HashMap<>();
// Extract JMS properties as headers
extractJmsProperties(jmsMessage, headers);
if (jmsMessage instanceof TextMessage textMessage) {
try {
body = textMessage.getText();
} catch (JMSException e) {
throw new RuntimeException("Failed to read text message body", e);
}
contentType = switch (format) {
case XML -> MessageContentType.XML;
default -> 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);
switch (format) {
case XML -> {
body = new String(data, charsetFor(mqMessage.characterSet, UTF_8));
contentType = MessageContentType.XML;
}
case JSON -> {
body = new String(data, charsetFor(mqMessage.characterSet, UTF_8));
contentType = MessageContentType.JSON;
}
case EBCDIC_870 -> {
body = new String(data, EBCDIC_870);
contentType = MessageContentType.RAW_TEXT;
} else {
try {
throw new IllegalArgumentException("Unsupported message type: " + jmsMessage.getJMSType());
} catch (JMSException e) {
throw new IllegalArgumentException("Unsupported message type", e);
}
}
case UTF8_1208 -> {
body = new String(data, UTF_8);
contentType = MessageContentType.RAW_TEXT;
}
default -> {
body = new String(data, UTF_8);
contentType = MessageContentType.RAW_TEXT;
}
}
return new ReceivedMessage(body, contentType, headers, timestamp, queueName, null);
}
/**
* Decode BytesMessage body based on CCSID.
*/
private String decodeBytesMessage(BytesMessage bytesMessage, int ccsid) {
private byte[] readMessageBody(MQMessage message) {
try {
long bodyLength;
try {
bodyLength = bytesMessage.getBodyLength();
} catch (JMSException e) {
throw new RuntimeException("Failed to get message body length", e);
}
byte[] data = new byte[(int) bodyLength];
bytesMessage.readBytes(data);
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);
message.seek(0);
int length = message.getMessageLength();
byte[] data = new byte[length];
message.readFully(data);
return data;
} catch (EOFException e) {
throw new RuntimeException("Failed to seek message body", e);
} catch (IOException e) {
throw new RuntimeException("Failed to read message body", e);
}
}
/**
* Extract JMS properties as headers.
* Extract MQ headers and message properties as headers.
*/
@SuppressWarnings("unchecked")
private void extractJmsProperties(Message message, Map<String, String> headers) {
try {
// Common JMS headers
headers.put("JMSMessageID", message.getJMSMessageID());
try {
headers.put("JMSType", message.getJMSType() != null ? message.getJMSType() : "");
} 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", "");
}
private void extractMqHeadersAndProperties(MQMessage message, Map<String, String> headers, String queueName) {
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() : "");
// Extract custom properties
Enumeration<String> propertyNames = (Enumeration<String>) message.getPropertyNames();
while (propertyNames.hasMoreElements()) {
String propName = propertyNames.nextElement();
Enumeration<String> propertyNames;
try {
propertyNames = message.getPropertyNames("%");
} catch (MQException e) {
LOG.warn("Failed to extract MQ properties", e);
return;
}
while (propertyNames.hasMoreElements()) {
String propName = propertyNames.nextElement();
try {
Object propValue = message.getObjectProperty(propName);
if (propValue != null) {
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);
}
}
/**
* Get Queue object from queue name.
*/
private javax.jms.Queue getQueue(String queueName) {
return jmsContext.createQueue(queueName);
private void applyMessageProperties(MQMessage message, Map<String, String> properties) {
if (properties == null) {
return;
}
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
public void close() {
if (jmsContext != null) {
if (mqQueueManager != null && mqQueueManager.isConnected()) {
try {
jmsContext.close();
mqQueueManager.disconnect();
LOG.info("Closed connection to IBM MQ: {}", queueManager);
} catch (Exception e) {
} catch (MQException e) {
LOG.error("Failed to close IBM MQ connection", e);
}
}
@ -499,4 +616,34 @@ public class IbmMqConnector implements Connector {
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;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.function.Predicate;
import cz.moneta.test.harness.connectors.messaging.kafkautils.CustomKafkaAvroDeserializer;
import cz.moneta.test.harness.connectors.messaging.kafkautils.JsonToAvroConverter;
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.MessagingSchemaException;
import cz.moneta.test.harness.support.messaging.exception.MessagingTimeoutException;
import cz.moneta.test.harness.support.messaging.kafka.MessageContentType;
import cz.moneta.test.harness.support.messaging.kafka.ReceivedMessage;
import io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient;
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.kafka.clients.consumer.ConsumerConfig;
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.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import cz.moneta.test.harness.messaging.exception.MessagingConnectionException;
import cz.moneta.test.harness.messaging.exception.MessagingDestinationException;
import cz.moneta.test.harness.messaging.exception.MessagingSchemaException;
import cz.moneta.test.harness.messaging.exception.MessagingTimeoutException;
import cz.moneta.test.harness.support.messaging.kafka.MessageContentType;
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;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.function.Predicate;
/**
* 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 {
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 consumerConfig;
@ -70,35 +67,45 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
String schemaRegistryApiKey,
String schemaRegistryApiSecret) {
this.schemaRegistryUrl = schemaRegistryUrl;
this.schemaRegistryClient = new CachedSchemaRegistryClient(
Collections.singletonList(schemaRegistryUrl), 100, new HashMap<>());
this.producerConfig = createProducerConfig(bootstrapServers, apiKey, apiSecret);
this.consumerConfig = createConsumerConfig(bootstrapServers, schemaRegistryApiKey, schemaRegistryApiSecret);
HashMap<String, String> schemaRegistryProps = new HashMap<>();
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.
*/
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();
config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.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.LINGER_MS_CONFIG, 1);
config.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
// SASL/PLAIN authentication
// 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 + "\";");
config.put(AbstractKafkaSchemaSerDeConfig.AUTO_REGISTER_SCHEMAS, false);
config.put(AbstractKafkaSchemaSerDeConfig.USE_LATEST_VERSION, true);
config.put(AbstractKafkaSchemaSerDeConfig.SCHEMA_REGISTRY_URL_CONFIG, schemaRegistryUrl);
config.put(SchemaRegistryClientConfig.BASIC_AUTH_CREDENTIALS_SOURCE, "USER_INFO");
config.put(SchemaRegistryClientConfig.USER_INFO_CONFIG, schemaRegistryApiKey + ":" + schemaRegistryApiSecret);
// SSL configuration
// config.put("ssl.endpoint.identification.algorithm", "https");
// SASL/PLAIN authentication
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;
}
@ -106,14 +113,16 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
/**
* 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();
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
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.ENABLE_AUTO_COMMIT_CONFIG, false);
// SASL/PLAIN authentication
config.put("security.protocol", "SASL_SSL");
config.put("sasl.mechanism", "PLAIN");
@ -122,7 +131,12 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
"username=\"" + apiKey + "\" password=\"" + apiSecret + "\";");
// 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);
// SSL configuration
@ -179,7 +193,7 @@ public class KafkaConnector implements cz.moneta.test.harness.connectors.Connect
*/
public List<ReceivedMessage> receive(String topic,
Predicate<ReceivedMessage> filter,
Duration timeout) {
Duration timeout, boolean startFromBeginning) {
KafkaConsumer<String, GenericRecord> consumer = null;
try {
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");
}
// Assign partitions and seek to end
consumer.assign(partitions);
// consumer.seekToBeginning(partitions);
consumer.seekToBeginning(partitions);
if (startFromBeginning) {
consumer.seekToBeginning(partitions);
} else {
consumer.seekToEnd(partitions);
}
// Poll loop with exponential backoff
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) {
try {
String jsonBody = avroToJson(record.value());
String jsonBody;
if (null != record.value()) {
jsonBody = avroToJson(record.value());
} else {
jsonBody = "";
}
Map<String, String> headers = new HashMap<>();
Headers kafkaHeaders = record.headers();
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) {
try {
return record.toString();
} catch (Exception 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 org.apache.avro.Schema;
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.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.List;
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);
return result;
}
@ -86,7 +80,7 @@ public class JsonToAvroConverter {
return type;
}
private static Object jsonPrimitiveToAvro(JsonPrimitive primitive, Schema schema){
private static Object jsonPrimitiveToAvro(JsonPrimitive primitive, Schema schema) {
switch (schema.getType()) {
case 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_PASSWORD_CONFIG = "vault.password";
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_CAGW_KEYS_PATH = "vault.cagw.client.secrets.path";
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.Logger;
import cz.moneta.test.harness.connectors.VaultConnector;
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.endpoints.Endpoint;
import cz.moneta.test.harness.messaging.MqMessageFormat;
import cz.moneta.test.harness.messaging.ReceivedMessage;
import cz.moneta.test.harness.support.messaging.MqMessageFormat;
import cz.moneta.test.harness.support.messaging.ReceivedMessage;
import cz.moneta.test.harness.support.auth.AuthSupport;
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 VAULT_PATH_KEY = "vault.imq-first-vision.secrets.path";
private static final String VAULT_KEYSTORE_PASSWORD_KEY = "keystorePassword";
private static final String KEYSTORE_PATH = "keystores/imq-keystore.jks";
private static final String KEYSTORE_PATH = "keystores/imq.jks";
/**
* Constructor that reads configuration from StoreAccessor.
@ -79,25 +77,10 @@ public class ImqFirstVisionEndpoint implements Endpoint {
*/
private void loadCredentialsFromVault() {
try {
// Get vault URL from configuration
String vaultPath = getConfig(VAULT_PATH_KEY);
String vaultUrl = getConfig(HarnessConfigConstants.VAULT_URL_CONFIG);
String vaultUser = getConfig(HarnessConfigConstants.VAULT_USERNAME_CONFIG);
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);
}
Credentials credentials = AuthSupport.getCredentials("imq-first-vision", store);
this.username = credentials.getUsername();
this.password = credentials.getPassword();
this.keystorePassword = AuthSupport.getClientSecret(VAULT_KEYSTORE_PASSWORD_KEY, store, VAULT_PATH_KEY);
} catch (Exception e) {
throw new IllegalStateException("Failed to load credentials from Vault", e);
}

View File

@ -1,21 +1,16 @@
package cz.moneta.test.harness.endpoints.kafka;
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.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 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.util.HashMap;
import java.util.List;
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.
@ -55,16 +50,10 @@ public class KafkaEndpoint implements Endpoint {
}
// Retrieve credentials from Vault
String vaultPath = store.getConfig("vault.kafka.secrets.path");
if (vaultPath == null) {
throw new IllegalStateException(
"You need to configure vault.kafka.secrets.path");
}
//
String apiKey = getVaultValue(vaultPath, "apiKey");
String apiSecret = getVaultValue(vaultPath, "apiSecret");
String schemaRegistryApiKey = getVaultValue(vaultPath, "schemaRegistryApiKey");
String schemaRegistryApiSecret = getVaultValue(vaultPath, "schemaRegistryApiSecret");
String apiKey = getVaultValue("apiKey");
String apiSecret = getVaultValue("apiSecret");
String schemaRegistryApiKey = getVaultValue("schemaRegistryApiKey");
String schemaRegistryApiSecret = getVaultValue("schemaRegistryApiSecret");
// Create connector
this.connector = new KafkaConnector(
@ -99,16 +88,16 @@ public class KafkaEndpoint implements Endpoint {
*/
public List<ReceivedMessage> receive(String topic,
java.util.function.Predicate<ReceivedMessage> filter,
Duration timeout) {
return connector.receive(topic, filter, timeout);
Duration timeout, boolean startFromBeginning) {
return connector.receive(topic, filter, timeout, startFromBeginning);
}
/**
* Receives a message with default timeout (30 seconds).
*/
public List<ReceivedMessage> receive(String topic,
java.util.function.Predicate<ReceivedMessage> filter) {
return receive(topic, filter, Duration.ofSeconds(30));
java.util.function.Predicate<ReceivedMessage> filter, boolean startFromBeginning) {
return receive(topic, filter, Duration.ofSeconds(30), startFromBeginning);
}
/**
@ -118,8 +107,8 @@ public class KafkaEndpoint implements Endpoint {
* @param timeout Maximum time to wait
* @return First message
*/
public List<ReceivedMessage> receive(String topic, Duration timeout) {
return receive(topic, msg -> true, timeout);
public List<ReceivedMessage> receive(String topic, Duration timeout, boolean startFromBeginning) {
return receive(topic, msg -> true, timeout, startFromBeginning);
}
/**
@ -164,36 +153,7 @@ public class KafkaEndpoint implements Endpoint {
/**
* Retrieves a value from Vault.
*/
private String getVaultValue(String path, String key) {
try {
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);
}
private String getVaultValue(String key) {
return AuthSupport.getClientSecret(key, store, VAULT_KAFKA_KEYS_CONFIG);
}
}

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.ImqFirstVisionQueue;
import cz.moneta.test.harness.exception.HarnessException;
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.MessagingTimeoutException;
import cz.moneta.test.harness.support.messaging.exception.MessagingTimeoutException;
import cz.moneta.test.harness.support.util.FileReader;
import cz.moneta.test.harness.support.util.Template;
import org.apache.commons.lang3.StringUtils;
@ -381,7 +378,7 @@ public final class ImqRequest {
@Override
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
@ -556,8 +553,8 @@ public final class ImqRequest {
}
@Override
public cz.moneta.test.harness.support.messaging.ReceivedMessage getMessage() {
return cz.moneta.test.harness.support.messaging.ReceivedMessage.fromMessagingReceivedMessage(message);
public ReceivedMessage getMessage() {
return message;
}
@Override

View File

@ -5,15 +5,17 @@ package cz.moneta.test.harness.support.messaging;
*/
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,
/**
* XML content - body is an XML string, can use XPath for extraction
* XML content - body is an XML string.
*/
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
}

View File

@ -1,23 +1,31 @@
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 {
/**
* 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,
/**
* 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,
/**
* 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,
/**
* 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
}

View File

@ -2,36 +2,32 @@ package cz.moneta.test.harness.support.messaging;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
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.XPathExpressionException;
import javax.xml.xpath.XPathConstants;
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.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
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>
* Provides unified API for accessing message content regardless of source system.
* Body is always normalized to a String, with content type detection for proper extraction.
* </p>
* For Kafka: Avro GenericRecord is automatically converted to JSON.
* For IBM MQ (JSON): JSON string from MQ string message.
* 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 {
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 MessageContentType contentType;
@ -40,80 +36,75 @@ public class ReceivedMessage {
private final String source;
private final String key;
private ReceivedMessage(Builder builder) {
this.body = builder.body;
this.contentType = builder.contentType;
this.headers = builder.headers != null ? Collections.unmodifiableMap(new HashMap<>(builder.headers)) : Collections.emptyMap();
this.timestamp = builder.timestamp;
this.source = builder.source;
this.key = builder.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;
}
/**
* Creates a new builder for ReceivedMessage.
*/
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>
* Extract a JSON value using JSON path (dot/bracket notation).
* Supports paths like "items[0].sku" or "nested.field".
*
* @param path the JSON path expression
* @return the extracted value as JsonNode
* @param path JSON path
* @return JsonNode for the extracted value
*/
public JsonNode extractJson(String path) {
if (contentType != MessageContentType.JSON) {
throw new IllegalStateException("JSON extraction is only supported for JSON content type, got: " + contentType);
if (body == null || StringUtils.isEmpty(path)) {
return null;
}
try {
JsonNode rootNode = JSON_MAPPER.readTree(body);
return extractNode(path, rootNode);
} catch (IOException e) {
throw new RuntimeException("Failed to parse JSON body: " + body, e);
JsonNode root = JSON_MAPPER.readTree(body);
return evaluateJsonPath(root, path);
} catch (Exception 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
* @return the extracted value as String
* @param xpathExpression XPath expression
* @return extracted value as string
*/
public String extractXml(String xpath) {
if (contentType != MessageContentType.XML) {
throw new IllegalStateException("XML extraction is only supported for XML content type, got: " + contentType);
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);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)));
XPath xPath = XPathFactory.newInstance().newXPath();
return xPath.evaluate(xpath, doc);
} catch (XPathExpressionException e) {
throw new RuntimeException("Failed to evaluate XPath: " + xpath, e);
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 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)
* @return the extracted value as String
* @param expression JSON path or XPath expression
* @return extracted value as string
*/
public String extract(String expression) {
return switch (contentType) {
@ -124,181 +115,272 @@ public class ReceivedMessage {
}
/**
* Returns the message body as a String.
*
* @return the body content
* Evaluate JSON path on a JSON node.
* Supports dot notation and bracket notation for arrays.
*/
public String getBody() {
return body;
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;
}
/**
* Returns the message content type.
*
* @return the content type
* Tokenize JSON path into segments.
*/
public MessageContentType getContentType() {
return contentType;
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]);
}
/**
* Returns a header value by name.
*
* @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
* Get the message key (Kafka message key, null for IBM MQ).
*/
public String getKey() {
return key;
}
/**
* Deserializes the message body into a Java object.
* <p>
* For JSON content: uses Jackson ObjectMapper.readValue
* For XML content: uses Jackson XmlMapper
* </p>
* 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 the target class
* @param <T> the target type
* @return the deserialized object
* @param type target type
* @param <T> target type
* @return deserialized object
*/
public <T> T mapTo(Class<T> type) {
try {
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) {
if (body == null) {
return null;
}
cz.moneta.test.harness.support.messaging.MessageContentType contentType =
switch (other.getContentType()) {
case JSON -> cz.moneta.test.harness.support.messaging.MessageContentType.JSON;
case XML -> cz.moneta.test.harness.support.messaging.MessageContentType.XML;
case RAW_TEXT -> cz.moneta.test.harness.support.messaging.MessageContentType.RAW_TEXT;
};
return builder()
.body(other.getBody())
.contentType(contentType)
.headers(other.getHeaders())
.timestamp(other.getTimestamp())
.source(other.getSource())
.key(other.getKey())
.build();
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

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

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.

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.

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.

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.

View File

@ -1,25 +1,19 @@
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.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import cz.moneta.test.harness.endpoints.kafka.KafkaEndpoint;
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.
@ -69,6 +63,8 @@ public class KafkaRequest {
* @return KafkaReceiveFilterPhase for filter configuration
*/
KafkaReceiveFilterPhase fromTopic(String topic);
}
/**
@ -130,8 +126,8 @@ public class KafkaRequest {
/**
* Appends a value to an array in the JSON payload.
*
* @param path Path to array (e.g., "items")
* @param value Value to append
* @param path Path to array (e.g., "items")
* @param value Value to append
* @return this for chaining
*/
KafkaPayloadPhase appendToArray(String path, Object value);
@ -187,6 +183,20 @@ public class KafkaRequest {
* Phase 2b: Configure filter for receiving.
*/
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.
*
@ -229,7 +239,8 @@ public class KafkaRequest {
// Receive configuration
private Predicate<ReceivedMessage> filter;
private Duration timeout;
//default true
private boolean startFromBeginning = true;
// Response (after receive)
private List<ReceivedMessage> messages;
@ -363,6 +374,18 @@ public class KafkaRequest {
return this;
}
@Override
public KafkaReceiveFilterPhase startFromBeginning() {
this.startFromBeginning = true;
return this;
}
@Override
public KafkaReceiveFilterPhase startFromEnd() {
this.startFromBeginning = false;
return this;
}
@Override
public KafkaAwaitingPhase receiveWhere(Predicate<ReceivedMessage> filter) {
this.filter = filter;
@ -372,7 +395,7 @@ public class KafkaRequest {
@Override
public MessageResponse withTimeout(long duration, TimeUnit unit) {
this.timeout = Duration.of(duration, unit.toChronoUnit());
messages = endpoint.receive(topic, filter, timeout);
messages = endpoint.receive(topic, filter, timeout, startFromBeginning);
return this;
}

Binary file not shown.

View File

@ -1,4 +1,5 @@
Hello World!!!
Hello World Too!!!
# Automated tests
This repo contains automated tests for all squads.

View File

@ -73,24 +73,6 @@
</activation>
<build>
<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>
<artifactId>maven-compiler-plugin</artifactId>
<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.hypos.Hypos;
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.imq.ImqFirstVision;
import cz.moneta.test.dsl.kafka.Kafka;
@ -142,7 +143,6 @@ public class Harness extends BaseStoreAccessor {
return new Ufo(this, SECOND_BANKER_TOKEN);
}
@Deprecated
public Oauth2Web withOauth2Web() {
return new Oauth2Web(this);
}
@ -191,6 +191,10 @@ public class Harness extends BaseStoreAccessor {
return new AresApiBuilder(this);
}
public PaeMqBuilder withPaeMq() {
return new PaeMqBuilder(this);
}
public Sb withSB() {
return new Sb(this);
}

View File

@ -152,6 +152,7 @@ public interface CustomerPage extends SmartAutoFlow<CustomerPage>, StoreAccessor
@TypeInto(NAME)
CustomerPage typeName(String name);
@Wait(value = PHONE_NUMBER, until = Until.VISIBLE)
@TypeInto(PHONE_NUMBER)
CustomerPage typePhoneNumber(String phoneNumber);
@ -331,6 +332,7 @@ public interface CustomerPage extends SmartAutoFlow<CustomerPage>, StoreAccessor
@Click(value = STAY_TYPE_CHOOSE, jsClick = true)
CustomerPage chooseStayType(StayType stayType);
@Wait(value = BUSINESSMAN_PHONE_NUMBER, until = Until.VISIBLE)
@TypeInto(BUSINESSMAN_PHONE_NUMBER)
CustomerPage typeBusinessmanPhoneNumber(String phoneNumber);
@ -355,6 +357,7 @@ public interface CustomerPage extends SmartAutoFlow<CustomerPage>, StoreAccessor
@Click(NUMBER_OF_EMPLOYEES_FIELD)
CustomerPage chooseNoOfEmployees();
@Wait (value = BUSINESSMAN_SILENT_COMPANION, until = Until.CLICKABLE)
@Click(BUSINESSMAN_SILENT_COMPANION)
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_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_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_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]";
@ -253,8 +254,12 @@ public interface NewCalculationPage extends SmartAutoFlow<NewCalculationPage>, S
@TypeInto(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY, clear = true)
NewCalculationPage typeVehicleInsuranceCustomerNationality(String nationality);
@Wait(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_FIELD)
@Click(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_FIELD, jsClick = true)
@Wait(value = VEHICLE_CAR_INSURANCE_CUSTOMER_NATIONALITY_TEXTBOX)
@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();
@Wait(VEHICLE_CAR_INSURANCE_CUSTOMER_ADDRESS)
@ -271,19 +276,19 @@ public interface NewCalculationPage extends SmartAutoFlow<NewCalculationPage>, S
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_VOLUME_AGRO)
NewCalculationPage typeVehicleInsuranceVehicleVolume(String volume);
NewCalculationPage typeVehicleInsuranceVehicleVolume(int volume);
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_NUMBER_OF_SEATS)
NewCalculationPage typeVehicleInsuranceVehicleNumberOfSeats(String numberOfSeats);
NewCalculationPage typeVehicleInsuranceVehicleNumberOfSeats(int numberOfSeats);
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
@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)
@TypeInto(value = VEHICLE_CAR_INSURANCE_VEHICLE_WEIGHT_AGRO)
NewCalculationPage typeVehicleInsuranceVehicleWeight(String weight);
NewCalculationPage typeVehicleInsuranceVehicleWeight(int weight);
@Wait(VEHICLE_CAR_INSURANCE_VEHICLE_TAB)
@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.CommonElements;
import cz.moneta.test.harness.support.web.CheckElementPresent;
import cz.moneta.test.harness.support.web.Click;
import cz.moneta.test.harness.support.web.TypeInto;
import cz.moneta.test.harness.support.web.Wait;
import cz.moneta.test.harness.support.web.*;
public interface OthersPage extends SmartAutoFlow<OthersPage> {
@ -45,12 +42,14 @@ public interface OthersPage extends SmartAutoFlow<OthersPage> {
@TypeInto(APPROVAL_MESSAGE)
OthersPage typeApprovalMessage(String approvalMessage);
@Wait(value = VEHICLE_PAGE, until = Until.CLICKABLE)
@Click(value = VEHICLE_PAGE, jsClick = true)
VehiclePage clickVehiclePage();
@Click(value = CommonElements.SAVE_CALCULATION_BUTTON, andWait = @Wait(value = CommonElements.SUCCESSFUL_SAVED_CALCULATION_MESSAGE), jsClick = true)
OthersPage clickSaveCalculation();
@Wait(value = DUPLICATE_APPLICATION, until = Until.CLICKABLE)
@Click(value = DUPLICATE_APPLICATION, jsClick = true)
OthersPage clickDuplicateApplication();

View File

@ -7,10 +7,10 @@ import cz.moneta.test.harness.support.web.*;
public interface SavedCalculationsPage extends SmartAutoFlow<SavedCalculationsPage>, StoreAccessor, CalendarAccessor {
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 CALCULATION_NAME = FIRST_APPLICATION_DIV + "/div[2]/div[contains(text(), 'TestDuplikace')]";
String FIRST_APPLICATION_DIV = "//h2/span[contains(text(), 'Dnes')]/../../div[1]";
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_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_TO = "//label[contains(., 'Datum do')]/following-sibling::div/button";
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)
VehiclePage clickSearchWithVin();
@Wait(value = BUTTON_TO_QUEUE, until = Until.CLICKABLE)
@Click(value = BUTTON_TO_QUEUE, jsClick = true)
VehiclePage clickToQueue();

View File

@ -9,9 +9,9 @@ public class CalculationData {
private Brand brand;
private Model model;
private FilterFuel fuel;
private String volume;
private String power;
private String weight;
private int volume;
private int power;
private int weight;
private int price;
private String vin;
private Vat vat;
@ -25,7 +25,7 @@ public class CalculationData {
private Subsidy subsidy;
private ItemType itemType;
private int firstPayment;
private String numberOfSeats;
private int numberOfSeats;
public CalculationData setCustomer(Customer customer) {
this.customer = customer;
@ -117,22 +117,22 @@ public class CalculationData {
return this;
}
public CalculationData setVolume(String volume) {
public CalculationData setVolume(int volume) {
this.volume = volume;
return this;
}
public CalculationData setPower(String power) {
public CalculationData setPower(int power) {
this.power = power;
return this;
}
public CalculationData setWeight(String weight) {
public CalculationData setWeight(int weight) {
this.weight = weight;
return this;
}
public CalculationData setNumberOfSeats(String numberOfSeats) {
public CalculationData setNumberOfSeats(int numberOfSeats) {
this.numberOfSeats = numberOfSeats;
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.cagw.CaGwBuilder;
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.v4.V4Builder;
import cz.moneta.test.dsl.cagw.api.v1.V1Builder;
public class ApiBuilder extends CaGwBuilder {
@ -17,6 +17,10 @@ public class ApiBuilder extends CaGwBuilder {
return new CblBuilder(harness);
}
public V1Builder v1() {
return new V1Builder(harness);
}
public V2Builder v2() {
return new V2Builder(harness);
}
@ -25,8 +29,4 @@ public class ApiBuilder extends CaGwBuilder {
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> {
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 SUBCATEGORY_ALL_INCOMING_MESSAGES_A = "all_incoming_messages";
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 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))
IncomingMessagesPage clickIncomingMessages();

View File

@ -140,7 +140,7 @@ public interface DetailIncomingMessagePage extends ExevidoWebFlow<DetailIncoming
DetailIncomingMessagePage saveFolderIssueNumber();
@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);
@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
default DetailIncomingMessagePage clickIncomingMessageRow(int timeout) {
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
endpoint.sendKeysOneAtATime(Key.ENTER);
endpoint.waitForElementAndRefresh(INCOMING_MESSAGE_ROW, Lookup.ID, endpoint::refeshPage, timeout, 2);
endpoint.click(() -> INCOMING_MESSAGE_ROW, Lookup.ID);
return null;

View File

@ -12,8 +12,9 @@ import static cz.moneta.test.dsl.exevido.pages.NewIncomingMessagePage.PAGE_LABEL
@Wait(PAGE_LABEL_B)
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 ANSWER_BUTTON = "answer";
String SUBJECT_INPUT = "subject";
String SENDER_XPATH = "//iq-select2[@id='_selectId']//input";
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 SENDER_ITEM = "item_0";
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 SEND_TO_ANOTHER_DATA_BOX_BUTTON = "//app-actis-button//button[contains(., 'Do jiné datové schránky')]";
String UNIVERSAL_SINGLE_SELECT = "singleSelect";
@ -35,6 +38,13 @@ public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessag
String UNIVERSAL_SUBMIT_SINGLE_SELECT_BUTTON = "submitSingleSelect";
String CONFIRM_BUTTON = "//button[normalize-space()='Potvrdit']";
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)
NewIncomingMessagePage fillSubject(String subject);
@ -83,7 +93,7 @@ public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessag
default NewIncomingMessagePage storeMessageId() {
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
String messageId = endpoint.getText(MESSAGE_ID_SPAN).replaceAll("ID:(\\d+)", "$1");
store(MESSAGE_ID_KEY, messageId);
store(INCOMING_MESSAGE_ID_KEY, messageId);
return null;
}
@ -96,6 +106,12 @@ public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessag
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 = SEND_TO_ANOTHER_DATA_BOX_BUTTON, by = Lookup.XPATH)
NewIncomingMessagePage sendToAnotherDataBox();
@ -114,4 +130,18 @@ public interface NewIncomingMessagePage extends ExevidoWebFlow<NewIncomingMessag
@Click(CHANGE_MESSAGE_TYPE)
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)
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 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 RECIPIENT_XPATH = "//iq-select2[@id='recipient_id']//input";
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 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 APPLICATION_TEMPLATE = "//ul[@id='pdf_templates_secondLevel']//a[text()='Přihláška']";
String EDIT_TEMPLATE_BUTTON = "edit_attachment";
String SAVE_TEMPLATE_XPATH = "//tbody[@id='attachment_table_body']//i[@title='Uložit']/..";
String UNPACK_MESSAGE_INFORMATIONS = "unpack_message_informations";
@ -50,7 +55,20 @@ public interface NewOutgoingMessagePage extends ExevidoWebFlow<NewOutgoingMessag
String BACK_BUTTON = "back_button";
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))
@KeyPress(value = Key.ENTER)
NewOutgoingMessagePage fillRecipient(String recipient);
@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))
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))
NewOutgoingMessagePage clickEditTemplate();
@ -179,7 +201,7 @@ public interface NewOutgoingMessagePage extends ExevidoWebFlow<NewOutgoingMessag
ExevidoEndpoint endpoint = getEndpoint(ExevidoEndpoint.class);
String messageId = endpoint.getText(MESSAGE_ID_SPAN).replaceAll("ID:(\\d+)", "$1");
store(MESSAGE_ID_KEY, messageId);
store(OUTGOING_MESSAGE_ID_KEY, messageId);
return null;
}

View File

@ -1,19 +1,34 @@
package cz.moneta.test.dsl.exevido.pages;
import cz.moneta.test.dsl.exevido.ExevidoWebFlow;
import cz.moneta.test.harness.support.web.Click;
import cz.moneta.test.harness.support.web.Lookup;
import cz.moneta.test.harness.support.web.Wait;
import cz.moneta.test.dsl.exevido.components.ExevidoPanels;
import cz.moneta.test.harness.context.StoreAccessor;
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;
@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 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)
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() {
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.harness.endpoints.imq.ImqFirstVisionEndpoint;
import cz.moneta.test.harness.endpoints.imq.ImqFirstVisionQueue;
import cz.moneta.test.harness.messaging.ReceivedMessage;
import cz.moneta.test.harness.messaging.exception.MessagingTimeoutException;
import cz.moneta.test.harness.support.messaging.ReceivedMessage;
import cz.moneta.test.harness.support.messaging.exception.MessagingTimeoutException;
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.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;
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.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 CARDS_BTN_XPATH = "//li[@data-testid='cards-link']";
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_SAVED_TEXT_XPATH = "//div[contains(@class,'productCard__ballance__ledger')]//small[normalize-space(.)='Naspořeno']";
String PENSION_CARD_XPATH = "//small[contains(., 'Doplňkové penzijní spoření')]";
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 CHECK_BOX_MOBILE_KEY_XPATH = "//span[@class='f-checkbox__indicator']";
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)
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)
RtvServicingPage clickOnStornoButton();

View File

@ -144,6 +144,7 @@ public interface RtvServicingPage extends NewIbPageFlow<RtvServicingPage> {
@Click(RTV_SERVICING_CANCEL_CONTINUE_BUTTON_XPATH)
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)
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 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_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 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í']";
@ -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_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 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_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.')]";
@ -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_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 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)
CardsSettingsPage clickOnCreditCardsTab();
@ -83,14 +85,14 @@ public interface CardsSettingsPage extends NewIbPageFlow<CardsSettingsPage> {
@CheckElementPresent(NO_CREDIT_CARDS_XPATH)
CardsSettingsPage checkNoCreditCards();
@Click(DEBIT_CARDS_TAB_XPATH)
@Click(value = DEBIT_CARDS_TAB_XPATH, andWait = @Wait(explicitWaitSeconds = 1))
CardsSettingsPage clickOnDebitCardsTab();
@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();
@Wait(value = CARDS_TO_THE_ACCOUNT_XPATH, until = Until.CLICKABLE)
@Wait(value = CANCEL_ACCOUNT, until = Until.VISIBLE)
@Click(CARDS_TO_THE_ACCOUNT_XPATH)
CardsSettingsPage clickOnCardsToTheAccount();
@ -98,7 +100,7 @@ public interface CardsSettingsPage extends NewIbPageFlow<CardsSettingsPage> {
@Click(CARD_DETAIL_BUTTON_XPATH)
CardsSettingsPage clickOnCardDetail();
@Wait(value = CARD_DETAIL_TITLE_XPATH, until = Until.CLICKABLE)
@Wait(ACCOUNT_NUMBER)
@CheckElementPresent(CARD_DETAIL_TITLE_XPATH)
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.support.web.Builders;
@Deprecated() // Needs completely review - If you want to work with this, please contact Harness admin firstly.
public class Oauth2Web {
private final Harness harness;
@ -13,21 +12,18 @@ public class Oauth2Web {
this.harness = harness;
}
@Deprecated() // Will be reviewed in the API Lab team.
public Oauth2WebTransitions onOauth2WebTransitions() {
harness.getEndpoint(Oauth2WebEndpoint.class).openApplication();
return Builders.newWebFlowBuilder(Oauth2WebTransitions.class, harness.getEndpoint(Oauth2WebEndpoint.class), harness);
}
@Deprecated() // Will be reviewed in the API Lab team.
public Oauth2WebTransitionsKyc onOauth2WebTransitionsKyc() {
harness.getEndpoint(Oauth2WebEndpoint.class).openApplication();
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() {
harness.getEndpoint(Oauth2WebEndpoint.class).openApplication();
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;
import cz.moneta.test.dsl.oauth2.web.pages.FederatedLoginPage;
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 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
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.Wait;
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)
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 {
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
while (line != null) {
if (line.contains("#LASTFIELD#")) {
if (lastField != null) {
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"));
}
if (line.contains("#YYYYMMDD#")) {
line = line.replace("#YYYYMMDD#", DateUtils.getFormattedTodayDate("yyyyMMdd"));
}
if (line.contains("#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"));
}
if (line.contains("#REF#")) {
line = line.replace("#REF#", String.valueOf(data.getTrxReference()));
}
if (line.contains("#IBAN#")) {
line = line.replace("#IBAN#", String.valueOf(data.getIban()));
}
if (line.contains("#RANDOM#")) {
line = line.replace("#RANDOM#", String.valueOf(data.getRandom()));
}
if (line.contains("#AMOUNT#")) {
line = line.replace("#AMOUNT#", String.valueOf(data.getAmount()));
}
if (line.contains("#AMOUNT1#")) {
line = line.replace("#AMOUNT1#", String.valueOf(data.getAmount1()));
}
if (line.contains("#CREDITOR#")) {
line = line.replace("#CREDITOR#", String.valueOf(data.getCreditorAcc()));
}
if (line.contains("#DEBTOR#")) {
line = line.replace("#DEBTOR#", String.valueOf(data.getDebtorAcc()));
}
if (line.contains("#BANKCODE#")) {
line = line.replace("#BANKCODE#", String.valueOf(data.getBankCode()));
}
if (line.contains("#MESSAGEID#")) {
line = line.replace("#MESSAGEID#", String.valueOf(data.getMessageId()));
}
if (line.contains("#FEETYPE#")) {
line = line.replace("#FEETYPE#", String.valueOf(data.getFeeType()));
}
if (line.contains("#HDTYPE#")) {
line = line.replace("#HDTYPE#", String.valueOf(data.getHdType()));
}
line = line.replace("#DATETIME#", DateUtils.getFormattedTodayDateTime("yyyy-MM-dd'T'hh:mm:ss"));
line = line.replace("#YYYYMMDD#", DateUtils.getFormattedTodayDate("yyyyMMdd"));
line = line.replace("#YYMMDD#", DateUtils.getFormattedTodayDate("yyMMdd"));
line = line.replace("#YYYY-MM-DD#", DateUtils.getFormattedTodayDate("yyyy-MM-dd"));
line = line.replace("#REF#", String.valueOf(data.getTrxReference()));
line = line.replace("#IBAN#", String.valueOf(data.getIban()));
line = line.replace("#RANDOM#", String.valueOf(data.getRandom()));
line = line.replace("#AMOUNT#", String.valueOf(data.getAmount()));
line = line.replace("#AMOUNT1#", String.valueOf(data.getAmount1()));
line = line.replace("#CREDITOR#", String.valueOf(data.getCreditorAcc()));
line = line.replace("#DEBTOR#", String.valueOf(data.getDebtorAcc()));
line = line.replace("#BANKCODE#", String.valueOf(data.getBankCode()));
line = line.replace("#MESSAGEID#", String.valueOf(data.getMessageId()));
line = line.replace("#FEETYPE#", String.valueOf(data.getFeeType()));
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.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})
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 DEBTOR_ACC = "//div[@id='Vyhledávání']//input[@name='field1#orAccIdent']";
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_FILLED = "//input[@name='field1#queueReason' and not(@value='')]";
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_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')]";
@ -36,7 +39,7 @@ public interface PaymentEngineSearchPage extends WebFlow<PaymentEngineSearchPage
String TRANSACTION_FILES = "//a[text()='Soubory']";
String TRANSACTION_LIFE_CYCLE = "//a[text()='Životní cyklus']";
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 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";
@ -48,6 +51,9 @@ public interface PaymentEngineSearchPage extends WebFlow<PaymentEngineSearchPage
@TypeInto(value = ID, clear = true)
PaymentEngineSearchPage typeId(String id);
@Click(ADVANCED_FILTER)
PaymentEngineSearchPage clickAdvancedFilter();
@Wait(value = DEBTOR_ACC, until = Until.VISIBLE)
@TypeInto(DEBTOR_ACC)
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))
PaymentEngineSearchPage selectReason(String reason);
@TypeInto(UETR_INPUT)
PaymentEngineSearchPage fillUetr(String uetr);
@Wait(value = SEARCH_BUTTON, until = Until.VISIBLE)
@Click(value = SEARCH_BUTTON, andWait = @Wait(value = AJAX_LOADING, until = Until.GONE))
PaymentEngineSearchPage clickSearch();
@ -121,6 +130,6 @@ public interface PaymentEngineSearchPage extends WebFlow<PaymentEngineSearchPage
PaymentEngineSearchPageLifeCycle clickLifeCycle();
@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.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;
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 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.shared.SharedElements.LOAD_IMG_DIV_CLASS;
@Wait(value = ADC_PRODUCT)
@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 CANCEL_INTERNET_BANK_BUTTON = "STS701_S002_B048";
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_SMART_BANK_CHECKBOX = FIRST_CANCEL_SMART_BANK_XPATH + "/../../..//input";
String STATUS_MESSAGE_DIV = "XXX702_T001_L107";
@Click(CANCEL_INTERNET_BANK_BUTTON)
@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)
STS701_S002_AdcProductsPanel clickFirstSmartBank();
@CustomAction
default 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;
}
@CheckElementContent(STATUS_BAR)
STS701_S002_AdcProductsPanel checkStatusMessage(String expectedStatusMessage);
}

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.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.NewProductsUfoOps;
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 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.shared.SharedElements.LOAD_IMG_DIV_CLASS;
@Wait(LIST_OF_OFFERS)
@Wait(value = LIST_OF_PRODUCTS, by = Lookup.XPATH)
@Wait(value = {CIF_DIV, RC_DIV})
@Wait(value = APPLICATIONS_BUTTON, by = Lookup.XPATH)
@Wait(value = {CLIENT_CIF_LABEL, CLIENT_RC_LABEL})
@Wait(value = APPLICATIONS_PANEL_XPATH, by = Lookup.XPATH)
@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> {
String CURRENT_ACCOUNT_NUMBER_KEY = "CURRENT_ACCOUNT_NUMBER";
String CIF_STORE_KEY = "CIF";
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 APPLICATIONS_BUTTON = "//button[text()='Žádosti']";
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 LIST_OF_OFFERS = "STS701_S002_V002";
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 BACK_CHANGE_DISTRIBUTION_BUTTON = "EVY701_S001_B002";
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 CLIENT_DETAIL_XPATH = "//button[contains(@title, 'STS701_S002_I009')]";
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 OPPORTUNITY_TABLE = "STS701_S002_G011_clone";
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 FIRST_CURRENT_ACCOUNT_COMBOBOX = "STS701_S002_C004";
String CHECK_ACCOUNT_STATE = "STS701_S002_L174";
String REFRESH_REQUIREMENT_BUTTON = "XXX702_T001_B001";
String BANK_BACK_OFFICE_BUTTON = "STS701_S002_I017";
String TRANSFER_TO_530 = "STS701_S002_I106";
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 BANK_CLIENT_SPAN = "//span[contains(text(), 'BankKlient')]";
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 = "//*[@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 DETAIL_OF_ADC_PRODUCT = "STS701_S002_B007";
String PLACE_OF_BUSINESS = "STS701_S002_L093";
String BACK_BUTTON = "HPO703_S001_S014";
String LOANS_BUTTON_XPATH = "//button[contains(@title, '[STS701_S002_I064]')]";
String RC_OF_HOLDER_LABEL = "STS701_S002_L157";
String NUMBER_OF_LOANS_ACCOUNT = "STS701_S002_L269";
String REQUEST_LIST = "//button[contains(@title, '[XXX702_T001_I015]')]";
String FIRST_REQUEST_DONE_DIV = "XXX702_T001_L312-1";
String COMPLAINT_BUTTON = "STS701_S002_I158";
String COMPLAINT_BUTTON = "STS701_S002_I126";
String COMPLAINTS_AND_OTHER_CLAIMS_BUTTON = "STS701_S002_I139";
String PRINT_OF_LETTER = "STS701_S002_I049";
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 TRANSACTIONS_SETTINGS = "STS701_S002_I093";
String PAYMENTS_THROUGH_MOTO_INTERNET_DIV = "STS701_S002_L145";
String DEBIT_CARD_SENDING_ADDRESS_STREET_LABEL = "STS701_S002_L160";
@Click(SENDING_OFFERS_MANUALS)
ZAS701_S002_SendingOffersAndManualsPage clickSendingOffers();
@ -285,7 +248,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
@CustomAction
default STS701_S002_ClientDetailPage storeAccountNumber() {
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
String accountNumber = endpoint.getText(TREE_ACCOUNT_XPATH, Lookup.XPATH).replaceAll(".*\\((\\d+);.*", "$1");
this.store(CURRENT_ACCOUNT_NUMBER_KEY, accountNumber);
@ -322,30 +284,12 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
@CheckElementPresent(FRAUD_TABLE)
STS701_S002_ClientDetailPage assertFraudTable();
@CheckElementPresent(NOTIFICATION_LABEL)
STS701_S002_ClientDetailPage assertNotice();
@CheckElementPresent(CREDIT_CARD_CONTRACT_STATE_LABEL)
STS701_S002_ClientDetailPage assertCreditCardContractState();
@CheckElementPresent(RETENTION_TABLE)
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)
STS701_S002_ClientDetailPage assertOpportunityTable();
@ -369,13 +313,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
@CheckElementContent("STS701_S002_L833")
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
default STS701_S002_ClientDetailPage clickTreeCreditCard() {
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)
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))
STS701_S002_ClientDetailPage clickClientDetailList();
@ -452,18 +364,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
@Click(CREATE_NEW_BUTTON)
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)
@Click(CHANGE_DISTRIBUTION_BUTTON)
STS701_S002_ClientDetailPage clickDistribution();
@ -501,17 +401,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
@CheckElementContent(CHECK_ACCOUNT_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)
@Click(value = INTERNET_BANK_DISPO_XPATH, by = Lookup.XPATH)
STS701_S002_ClientDetailPage clickIB();
@ -545,15 +434,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
@Click(value = ACCOUNT_BENEFITS)
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")
STS701_S002_ClientDetailPage acceptAlert();
@ -564,6 +444,7 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
default UKO735_S001_ClaimsAndComplaints clickComplaint() {
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
endpoint.click(() -> COMPLAINT_BUTTON);
endpoint.click(() -> COMPLAINTS_AND_OTHER_CLAIMS_BUTTON);
endpoint.focusToNewPopup(10);
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)")
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
default STS701_S002_AdcProductsPanel clickSmartBank() {
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
@ -615,9 +492,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
return null;
}
@CheckElementContent(CANCEL_ADC_PRODUCT_DIV)
STS701_S002_ClientDetailPage checkCancelAdcProduct(String content);
@CheckElementContent(PLACE_OF_BUSINESS)
STS701_S002_ClientDetailPage checkPlaceOfBusiness(String place);
@ -642,50 +516,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
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
default STS701_S002_ClientDetailPage scrollToSendingOffersManuals() {
UfoEndpoint endpoint = this.getEndpoint(UfoEndpoint.class);
@ -693,13 +523,6 @@ public interface STS701_S002_ClientDetailPage extends StoreAccessor, WebFlow<STS
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
default STS701_S002_ClientDetailPage checkInfoServiceProductIsNotPresent() {
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);

View File

@ -1,5 +1,6 @@
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.endpoints.ufo.UfoEndpoint;
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 {
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_CARDS_BUTTON = "STS701_S002_P014-%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.waitForElementsToLoad(5, Lookup.CLASSNAME, Until.GONE, LOAD_IMG_DIV_CLASS);
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;
}

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_ClientDetailPage;
import cz.moneta.test.dsl.ufo.operations.shared.topmenu.XXX702_SharedTopMenu;
import cz.moneta.test.harness.context.StoreAccessor;
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
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;
@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 CLIENTS_NAME = "ADC739_S001_L004-1";
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 PHISING_SMS_BUTTON = "ADC739_S001_B008";
String BLOCATION_ALL_PROFILES_BUTTON = "ADC739_S001_B001";
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 STATE_OF_IB_CANAL = "ADC739_S001_L104";
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)
@CustomAction
default ADC739_S001_IBSBPage checkIfStatusBarIsOverwritten(String textInStatusBar) {
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
String fullText = endpoint.getText(STATUS_BAR);
String fullText = getStatusBarContent();
String textWithoutTime = fullText.replaceFirst("^\\d{2}:\\d{2}:\\d{2}", "");
Assert.assertTrue(textWithoutTime.contains(textInStatusBar));
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)
@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")
@ -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))
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)
@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?")

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;
import cz.moneta.test.dsl.ufo.operations.recorder.CRC710_S001_RecorderMainPage;
import cz.moneta.test.harness.context.StoreAccessor;
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
import cz.moneta.test.harness.support.web.*;
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 {
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";
@Wait(value = REQUIREMENT_DATE, until = Until.VISIBLE)
@GetElementContent(REQUIREMENT_DATE)
String getRequirementDate();
@CheckElementPresent(FIRST_REQUIREMENT_DESCRIPTION)
T checkFirstRequirementDescriptionPresence();
@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)
@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;
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.harness.support.web.*;
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";
@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))
XXX702_Requirements<T> menuClickRequirements();
@Wait(value = CLIENT_DETAIL_PANEL_XPATH, by = Lookup.XPATH, until = Until.CLICKABLE)
@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)
@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 {
String STATUS_BAR = "XXX702_T001_L107";
String LOGOUT_BUTTON = "XXX702_T001_B008";
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 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)
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() {
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
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);
String correspondenceDate = endpoint.getText(CORRESPONDENCE_DATE);
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;
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.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 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 UNBLOCK_DEBIT_CARD_BUTTON = "PLK703_S002_B004";
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 TELEPHONE_NUMBER_TEXTBOX = "PLK703_S002_E007";
@ -58,21 +55,6 @@ public interface PLK703_S002_DebitCardBlocationPage extends WebFlow<PLK703_S002_
@Click(value = CONFIRM_BLOCK_BUTTON)
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)
PLK703_S002_DebitCardBlocationPage clickConfirmAlertButton();

View File

@ -1,6 +1,7 @@
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.shared.topmenu.XXX702_SharedTopMenu;
import cz.moneta.test.harness.context.StoreAccessor;
import cz.moneta.test.harness.endpoints.ufo.UfoEndpoint;
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;
@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 ADDRESS_FOR_SENDING_SELECT = "PLK708_S001_C001";

View File

@ -1,7 +1,6 @@
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.harness.context.StoreAccessor;
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 DETAIL_OF_LIST_CHANGE = "STO704_S001_P002-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 GENERATE_PRINT = "STO704_S001_B008";
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 = "XXX702_T001_L172";
String POST_CONSENT = "STO704_S001_L077-4";
String IBSB_CONSENT = "STO704_S001_L077-6";
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)
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)
STO704_S001_ClientConsentsPage selectTypeOfPrint(int order);
@ -189,15 +171,6 @@ public interface STO704_S001_ClientConsentsPage extends WebFlow<STO704_S001_Clie
@CheckElementContent(EMAIL_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ů.")
STO704_S001_ClientConsentsPage acceptAlert();
@ -269,24 +242,13 @@ public interface STO704_S001_ClientConsentsPage extends WebFlow<STO704_S001_Clie
@CheckElementContent(OTHER_CHANNELS_MMB_CONSENTS)
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)
@CustomAction
default STO704_S001_ClientConsentsPage checkIfIsSelectedTodayDate() {
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
String todayDateInChanges = endpoint.getAttribute(TODAY_DATE_IN_CHANGES, "value");
String todayDate = endpoint.getText(TODAY_DATE);
Assertions.assertEquals(todayDateInChanges, todayDate, "Dates aren't same.");
String todayDate = getActualDate();
Assertions.assertEquals(todayDate, todayDateInChanges, "Dates aren't same.");
return null;
}
}

View File

@ -25,8 +25,6 @@ public interface TRA740_S001_CreateNewTransferPaymentOrderPage extends WebFlow<T
String AMOUNT_INPUT = "TRA740_S001_E005";
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 SPECIFICALLY_SYMBOL = "TRA740_S001_E009";
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))
TRA740_S001_CreateNewTransferPaymentOrderPage clickSend();
@CheckElementContent(TRANSACTION_SUCCESSFULLY_ESTABLISHED_DIV)
TRA740_S001_CreateNewTransferPaymentOrderPage checkTransactionSuccessfullyEstablished(String content);
@CustomAction
default TRA740_S001_CreateNewTransferPaymentOrderPage saveTaskIDPaymentOrder() {
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);
return null;
}

View File

@ -73,12 +73,8 @@ public interface XCM701_S001_MortgagesPanel extends XCM701_S001_ContactForwardin
return null;
}
@CustomAction
default XCM701_S001_MortgagesPanel checkPhone(String phone) {
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
Assertions.assertEquals(phone, endpoint.getAttribute(PHONE_INPUT, "value"));
return null;
}
@TypeInto(value = PHONE_INPUT, clear = true)
XCM701_S001_MortgagesPanel fillPhone(String phone);
@CustomAction
default XCM701_S001_MortgagesPanel checkEmail(String email) {

View File

@ -90,12 +90,8 @@ public interface XCM701_S001_OtherPanel extends XCM701_S001_ContactForwardingPag
return null;
}
@CustomAction
default XCM701_S001_OtherPanel checkMobile(String mobile) {
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
Assertions.assertEquals(mobile, endpoint.getAttribute(MOBILE_INPUT, "value"));
return null;
}
@TypeInto(value = MOBILE_INPUT, clear = true)
XCM701_S001_OtherPanel fillMobile(String mobile);
@CustomAction
default XCM701_S001_OtherPanel checkEmail(String email) {

View File

@ -77,12 +77,8 @@ public interface XCM701_S001_SMEPanel extends XCM701_S001_ContactForwardingPage
return null;
}
@CustomAction
default XCM701_S001_SMEPanel checkMobile(String mobile) {
UfoEndpoint endpoint = getEndpoint(UfoEndpoint.class);
Assertions.assertEquals(mobile, endpoint.getAttribute(MOBILE_INPUT, "value"));
return null;
}
@TypeInto(value = MOBILE_INPUT, clear = true)
XCM701_S001_SMEPanel fillMobile(String mobile);
@CustomAction
default XCM701_S001_SMEPanel checkEmail(String email) {
@ -101,7 +97,7 @@ public interface XCM701_S001_SMEPanel extends XCM701_S001_ContactForwardingPage
@CustomAction
default XCM701_S001_SMEPanel checkInactiveAvailabilityHours() {
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;
}
}

View File

@ -182,5 +182,10 @@ public class Keys {
*/
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
private String messageId;
@Setter
private String uetr;
@Setter
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.firstvision.FirstVisionTasks;
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.insurance.InsuranceTasks;
import cz.moneta.test.dsl.util.task.kasanova.KSNTasks;
@ -187,4 +188,8 @@ public class Tasks {
public ExevidoTasks exevidoTasks() {
return new ExevidoTasks(harness);
}
public PaeMqTasks paeMq() {
return new PaeMqTasks(harness);
}
}

View File

@ -143,7 +143,8 @@ public class CalculationTypeTasks {
.typeVehicleInsuranceCustomerSurname(customer.getSurname())
.typeVehicleInsuranceCustomerBirthdate(customerData.getBirthdate().getValue())
.typeVehicleInsuranceCustomerPIN(customerData.getPin().getValue())
.typeVehicleInsuranceCustomerNationality(customerData.getNationality().getValue())
.clickVehicleInsuranceCustomerNationalityTextbox()
.clickVehicleInsuranceCustomerNationalityTextbox()
.clickVehicleInsuranceCustomerNationality()
.typeVehicleInsuranceCustomerAddress(customer.getAddress())
.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;
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.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.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;
public class ClientDetailsTasks {
@ -32,4 +36,24 @@ public class ClientDetailsTasks {
return start -> start.then(harness.tasks().ufo().operations().searchClient().byRc(rcOfExistingClient))
.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()
.onTransactionsPage()
.clickBack()
.clickDemand()
.clickRefreshRequirementButton()
.checkDemandDescriptionFirstRow("UFO - Bězný účet - Výpisy - Zaslání přes KC")
.menuClickClientRequirements()
.clickRefreshRequirements()
.assertFirstRequirementDescription("UFO - Bězný účet - Výpisy - Zaslání přes KC")
.clickRefreshClientButton();
}
}

View File

@ -30,9 +30,7 @@ public class DebitCardChangesTasks {
.clickInternetTransactionsOn()
.clickSaveSettings()
.checkPaymentsThroughMotoInternet("Zapnuto - vše")
.clickDemand()
.clickRefreshRequirementButton()
.checkDateInRequirement();
.then(harness.tasks().ufo().operations().clientDetails().assertFirstRequirementSolveDate());
}
public Function<STS701_S002_ClientDetailPage, STS701_S002_ClientDetailPage> stepsToTurnOffInternetPayments() {
@ -41,9 +39,7 @@ public class DebitCardChangesTasks {
.clickInternetTransactionsOff()
.clickSaveSettings()
.checkPaymentsThroughMotoInternet("Vypnuto - vše")
.clickDemand()
.clickRefreshRequirementButton()
.checkDateInRequirement();
.then(harness.tasks().ufo().operations().clientDetails().assertFirstRequirementSolveDate());
}
public Function<PLK708_S001_DataChangesPage, STS701_S002_ClientDetailPage> setSendingAddressAndCheckChange(Address address, String postOffice, String requirementFirstRowText) {
@ -56,9 +52,7 @@ public class DebitCardChangesTasks {
.checkPostOfficeInput(postOffice)
.clickSaveButton()
.checkDebitCardSendingAddressStreetLabel(address.getStreet() + " " + address.getDescriptiveNumber())
.clickDemand()
.clickRefreshRequirementButton()
.checkDateInRequirement()
.checkDemandDescriptionFirstRow(requirementFirstRowText);
.then(harness.tasks().ufo().operations().clientDetails().assertFirstRequirementSolveDate())
.assertFirstRequirementDescription(requirementFirstRowText);
}
}

View File

@ -66,7 +66,7 @@ public class OperationsTasks {
return new SavingAccountTasks(harness);
}
public GdprTasks GdprTasks() {
public GdprTasks gdprTasks() {
return new GdprTasks(harness);
}

View File

@ -28,7 +28,7 @@ public class PaymentOrderTasks {
.fillRecipientAccountNumber(accountNumberRecipient)
.fillAmount(amount)
.clickSend()
.checkTransactionSuccessfullyEstablished("Transakce byla úspěšně založena pod ID:")
.assertStatusBarContent("Transakce byla úspěšně založena pod ID:")
.saveTaskIDPaymentOrder()
.clickHomePage();
}

View File

@ -1,16 +1,12 @@
package cz.moneta.test.dsl.util.task.ufo.operations;
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.SearchBy;
import cz.moneta.test.dsl.ufo.operations.ufoOperations.*;
import cz.moneta.test.dsl.util.DateUtils;
import java.util.function.Function;
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_TaskPage.ID_OBJECT_IN_TASK_KEY;
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) {
return start -> start
.clickClientDetailInfo()
.checkClientRc(rcOfExistingClient)
.assertClientRc(rcOfExistingClient)
.checkPageNotContainsMenuElements()
.closeSecondWindow();
}

Some files were not shown because too many files have changed in this diff Show More