Skip to main content

ZWL Language Introduction

ZWL is designed to be easy, light and little restrictive with a focus on writing end to end tests. In this document we'll give you a high level detail of the language in easy to understand terms. It is expected that you understand the basics of at least one programming language.

We highly recommend reading this whole document. It contains almost everything you must know about ZWL in order to begin writing end to end tests.

info

While learning ZWL language, you may often want to check the behavior of a code snippet. For example, you may want to check the output of an expression, calculation or a language feature. Dry Run feature of IDE allows you to run tests written in ZWL without running a browser (and a VM). It comes handy to verify that a code snippet behaves as expected.

Dynamically typed#

ZWL language is dynamically typed such as python or javascript. This means the type of a value is known only at run time. ZWL infers the actual type from a given value while evaluating a given expression. For example:

print('30' + 5) # prints 35print('abc' + 5) # prints abc5

In the first statement, + operator tells ZWL that an addition operation is intended. The operands are then tried for conversion into a Number. If conversion was successful, ZWL performs an arithmetic addition operation.

Similarly in second statement, one of the operand wasn't a Number. ZWL performs a string concatenation operation in this case after converting operands to String.

Other operations are handled in similar ways so that you don't have to worry about explicit type conversion. For instance, if you get a number from a web page in form of a text, and you try performing an arithmetic operation on it, ZWL automatically converts the text into Number and derives a result that you'd expect.

Identifiers#

Identifiers name entities such as variables and functions. ZWL identifiers are [a-zA-Z_][0-9a-zA-Z_]* which means the first character must be ASCII a-z or A-Z or _ and the rest of characters are any combination of ASCII a-z or A-Z or _ or 0-9. Only the first character is required.

Nothing, Void are restricted identifiers and can't be used.

Variables#

ZWL variables are valid ZWL identifiers (this means they must follow the same rules an identifier does). We prefer camel cased names such as fooBar but you can use any style you're comfortable with. There are a few important things to note about variables in ZWL:

  • There is no block level scope and all variables are scoped globally within the test they are defined in. Look at the following example:

    if true {  foo = 1}# check whether variable defined in above block existassertTrue(exists(foo))# Will pass because ZWL doesn't have any block level scope

    Although foo is defined in a block, it will still be accessible after block ends. This is because all variable are scoped globally.

    There is however an exception to this. Variables defined in for statements live only within it's block, therefore not scoped globally. Look at the following code:

    for i = 1 to 10 {  print(i)}print(i) # It's an error to access i here because it was local to the loop.
    # Can define another loop using i which will create a new variablefor i = 1 to 10 {  print(i)}

Strings#

ZWL supports all common string representations you'd expect. Following are all lexically (syntactically) valid representation to define a string in ZWL:

foo = 'ZWL is cool'bar = "ZWL is easy"baz = `ZWl make writingend to end tests fun.`

Escape characters (such as backslash) work only within double and single quote representation. Raw or multiline string representation (text enclosed in backtick) will not handle any character specially and everything within it is treated literally (as-it-is). There raw strings must only be used to keep a string that doesn't require any special handling.

String operators and operations#

# String concatenation operator can be used to concat 2 or more stringsfoo = 'ZWL' + ' is cool'print(foo) # prints ZWL is cool
# format function can be used to format stringfoo = format('%s is cool', 'ZWL')print(foo) # prints ZWL is cool
# Escape charactersfoo = '\'ZWL\' is cool'print(foo) # prints 'ZWL' is cool
note

String interpolation '${foo} xx' is currently not supported.

All string manipulation functions will be discussed in later chapters.

Booleans#

foo = truebar = falseassertFalse(foo && bar)

Boolean operators and operations#

# Following prints truthyfoo = trueif foo {  print('truthy')} else {  print('falsy')}
# Following prints falsyfoo = trueif !foo {  print('truthy')} else {  print('falsy')}
print(true && false) # prints false
print(false || true) # prints true
print(true == false) # prints false
print(!true == false) # prints true
print(!false != false) # prints true

Numbers#

Integers and floating point numbers are supported.

foo = 121bar = 1.12baz = .21
foo = -121bar = -1.12baz = -.21

