Skip to content
QiTASC.com / SMS Steps and Compound Steps /
Logging Incoming Short Messages Steps
/ .. /
Logging Incoming Short Messages Steps





Logging Incoming Short Messages Steps

The SMS logging capability logs all incoming short messages within a scenario. This is used in test cases where unexpected short messages (such as "welcome" messages) arrive during the test run. It saves all incoming short messages received by a phone as a Context Variable, where they can be retrieved. The short message log list's data structure allows for filtering for messages that satisfy given conditions.

Logging Incoming Short Messages
Logging Incoming SMS Step
Available Filtering Methods
Text, Text Contains and Regex Text Matches
From, From Contains and Regex From Matches
After, After Seconds and After Milliseconds
Before, Before Seconds and Before Milliseconds
Available Methods for Filtered Short Messages
Size
Get
First and Last Element
Additional Get Methods
Await Conditions
Example Test Case

Logging Incoming SMS Step

Syntax

1
make short message log of <phone Identifier> available as <smsLogVariable String>

Parameters

  • phone - The name assigned to the phone receiving the short messages

  • smsLogVariable - The name assigned to the Context Variable where all incoming short messages are logged

Example

1
And make short message log of A available as MSG_A

When this step is present anywhere in a scenario, all arriving short messages in the scenario are logged. This list generally grows during the test run, so the Context Variable's content changes with time.

Available Filtering Methods

These methods are called on a short message log list (as with MSG_A in the previous example). The methods filter a given short message log list so that the filtered result only contains messages that satisfy one or more given conditions. These methods may be chained.

Additional methods can be performed on filter methods. These are described below in Available Methods for Filtered Short Messages.

Text, Text Contains and Regex Text Matches

These methods match short messages whose content equals defined criteria.

Syntax

1
2
3
4
5
6
// Matches short messages whose content is exactly the same as the specified text
<smsLogVariable Identifier>.text(<content String>)
// Matches short messages whose content contains the specified snippet/excerpt
<smsLogVariable Identifier>.textContains(<content String>)
// Matches short messages whose content matches the regular expressions
<smsLogVariable Identifier>.textMatches(<regex String>)

Parameters

  • smsLogVariable - The name assigned to the Context Variable where all incoming short messages are logged

  • content - The SMS' content to be fully or partially matched against the short messages

  • regex - The regular expression to match against the ticket

    • The regex must match the entire content to yield a positive result

Example

1
2
3
And verify MSG_A.text("Your invoice is available.")
And verify MSG_B.textContains("Hello").afterEpochSeconds(1000)
And await MSG_C.textMatches("\\d+").size()==2 or timeout after 60 seconds

From, From Contains and Regex From Matches

These methods match short messages whose originating phone numbers equals defined criteria.

Syntax

1
2
3
4
5
6
7
// Matches messages whose originating number is exactly the same as the
// specified string
<smsLogVariable Identifier>.from(<phoneNumber String>)
// Matches short messages whose originating number matches the specified snippet/excerpt
<smsLogVariable Identifier>.fromContains(<phoneNumber String>)
// Matches short messages whose originating number matches the regular expressions
<smsLogVariable Identifier>.fromMatches(<regex String>)

Parameters

  • smsLogVariable - The name assigned to the Context Variable where all incoming short messages are logged

  • phoneNumber - The originating phone number to be fully or partially matched

  • regex - The regex to match against the originating number

Example

1
2
3
And verify messages.from("orig1").size
And verify messages.fromContains("+4312345")
And verify messages.fromMatches("^..ig1$")

After, After Seconds and After Milliseconds

These methods match messages whose arrival timestamp is after a specified date.

Syntax

1
2
3
4
5
6
7
8
// Matches short messages whose timestamp (of arrival) is after the given date
<smsLogVariable Identifier>.after(<date ZonedDateTime>)
// Matches short messages whose arrival time stamp is after the instant given
// by the Unix epoch time in seconds
<smsLogVariable Identifier>.afterEpochSeconds(<seconds Number>)
// Matches short messages whose arrival time stamp is after the instant given
// by the Unix epoch time in milliseconds
<smsLogVariable Identifier>.afterEpochMillis(<milliseconds Number>)

Parameters

  • smsLogVariable - The name assigned to the Context Variable where all incoming short messages are logged

  • date - The date in ZoneDateTime

  • seconds - The number of seconds

  • milliseconds - The number of milliseconds

Example

1
2
3
And verify messages.after(now)
And verify messages.afterEpochSeconds(1000)
And verify messages.afterEpochMillis(100000)

Before, Before Seconds and Before Milliseconds

These methods match messages whose arrival timestamp is before a specified date.

Syntax

1
2
3
4
5
6
7
8
// Matches short messages whose timestamp (of arrival) is before the given date
<smsLogVariable Identifier>.before(<date ZonedDateTime>)
// Matches short messages whose arrival time stamp is before the instant given
// by the Unix epoch time in seconds
<smsLogVariable Identifier>.beforeEpochSeconds(<seconds Number>)
// Matches short messages whose arrival time stamp is before the instant given
// by the Unix epoch time in milliseconds
<smsLogVariable Identifier>.beforeEpochMillis(<milliseconds Number>)

Parameters

  • smsLogVariable - The name assigned to the Context Variable where all incoming short messages are logged

  • date - The date in ZoneDateTime

  • seconds - The number of seconds

  • milliseconds - The number of milliseconds

Example

