Skip to content
This repository has been archived by the owner on Aug 4, 2018. It is now read-only.

Commit

Permalink
- Support for variables in scenarios (variable types: random/constant)
Browse files Browse the repository at this point in the history
- Better error logging and warnings
- Added wait_for_element and sleep functions
- Open url can accept an array now and it will pick one of the urls randomly
- Added screenshot option to have easier debuging
- Added support for comments in the scenario json (this requires the user to install commentjson (pip install commentjson)
- Various fixes to make sure that the scenario will run correctly without failing
  • Loading branch information
Hatem Mostafa committed Feb 29, 2016
1 parent e266b79 commit 030b834
Show file tree
Hide file tree
Showing 4 changed files with 607 additions and 104 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ optional arguments:

* [Samuel Vandamme](http://www.sava.be)
* Stijn Polfliet
* Hatem Mostafa
<img src="http://docs.coscale.com/gfx/logo.png" alt="CoScale logo" />
167 changes: 167 additions & 0 deletions examples/magento_checkout.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// This scenario is written for a magento application with sample data v1.9
// You can follow the steps in the documentation to install it and test this scenario
// http://devdocs.magento.com/guides/m1x/ce18-ee113/ht_magento-ce-sample.data.html
// You can change the baseUrl to the url of your magento installation.
{
"variables":[
{
"type": "randomString",
"length": 7,
"name": "emailPrefix"
},
{
"type": "constant",
"value": "http://magento001",
"name": "baseUrl"
},
{
"type": "constant",
"value": [
"$[baseUrl]/accessories/bags-luggage.html",
"$[baseUrl]/accessories/eyewear.html",
"$[baseUrl]/vip.html",
"$[baseUrl]/accessories/jewelry.html",
"$[baseUrl]/home-decor/bed-bath.html",
"$[baseUrl]/home-decor/electronics.html",
"$[baseUrl]/home-decor/decorative-accents.html",
"$[baseUrl]/sale/home-decor.html"
],
"name": "productPages"
}

],
"steps": [

// ----------------------------------------------------------------------
// Signing up the user.
// ----------------------------------------------------------------------
{
"action": "open_url",
"value": "$[baseUrl]/customer/account/create/"
},
{
"action": "set_value",
"selector": "input#firstname",
"value": "John"
},
{
"action": "set_value",
"selector": "input#lastname",
"value": "Doe"
},
{
"action": "set_value",
"selector": "input#email_address",
"value": "$[emailPrefix]@example.com"
},
{
"action": "set_value",
"selector": "input#password",
"value": "qwerty"
},
{
"action": "set_value",
"selector": "input#confirmation",
"value": "qwerty"
},
{
"action": "submit",
"selector": "#form-validate"
},

// ----------------------------------------------------------------------
// Adding products to the cart.
// ----------------------------------------------------------------------
{
"action": "open_url",
"value": "$[productPages]"
},
{
"action": "click_one",
"selector": "button.button.btn-cart[type=button]"
},
{
"action": "open_url",
"value": "$[productPages]"
},
{
"action": "click_one",
"selector": "button.button.btn-cart[type=button]"
},
{
"action": "open_url",
"value": "$[productPages]"
},
{
"action": "click_one",
"selector": "button.button.btn-cart[type=button]"
},

// ----------------------------------------------------------------------
// Checking out.
// ----------------------------------------------------------------------
{
"action": "open_url",
"value": "$[baseUrl]/checkout/onepage/"
},
{
"action": "set_value",
"selector": "input#billing\\:street1",
"value": "Nowhere 1"
},

{
"action": "set_value",
"selector": "input#billing\\:city",
"value": "Utopia"
},
{
"action": "set_value",
"selector": "select#billing\\:region_id",
"value": "1"
},
{
"action": "set_value",
"selector": "input#billing\\:postcode",
"value": "555AL"
},
{
"action": "set_value",
"selector": "input#billing\\:telephone",
"value": "0123456789"
},
{
"action": "click",
"selector": "#checkout-step-billing button.button[title=Continue]"
},
{
"action": "wait_for_element",
"selector": "input[type=radio][name=shipping_method]"
},
{
"action": "click_one",
"selector": "input[type=radio][name=shipping_method]"
},
{
"action": "click",
"selector": "#shipping-method-buttons-container button.button"
},
{
"action": "wait_for_element",
"selector": "#shipping-method-buttons-container button.button"
},
{
"action": "click",
"selector": "div#payment-buttons-container button"
},
{
"action": "wait_for_element",
"selector": "#checkout-review-submit button.button"
},
{
"action": "click",
"selector": "#checkout-review-submit button.button"
}
]

}
60 changes: 56 additions & 4 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@
import time
import json
import os.path
import string
import random
import commentjson
import copy
from Queue import Queue, Empty
from threading import Thread

__license__ = "MIT"
__maintainer__ = "Samuel Vandamme"
__email__ = "[email protected]"
__author__ = "Samuel Vandamme"
__credits__ = ["Stijn Polfliet", "Samuel Vandamme"]
__credits__ = ["Stijn Polfliet", "Samuel Vandamme", "Hatem Mostafa"]
__version__ = "alpha"

threadQueue = Queue()
Expand All @@ -34,7 +38,7 @@ def main(args):
# Load in scenario
with open(options['scenario'], 'r') as content_file:
content = content_file.read()
scenario = json.loads(content)
scenario = commentjson.loads(content)

# Test option
if options['test']:
Expand Down Expand Up @@ -72,6 +76,8 @@ def parse_arguments(args):
help="run a scenario only once")
parser.add_argument('--slimerjs', action='store_true',
help="use slimerjs instead of phantomjs")
parser.add_argument('--screenshot', action='store_true',
help="provide screenshots after each step")
parser.add_argument('scenario')
args = parser.parse_args()

Expand All @@ -92,7 +98,8 @@ def parse_arguments(args):
'threads': args.threads,
'verbose': args.verbose,
'debug': args.debug,
'test': args.test
'test': args.test,
'screenshot': args.screenshot
}