Number operators and operations#

print(1 + 1) # prints 2
print(1 - 1) # prints 0
print(-1 + -90) # prints -91
print(2 * 2) # prints 4
print(2 / 2) # prints 1
print(10 % 2) # prints 0
foo = 1foo++print(foo) # prints 2
foo = 1foo--print(foo) # prints 0
print(2 < 1) # prints false
print(2 > 1) # prints true
print(2 >= 2) # prints true
print(2 <= 2) # prints true
print((2 * 3) / 4 * (7 + 8)) # prints 22.5
note

+=, -= operators are not supported.

Prefix increment and decrement operators ++foo, --foo are not supported.

Lists#

Lists are collection of values. ZWL lists can have values of any supported type and support all common list type operations.

# Create a list using list literal. List indexes starts from 0foo = [1, 2, 3]print(foo[0]) # prints 1
# List containing values of multiple typesfoo = ['bar', 1, true, [3, 4]]

List manipulation functions will be discussed in later chapters.

Maps#

Maps are collection of key: value pairs having unique keys. ZWL maps can have values of any supported type and support all common map type operations. Map keys can either be a valid identifier or non identifier.

ten = 10foo = {  name: 'John',  age: 15,  isMale: true,  hobbies: ['reading', 'exercising', 'writing'],  'employer 1': 'Walmart',  [ten]: 100 * 2}print(foo.name) # prints John
# Usage of bracket notation for non identifier or variable keysprint(foo['employer 1']) # prints Walmartprint(foo[ten]) # prints 200
print(foo.hobbies[1]) # prints exercising

Map manipulation functions will be discussed in later chapters.

Nulls#

Nulls are not allowed in ZWL. You can't assign a null to a variable or pass it as an argument. No function accepts a null in ZWL.

ZWL internally uses a special value called Nothing to specify a non-existing value. This is used in functions that either returns a value or nothing at all. To check on existing values, there is a utility function called exists that can be used for exact same purpose.

In rare circumstances, if you ever feel like requiring a null, please ask a question to community and we will be happy to discuss it.

Comments#

Both single and multi line comments are supported.

# This is a single line comment
/*This is amulti line comment*/

Statement termination#

There is no statement termination character in ZWL, such as ; in java or javascript. Every statement should be separated by a new line.

# Validfoo = 1bar = 1
# Invalidbar = 1;
# Discouragedfoo = 1 bar = 1

If statement#

If statements requires a boolean expression or an expression that evaluates to a boolean value.

# Following prints equals to 1foo = 1if foo < 1 {  print('less than 1')} else if foo > 1 {  print('greater than 1')} else {  print('equals to 1')}
note

if statements in ZWL don't have opening ( and closing ) parenthesis around the expression.

For statement#

Following variants of for statement are supported in ZWL:

  • For-To#

    for i = 1 to 10 {  print(i) # prints 1-10, 10 times}
    foo = [1, 2, 3]for i = 0 to length(foo) - 1 {  print(foo[i]) # prints 1, 2, 3}
  • For-In using List#

    Iterates through all the values in a list.

    foo = [1, 2, 3]for i in foo {  print(i) # prints 1, 2, 3}
  • For-In using Map#

    Iterates through all the key-value pairs in a map.

    productOrders = {  foo: 5,  bar: 1,  baz: 10}totalOrders = 0for key, value in productOrders {  totalOrders = totalOrders + value}print(totalOrders) # prints 16
note

for statements in ZWL don't have opening ( and closing ) parenthesis around the expression.

While statement#

foo = 10while foo > 0 {  foo--  print(foo) # prints 9 to 0}
note

while statements in ZWL don't have opening ( and closing ) parenthesis around the expression.

Functions#

ZWL has built-in functions for all possible use cases. There is (currently) no support for user defined functions. Following code snippet shows a function invocation:

maxNum = max(88, 43, 99)

The arguments to a function can be one of supported types or expression composed of supported types.

Notes#

info

Further in the documentation, whenever we say 'supported types' it means the data types supported in ZWL. As you already know, they are string, boolean, number, list and map.