1
2
3
And verify messages.before(now)
And verify messages.beforeEpochSeconds(1000)
And verify messages.beforeEpochMillis(100000)

Available Methods for Filtered Short Messages

The following methods can be chained to the list of filtered short messages. These can also be applied to the entire list of unfiltered messages. However, in most use cases, the method receiver will be a filtered list.

Size

This method returns the number of elements in the filtered short message log list.

Syntax

1
<filteredMessage Function>.size()

Parameter

  • filteredMessage - The function comprised of the message variable and any additional methods chained to the size() method

Example

1
MYMESSAGES.textMatches("\\d+").size()

The example above only looks for messages only consisting of numbers.

Get

Returns the element of the list at the specified position. The index starts at 0.

Parameters

  • filtered - The function comprised of the message variable and any additional methods chained to the get() method

  • getIndex - The index position from where the element should be returned

Example

1
MYMESSAGES.text("Hello").get(1)

In the example above, the expression returns the second element of the filtered list. For example, the second message whose content equals "Hello". If the get() method is ommitted, then all short messages whose content equals "Hello" will be returned.

First and Last Element

These methods return the first or last element of the list.

Syntax

1
2
3
4
// Returns the list's first element
<filteredMessage Function>.first()
// Returns the list's last element
<filteredMessage Function>.last()

Parameter

  • filteredMessage - The function comprised of the message variable and any additional methods chained to the first() or list() method

Example

1
2
And verify MSG_B.textContains("result:").first()
And verify messages.textContains("text").afterEpochMillis(101000).last()

Additional Get Methods

Any given single element of a short message log list is a ShortMessage data structure that can be accessed with the following methods.

Syntax

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Returns the SMS' text/content
<filteredMessage Function>.getText()
// Returns the destination device's phone number, for example, the phone that
// received the short message as a string
<filteredMessage Function>.getNumber()
// Returns the sending phone's number as a string.
<filteredMessage Function>.getOriginatingNumber()
// Returns the Unix Epoch Time in milliseconds as a long value
// (the number of milliseconds since `1.1.1970 00h00m00s`).
<filteredMessage Function>.getTimestamp()

Example

1
2
3
4
And verify MSG_A.textContains("result:").first().getText() == "result:579"
And verify MSG_B.text("Hello").getNumber()
And verify MYMESSAGES.textMatches("\\d+").getOriginatingNumber()
And verify MYMESSAGES.before(now).getTimestamp()

Await Conditions

This expression waits until a certain number of messages with given conditions have arrived. More information is available in the Await Condition Steps section.

Syntax

1
await <condition Expression> or timeout after <timeout Number> <units TimeUnit>

Parameters

  • condition - The expression representing the expected state

  • timeout - The maximum amount of time units to wait for the condition

  • units - May be one of milliseconds, second, seconds, minute, minutes, hour or hours

Example

1
await MYMESSAGES.textContains("bonjour").size()==2 or timeout after 60 seconds

The example above waits until two messages arrive whose text contains the word "bonjour". If this condition is not met after 60 seconds, the step fails.

Text Case Example

The example below contains a Feature File and a Stepdef. The Scenario uses two phones, A and B. B sends two short messages to A, each of which only contain integer numbers (123 and 456). A waits for these messages, extracts the numbers and adds the two numbers to yield a result. This result is sent back to B (with the text "result:579").

Feature File Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Feature: SMSLogger
  Scenario: B asks A to add two numbers using SMS
   # Allocate 2 phones, A and B
   Given an Android phone as A
   And an Android phone as B

   # save the incoming short messages to MSG_A and MSG_B
   And make short message log of A available as MSG_A
   And make short message log of B available as MSG_B

   And B sends a short message to A as FIRSTOP:
       * with text "123"

   And within 10 seconds, expect the short message FIRSTOP to be sent

   And B sends a short message to A as SECONDOP:
       * with text "456"

   # A waits for these messages ...
   And await MSG_A.textMatches("\\d+").size()==2 or timeout after 60 seconds
   And define OPERANDS as MSG_A.textMatches("\\d+")

   # ... extracts the numbers and performs the addition
   And compute result of OPERANDS as RESULT

   And A sends a short message to B as RES:
       * with text "result:" + RESULT

   # B waits for the result and checks it it is correct
   And await MSG_B.textContains("result:").size() == 1 or timeout after 60 seconds
   And verify MSG_B.textContains("result:").first().getText() == "result:579"

In the example above:

  • The steps And make short message log of A available as MSG_A/MSG_B make the incoming logged messages go to the short message log lists called MSG_A and MSG_B.

  • A waits for the messages comprised only of numbers by using the step And await MSG_A.textMatches("\\d+").size()==2 or timeout after 60 seconds.

  • As soon as the messages have arrived, the filtered list is copied to a Context Variable called OPERANDS by using And define OPERANDS as MSG_A.textMatches("\\d+").

Stepdef Example

A custom Steps Language Stepdef for the Feature File above performs the actual calculation.

1
2
3
4
5
6
7
stepdef "compute result of {} as {ident}" / operands, res /
    op1 := toNumber(operands.get(0).getText())
    op2 := toNumber(operands.get(1).getText())
    println("op1= " + op1 + "; op2= " + op2)
    setContextObject(res, toString(op1 + op2))
    println("RESULT is " + getContextObject(res))
end

In the example above, the operands are extracted and converted to numbers. The addition result is converted back to a string and stored in the Context Object under parameter res.