return options
Expand Down Expand Up @@ -182,7 +189,7 @@ def execute(threadId, scenario, options):
options['browser'],
'worker.js',
str(threadId),
json.dumps(scenario),
json.dumps(preprocessScenario(scenario)),
json.dumps(options)
]
process = subprocess.Popen(
Expand All @@ -204,5 +211,50 @@ def execute(threadId, scenario, options):

return None

# Preprocess the scenario json so that tha variables are filled in the steps.
def preprocessScenario(obj):
variables = copy.deepcopy(obj['variables'])
steps = copy.deepcopy(obj['steps']);
for idx in range(len(variables)):
variable = variables[idx]
varType = variable['type']
searchForExactMatch = False
if varType == 'randomString':
value = getRandomString(variable['length'])
elif varType == 'constant':
value = variable['value']
if isinstance(value, list):
# We will be searching for exact match in case of arrays because we will replace the whole variable.
searchForExactMatch = True
else:
value = None
print 'Unknown variable type `' + variable['type'] + '`'

if value != None:
# Replacing the variable name with its value in the following variables.
for idx2 in range(idx + 1, len(variables)):
variable2 = variables[idx2]
if 'value' in variable2:
if searchForExactMatch:
if variable2['value'] == '$[' + variable['name'] + ']':
variable2['value'] = value
else:
variable2['value'] = json.loads(json.dumps(variable2['value']).replace('$[' + variable['name'] + ']', value))

# Replacing the variable name with its value in the steps.
for step in steps:
if 'value' in step:
if searchForExactMatch:
if step['value'] == '$[' + variable['name'] + ']':
step['value'] = value
else:
step['value'] = json.loads(json.dumps(step['value']).replace('$[' + variable['name'] + ']', value))

return steps;

# Generate random string.
def getRandomString(size=6, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for x in range(size))

if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
Loading

0 comments on commit 030b834

Please sign in to comment.