Giter Site home page Giter Site logo

behaving's Introduction

behaving

GitHub Workflow Status PyPI Docker Image Version (latest by date)

behaving is a web application testing framework for Behavior-Driven-Development, based on behave and splinter.

behave is written in Python and is similar to Cucumber. behaving adds the step-libraries for multi-user web/email/sms/gcm interactions, and provides the Python behaving namespace so that independent step-libraries can work together.

Please refer to behave's excellent documentation for a guide on how to use it, how to write your custom steps and make it possible to extend behaving.

Hello world

Starting to use behaving is pretty easy. Inside some python module, add your features consisting each of one or more scenarios. These features are Gherkin language files with an extension of .feature. In the same directory you should have a steps module which imports the behaving steps as well as your own custom steps (more on that later in the setup_ section) . Here's a basic example:

Feature: Text presence

    Background:
        Given a browser

    Scenario: Search for BDD
        When I visit "http://www.wikipedia.org/"
        And I fill in "search" with "BDD"
        And I press "go"
        Then I should see "Behavior-driven development" within 5 seconds

Email, SMS & GCM (Google Cloud Messaging)

While the web is the focus of behaving, it also includes simple mocks for a mail, SMS and a GCM server. These come with a small collection of steps allowing you to do things like:

Feature: Email & SMS

    Scenario: Click link in an email
        Given a browser
        When I send an email to "[email protected]" with subject "Hello" and body "Try out this website at http://google.com"
        And I click the link in the email I received at "[email protected]"
        Then the browser's URL should be "http://google.com/"

    Scenario: Receive SMS with body
        When I send an sms to "+4745690001" with body "Hello world"
        Then I should receive an sms at "+4745690001" containing "world"

    Scenario: Receive GCM Notification
        When I send a gcm message "{"to":"deviceID", "data": {"message": "Foo Bar", "badge": 6}}"
        Then I should receive a gcm notification at "deviceID" containing "{'data': {'message': 'Foo Bar'}}"

Typically, it will be your web application that sends email/sms/notifications and testing it comes down to configuring the application to send email/sms/notifications to the mock servers.

Personas & state

A lot of web apps today rely on multi-user interactions. To help you with those interactions, behaving uses the notion of personas. A persona within a test runs in its own instance of a browser and you can have more than one persona (and its browser instance) running concurrently. You switch among personas by calling

Given "PersonaName" as the persona

Personas are also typically implemented as simple dictionaries allowing them to carry state, save and reuse variables inside a scenario. When a persona is first invoked it is created as an empty dictionary. You can predefine personas though with set values.

Let's take the familiar LOTR characters as our test users. On setting up the test environment (details later in the setup_ section), we set up the characters basic variables we might be needing in the tests as such:

PERSONAS = {
    'Frodo': dict(
        fullname=u'Frodo Baggins',
        email=u'[email protected]',
        password=u'frodopass',
        mobile='+4745690001',
        address: {
            street: "The Shire",
            zip: "4321"
        }
    ),
    'Gandalf': dict(
        fullname=u'Gandalf the Grey',
        email=u'[email protected]',
        password=u'gandalfpass',
        mobile='+4745690004',
        address: {
            street: "Rivendell street 1",
            zip: "1234"
        }
  ),
  ...
}
def before_scenario(context, scenario):
    ...
    context.personas = PERSONAS

Within a test and given a persona, you can now use $var_name to access a variable of a persona. You can also set new variables on personas. So the following,

Given "Gandalf" as the persona
When I fill in "name" with "$fullname"
And I fill in "street" with "$address.street"
And I set "title" to the text of "document-title"
And I fill in "delete" with "$title"
And I set "address.country" to the text of "country"
And I set "postaddress" to:
"""
$fullname
$address.street, $address.zip, $address.country
"""

would fill in the field with id name with Gandalf the Grey, street with Rivendell street 1 set the variable title to the text of the element with id document-title and reuse the variable title to fill in the field with id delete. It would also store the value of the field with id "country" in address[country]. The $var_name pattern is also usable in the text received by steps that expect a body of text, which means that the postaddress persona variable will contain Gandalf's complete snail-mail postage address nicely formatted on multiple lines.

Hello Persona example

Let us assume the following (coming from a real example) scenario. Crypho, is an online messaging/sharing site that provides users with end-to-end encrypted real-time communications. behaving was written to help test Crypho.

In Crypho, teams collaborate in spaces. To invite somebody in a space the invitee has to share a token with an invitor, so both can verify each other's identity.

Feature: Frodo invites Gandalf to The Shire space

    Given state "the-shire"

    Scenario: Frodo invites Gandalf to The Shire

        Given "Gandalf" as the persona
        When I log in

Before the scenarios start, the custom step Given state "the-shire" executes. This preloads the db with data, sets up the server etc. Then the scenario executes:

First Gandalf logs in. The step Given "Gandalf" as the persona, fires up a browser that belongs to the persona Gandalf. The following step, When I log in is a custom step defined as follows:

@when('I log in')
def log_in(context):

    assert context.persona
    context.execute_steps(u"""
        When I go to Home
            Then I should see an element with id "email" within 2 seconds
        When I fill in "email" with "$email"
        And I press "send-sms"
            Then I should see "We have sent you an SMS with a security code" within 2 seconds
            And I should receive an sms at "$mobile"
            And "token" should be enabled
        When I parse the sms I received at "$mobile" and set "Your Crypho code is {token}"
        And I fill in "token" with "$token"
        And I fill in "password" with "$password"
        And I press "login"
            Then I should see "Crypho" within 5 seconds
    """)

Observe above how the current persona (Gandalf) parses the sms it receives and saves it as "token". Later Gandalf reuses it to fill in the two-factor authentication field.

Now that Gandalf is logged in, the test proceeds with Frodo. Frodo will log in, and invite Gandalf to a private space.

Given "Frodo" as the persona
When I log in
And I click the link with text that contains "My spaces"
And I click the link with text that contains "The Shire"
And I press "invite-members"
    Then I should see "Invite members" within 1 seconds
When I fill in "invitees" with "[email protected]"
And I fill in "invitation-message" with "Come and join us!"
And I press "send-invitations"
    Then I should see "Your invitations have been sent" within 2 seconds

Once the invitations are sent we switch back to Gandalf's browser, who should have received a notification in his browser, as well as an email. He then proceeds to send an sms to Frodo with the token who completes the invitation.

Given "Gandalf" as the persona
Then I should see "Your invitations have been updated" within 2 seconds
And I should receive an email at "[email protected]" containing "Frodo Baggins has invited you to join a private workspace in Crypho"
When I click the link with text that contains "Invitations"
And I click the link with text that contains "Pending invitations"
    Then I should see "Come and join us!"
When I set "token" to the text of "invitation-token"
And I send an sms to "45699900" with body "$token"

Given "Frodo" as the persona
    Then I should receive an sms at "45699900"
When I set "FrodoToken" to the body of the sms I received at "45699900"
And I click the link with text that contains "Invitations"
And I click the link with text that contains "Enter authorization token"
And I fill in "auth-token" with "$FrodoToken"
And I press "Submit"
    Then I should see "The invitation has been accepted." within 5 seconds
    And I should see "Gandalf the Grey has joined the space, invited by Frodo Baggins" within 10 seconds

You can see the test in action on video here.

Setting up a test environment

Start by installing behaving by using either pip or easy_install. This will also install dependencies and create the behave script with which you invoke your tests. If you prefer using buildout, clone the package itself from its repository, it contains already a buildout configuration.

Typically you will be having a folder containing all your features and steps. For example a directory structure like the following:

features/
features/mytest.feature
features/myothertest.feature
features/environment.py
features/steps/
features/steps/steps.py

In the steps directory you will need to import the behaving steps you need. You can also define your own steps. So steps.py might look like:

from behave import when
from behaving.web.steps import *
from behaving.sms.steps import *
from behaving.mail.steps import *
from behaving.notifications.gcm.steps import *
from behaving.personas.steps import *

@when('I go to home')
def go_to_home(context):
    context.browser.visit('https://web/')

In environment.py you specify settings as well the things that need to happen at various stages of testing, i.e. before and after everything, a feature run, or a scenario run. For convenience you can import and reuse behaving.environment which will perform default actions like closing all browsers after a scenario, clean the email folder etc.

It is also possible to use behaving.web.environment, behaving.mail.environment, behaving.sms.environment and behaving.personas.environment on their own, if you don't have need for SMS for example.

An example of an environment that does simply set some variables and then rely on default actions for the various stages, might look like the following:

import os
from behaving import environment as benv

PERSONAS = {}

def before_all(context):
    import mypackage
    context.attachment_dir = os.path.join(os.path.dirname(mypackage.__file__), 'tests/data')
    context.sms_path = os.path.join(os.path.dirname(mypackage.__file__), '../../var/sms/')
    context.gcm_path = os.path.join(os.path.dirname(mypackage.__file__), '../../var/gcm/')
    context.mail_path = os.path.join(os.path.dirname(mypackage.__file__), '../../var/mail/')
    benv.before_all(context)


def after_all(context):
    benv.after_all(context)


def before_feature(context, feature):
    benv.before_feature(context, feature)


def after_feature(context, feature):
    benv.after_feature(context, feature)


def before_scenario(context, scenario):
    benv.before_scenario(context, scenario)
    context.personas = PERSONAS

def after_scenario(context, scenario):
    benv.after_scenario(context, scenario)

The following variables are supported and can be set to override defaults:

  • screenshots_dir (the path where screenshots will be saved. If it is set, any failure in a scenario will result in a screenshot of the browser at the time when the failure happened.)
  • attachment_dir (the path where file attachments can be found)
  • sms_path (the path to be used by smsmock to save sms. Defaults to current_dir/sms )
  • gcm_path (the path to be used by gcmmock to save gcm notifications. Defaults to current_dir/gcm )
  • mail_path (the path to be used by mailmock to save mail. Defaults to current_dir/mail )
  • default_browser
  • default_browser_size (tuple (width, height), applied to each browser as it's created)
  • max_browser_attempts (how many times to retry creating the browser if it fails)
  • remote_webdriver_url (points to your selenium hub url or remote webdriver. Defaults to None)
  • browser_args (a dict of additional keyword arguments used when creating a browser)
  • base_url (the base url for a browser, allows you to use relative paths)
  • accept_ssl_certs (setting to True will accept self-signed/invalid certificates. Defaults to None)

You can run the tests simply by issuing

./bin/behave ./features

For chrome and docker issues, the code below is useful

from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--no-sandbox')
context.browser_args = {
    'options': chrome_options
}

Mail, GCM and SMS mock servers

When behaving is installed, it creates three scripts to help you test mail, gcm and sms, mailmock, gcmmock and smsmock respectively. You can directly invoke them before running your tests, they all take a port as well as the directory to output data as parameters. For example,

./bin/smsmock -p 8081 -o ./var/sms
./bin/gcmmock -p 8082 -o ./var/notifications/gcm
./bin/mailmock -p 8083 -o ./var/mail [--no-stdout]

behaving.web Supported matchers/steps

  • Browsers

    • Given a browser [opens the default browser, i.e. Firefox]
    • Given brand as the default browser [sets the default browser to be brand, this is the browser name when using the remote webdriver or Firefox, Chrome, Safari]
    • Given the electron app "app_path" [for use with electron-based desktop apps]
    • Given browser "name" [opens the browser named name]
    • When I reload
    • When I go back
    • When I go forward
    • When I resize the browser to widthxheight
    • When I resize the viewport to widthxheight
    • When I take a screenshot [will save a screenshot of the browser if screenshots_dir is set on the environment. Also, if screenshots_dir is set, all failing tests will result in a screenshot.]
    • When I execute the script "script"
    • When I set the cookie "key" to "value"
    • When I delete the cookie "key"
    • When I delete all cookies
    • When I close the browser "name"
  • Frames

    • When I switch to frame with css "css"
    • When I switch back to the main page
  • Windows

    • When I open a new window named "name" at "url"
    • When I name the current window "name"
    • When I switch to the window named "name"
  • URLs

    • Given the base url "url" [sets the base url to url, alternatively set context.base_url directly in environment.py]
    • When I visit "url"
    • When I go to "url"
    • When I parse the url path and set "{expression}"
    • Then the browser's URL should be "url"
    • Then the browser's URL should contain "text"
    • Then the browser's URL should not contain "text"
  • Links

    • When I click the link to "url"
    • When I click the link to a url that contains "url"
    • When I click the link with text "text"
    • When I click the link with text that contains "text"
  • Text, element & class presence

    • When I wait for timeout seconds

    • When I show the element with id "id"

    • When I hide the element with id "id"

    • Text

      • Then I should see "text"
      • Then I should not see "text"
      • Then I should see "text" within timeout seconds
      • Then I should not see "text" within timeout seconds
    • ID

      • Then I should see an element with id "id"
      • Then I should not see an element with id "id"
      • Then I should see an element with id "id" within timeout seconds
      • Then I should not see an element with id "id" within timeout seconds
  • CSS

    • Existence
      • Then I should see an element with the css selector "selector"
      • Then I should not see an element with the css selector "selector"
      • Then I should see an element with the css selector "selector" within timeout seconds
      • Then I should not see an element with the css selector "selector" within timeout seconds
      • Then I should see n elements with the css selector "css"
      • Then I should see at least n elements with the css selector "css" within timeout seconds
    • Visibility
      • Then the element with the css selector "css" should be visible
      • Then the element with the css selector "css" should be visible within timeout seconds
      • Then the element with the css selector "css" should not be visible
      • Then the element with the css selector "css" should be visible within timeout seconds
      • Then {n:d} elements with the css selector "css" should be visible
      • Then {n:d} elements with the css selector "css" should be visible within timeout seconds
      • Then at least {n:d} elements with the css selector "css" should be visible
      • Then at least {n:d} elements with the css selector "css" should be visible within timeout seconds
    • Existence of a class on an element
      • Then the element with xpath "xpath" should have the class "cls"
      • Then the element with xpath "xpath" should not have the class "cls"
      • Then the element with xpath "xpath" should have the class "cls" within timeout seconds
      • Then the element with xpath "xpath" should not have the class "cls" within timeout seconds
      • Then "name" should have the class "cls"
      • Then "name" should not have the class "cls"
      • Then "name" should have the class "cls" within timeout seconds
      • Then "name" should not have the class "cls" within timeout:d seconds
    • XPath
      • Then I should see an element with xpath "xpath"
      • Then I should not see an element with xpath "xpath"
      • Then I should see an element with xpath "xpath" within timeout seconds
      • Then I should not see an element with xpath "xpath" within timeout seconds
  • Forms

    • When I fill in "name|id" with "value"
    • When I clear field "name|id"
    • When I type "value" to "name|id" [same as fill, but happens slowly triggering keyboard events]
    • When I choose "value" from "name"
    • When I check "name|id"
    • When I uncheck "name|id"
    • When I toggle "name|id"
    • When I select "value" from "name""
    • When I select by text "text" from "name""
    • When I press "name|id|text|innerText"
    • When I press the element with xpath "xpath"
    • When I attach the file "path" to "name"
    • When I set the innner HTML of the element with id "id" to "contents" [Sets html on a contenteditable element with id id to contents]
    • When I set the innner HTML of the element with class "class" to "contents"
    • When I set the innner HTML of the element with class "class" to "contents"
    • When I send "KEY" to "name"
    • When I focus on "name"
    • Then field "name" should have the value "value"
    • Then field "name" should have the value "value" within timeout seconds
    • Then the selection "name" should have the options "valueA, valueB" selected
    • Then "name" should be enabled
    • Then "name" should be disabled
    • Then "name" should not be enabled
    • Then "name" should be valid
    • Then "name" should be invalid
    • Then "name" should not be valid
    • Then "name" should be required
    • Then "name" should not be required
  • HTML tables

    • Then the table with id "id" should be
      | header1 | header2 | ... | header(m) |
      | cell00 | cell01 | ... | cell0m |
      | cell10 | cell11 | ... | cell1m |
      ...
      | celln0 | celln1 | ... | cellnm |

    • Then the table with xpath "xpath" should be
      | header1 | header2 | ... | header(m) |
      | cell00 | cell01 | ... | cell0m |
      | cell10 | cell11 | ... | cell1m |
      ...
      | celln0 | celln1 | ... | cellnm |

    • Then the table with id "id" should contain the rows
      | cell00 | cell01 | ... | cell0m |
      | cell10 | cell11 | ... | cell1m |

    • Then the table with xpath "xpath" should contain the rows
      | cell00 | cell01 | ... | cell0m |
      | cell10 | cell11 | ... | cell1m |

    • Then the table with id "id" should not contain the rows
      | cell00 | cell01 | ... | cell0m |
      | cell10 | cell11 | ... | cell1m |

    • Then the table with xpath "xpath" should not contain the rows
      | cell00 | cell01 | ... | cell0m |
      | cell10 | cell11 | ... | cell1m |

    • Then row row_no in the table with id "id" should be
      | cell00 | cell01 | ... | cell0m |

    • Then row row_no in the table with xpath "xpath" should be
      | cell00 | cell01 | ... | cell0m |

    • Then the value of the cell in row row_no, column col_no in the table with id "id" should be "value"

    • Then the value of the cell in row row_no, column col_no in the table with xpath "xpath" should be "value"

    • Then the value of the cell in row row_no, column "col_header" in the table with id "id" should be "value"

    • Then the value of the cell in row row_no, column "col_header" in the table with xpath "xpath" should be "value"

  • Alerts & prompts

    • When I enter "text" to the alert - When I accept the alert - When I dismiss the alert - Then I should see an alert - Then I should see an alert within timeout seconds - Then I should see an alert containing "text" - Then I should see an alert containing "text" within timeout seconds
  • Mouse

    • When I mouse over the element with xpath "xpath"
    • When I mouse out of the element with xpath "xpath"
  • Downloads

    • Then the file "filename" with contents "text" should have been downloaded within timeout seconds
    • Then the file "filename" should have been downloaded within timeout seconds
  • Persona interaction & variables

    • When I set "key" to the text of "id|name"
    • When I set "key" to the attribute "attr" of the element with xpath "xpath"
    • When I evaluate the script "script" and assign the result to "key"

behaving.mail Supported matchers/steps

  • When I click the link in the email I received at "address"
  • When I parse the email I received at "address" and set "expression"
  • When I clear the email messages
  • Then I should receive an email at "address"
  • Then I should receive an email at "address" with subject "subject"
  • Then I should receive an email at "address" containing "text"
  • Then I should receive an email at "address" with attachment "filename"
  • Then I should not have received any emails at "address"

behaving.sms Supported matchers/steps

  • When I set "key" to the body of the sms I received at "number"
  • When I parse the sms I received at "number" and set "expression"
  • Then I should receive an sms at "number"
  • Then I should receive an sms at "number" containing "text"

behaving.notifications.gcm Supported matchers/steps

  • When I send a gcm message "{"to":"deviceID", "data": {"message":"Foo Bar", "badge": 6}}"
  • Then I should receive a gcm notification at "deviceID" containing "{'data': {'message': 'Foo Bar'}}"
  • Then I should have received any gcm notifications at "deviceID"

behaving.personas Supported matchers/steps

  • Given "name" as the persona
  • When I set "key" to "value"
  • When I set "key" to:
    """ some longer body of text
    usually multiline
    """
  • When I clone persona "source" to "target"
  • Then "key" is set to "value"

Debugging

  • When I pause the tests

Docker integration

A Dockerfile as well as a complete setup using docker-compose are provided to help you create selenium grid configurations that run your tests. In addition dev container configuration is included if VSCode is your thing.

In addition we provide pre-build images on docker hub for the linux/amd64 and linux/arm64 platforms. Use

docker pull behaving/behaving:latest

to pull the image.

Running behaving tests

You can run all behaving tests as follows:

Start docker compose:

docker-compose up

Open a shell in the behaving container:

docker-compose exec behaving bash

Run behaving tests:

behave tests/features

behaving's People

Contributors

andheiberg avatar anti1869 avatar antych avatar baekholt avatar ciprian-balauroiu avatar day-me-an avatar demetris-manikas avatar dependabot[bot] avatar erlendfh avatar fgimian avatar ggozad avatar guoqiao avatar harry-nguyen22 avatar julianpistorius avatar kageurufu avatar lampmantech avatar lrowe avatar mceike avatar metajiji avatar oyvinev avatar rosselliott avatar tsnowlan avatar wichert avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

behaving's Issues

Screenshot filename format should start with the datetime

Hello!

I was wondering if you think it'd be better if the format of the screenshot's filename start with the datetime. This might be a nitpick, but in my opinion, failing tests' screenshots would be easier to find if the files are sorted by name on explorer/finder. I'll be happy to make a PR if you think this is a good idea.

Thoughts? 😄

context.personas emptied before scenario

I was following the docs, and added context.personas = PERSONAS to before_all(). This doesn't work for me, because in before_scenario() context.personas = {} empties the dict and there are no personas available for the Given step.

Either I'm doing something wrong, or the personas dict shouldn't be emptied, or context.personas = PERSONAS should be assigned to context in before_scenario() instead - this works.

Some improvements

We are starting to use behaving a lot and have a few changes to the built in steps that would be worthwhile making.

  1. Add @persona_vars to as many steps as possible, for example 'I should see ...' would work far better if you could pass in a persona key such as 'I should see "$j-random-name"'
  2. Change 'Given "persona" as the persona' to only create a new browser connection if one doesn't exist already. This causes problems when using saucelabs for instance as when we switch personas in a scenario a new connection will open and then we lose track of the results.
  3. Where there are steps that use xpath create duplicates that use css selectors, it seems that this is where some people want to go (I actually prefer xpath)

We have had to implement our own steps to do the above but it would be nice to use the standard steps instead.

Can't find a Behaving version that works on Python 3.9

We're trying to run file upload tests on Python 3.9, which means we need to use Selenium 4 in order to fix SeleniumHQ/selenium#8762, but there doesn't seem to be any Behaving version that we can use.

  • Behaving 2.0.0 is incompatible with Selenium 4; attempting to click on an element with steps like 'I click the link with text that contains "{text}"' results in an AttributeError: 'dict' object has no attribute 'click'
  • Behaving 3.0.0 to 3.0.4 requires Splinter 0.16.0, which is incompatible with Selenium 4 (won't install).
  • Behaving 3.0.5+ requires Python 3.10.

Provide a mechanism to override predefined steps

I am using steps from a 3rd party library (behave_http)

Now I need to modify the behaviour of these steps specifically for my project

So in my steps I need a way to override the steps defined in the library.

Currently it errors out with an exception about duplicate step definition

Packages using the behaving Python namespace

This is realy a Request for Discussion, but I thought I'd post it here rather than sending you email,
so that the discussion can be followed by others.

Firstly, thank-you very much for writing behaving - it's saved me huge amounts of my time.

Secondly, I appreciate the way that you used Python namespace packages for your components,
and I would like to propose that as the way forward for the behave community to package up step libraries in a way for making them work together. And I like the idea of the behaving namespace being completely independent from the behave base.

I've done a proof of concept package that plugs into the behaving.cmd namespace, which
will be a step library for the standard file manipulation commands. But I just cut and pasted your layout and namespace packaging so that it should "just work" alongside behaving. See the
README at https://github.com/lampmantech/behaving.cmd

Could I ask you to take a look at the package and layout and double check that I didn't
make any mistakes in my cut and paste. I didn't bother with buildout, but perhaps travis should be put back in...

If you like the proof-of-concept, then we can suggest the layout and packaging to be the way forward for packaging step libraries. Then the behave community can work together without fragmentation and the havoc wrecked by entropy, and behaving.cmd can replace the dormant https://github.com/behave/behave4cmd , ideally under the behave project.

Scenario Outline and Example Tables

How do I use 'behaving' with behave's scenario outline and example tables? Right now any Given, When, Then statements with '<>' are skipped and not processed by 'behaving'. I get an error steps are not implemented.

Given I should see <heading_on_page>
When I search for <query_in_search_field>
And I should see <text_in_search_result> within 15 seconds
And I click the link with text that contains <title>
Then I should see <text_in_document> within 10 seconds

If I copy the relevant steps from behaving into my own step file and remove the double quotes around the variable in the decoration, my outline passes.

@given(u'I should see {text}')
# @step(u'I should see "{text}"')
# @persona_vars
def should_see(context, text):
    assert context.browser.is_text_present(text), u'Text not found'

Can not clear text in input box

I am using behaving for auto-testing. I need to clear the text in a input box so I can check the error message. I did this:

When I fill in "field-name" with ""

However I got this error:

You can implement step definitions for undefined steps with these snippets:

@when(u'I fill in "field-name" with ""')
def impl(context):
assert False

Set input box to empty is useful, hope this can be allowed.

deployment of behaving 1.5.0 on PyPi is not installable

https://pypi.python.org/pypi/behaving/ lists behaving 1.5.0 as deployed and available, however a

$ pip install behaving==1.5.0

fails with a 404 not found, with the logs saying it looked for the download in https://pypi.python.org/simple/behaving/ which only lists downloads up to behaving 1.4.1

Additionally, https://pypi.python.org/pypi/behaving/1.4.1 has a green download button, whereas https://pypi.python.org/pypi/behaving/1.5.0 is missing the button.

Decoding mail payload

Hi, I was using click_link_in_email step and seems like you are not encoding the payload there as in should_receive_email_containing_text for example. Is it a bug, or I'm using it wrong?

Project `Behave` badge?

Tools such as Black and Pre-commit have repository badges. I haven't been able to find one for Behave, does one exist?

Passing configuration information to backends

This is a Request for Enhancement, but also the identification of a broader issue across behaving namespace packages.

With behaving.web I can select the browser that will be used from a feature/step.
But in some cases, I need to configure the browser that will be called by splinter.
I may need to set firefox up with a profile, or instruct PhotomJS about the cache.

Unforunately the call that splinter makes takes very different call signatures for each brower so there is no way to do this in a generalized way. E.g. for firefox:

def __init__(self, profile=None, extensions=None, user_agent=None, profile_preferences=None, fullscreen=False, wait_time=2):

For PhantomJS

def __init__(self, user_agent=None, load_images=True, desired_capabilities=None, wait_time=2, custom_headers={}, **kwargs)

You could do this by individualized steps to parameterize each browser, but even then it would get messy, as some of these parameters are not just strings, but dictionaries.

This is a generic problem of how to configure the backend, and I think needs a generic solution. A generic solution would be then adopted by all of the packages in the
behaving namespace so that we all stay on the same page.

If you look at the approach we have taken in:
https://github.com/lampmantech/behaving.trytond

you'll see an environment.cfg file in the src/behaving/tests/features directory alongside the environment.py to parameterize the steps. This can be used
to parameterize the steps, and the reason we used configobj rather than
configparser is that it gracefully handles dictionaries or JSON. I think that something like this will be needed by behaving to parameterize the arguments to the browser instances that are created by splinter, or any other back end, like a server.

If our approach works for you, all we need to do is sync some naming conventions.
For example the section names should be the behaving namespace names,
so that we all could use the same environment.cfg file, and any client-end use
of the environment.cfg file would know that it could use any mix of all of
the possible behaving namespace packages. There may even be some common settings
in a [behaving] sections: things like verbosity, or which debugger to call on error.

Issue with phantomjs left running

I've started using PhantomJS as my browser under behaving.web and I'm noticing
that it's leaving the process running after the behave run is finished. After a while,
I have a dozen background phantomjs processes each taking a 1/2G of memory each...

I don't know who's "fault" it is: behaving, behave, splinter, selenium, phantomjs etc.,
and it's unlikely to be behaving, but I thought I'd flag it so you can keep your eye
on it. If I have time, I'll try to look at the chain of execution and report back.

phantomjs 2.0.0 under Linux.

Personas is giving weird error

This is my traceback:

  Traceback (most recent call last):
    File "/Users/galuszkak/Projects/virtuals/evmgmt/lib/python2.7/site-packages/behave/model.py", line 1173, in run
      match.run(runner.context)
    File "/Users/galuszkak/Projects/virtuals/evmgmt/lib/python2.7/site-packages/behave/model.py", line 1589, in run
      self.func(context, *args, **kwargs)
    File "/Users/galuszkak/Projects/virtuals/evmgmt/lib/python2.7/site-packages/behaving/personas/persona.py", line 53, in replace
      value = context.persona.get_value(var)
  AttributeError: 'dict' object has no attribute 'get_value'

How to escape the quotes needed to parse the variable

Hi,
Any idea how to escape the quotes needed(?) to parse the variables? Tried {}/:[] with no result.

Example:
Step "#hello_$randomday_$randommonth_$randomyear" - the variables are not parsed
Step " #hello_"$randomday" _ "$randommonth" _ "$randomyear" " - the variables are parsed but I got something like this - #hello_ "1" _ "July" _"2015"

Thank you for your help with this,
Bogdan

"I fill in" step cannot be used with text containing double quotes

behaving/web/steps/forms.py does not provide a way to fill in text containing double quotes. This is particularly relevant for text areas.

It might be beneficial to provide a variant I fill in "{name}" with step that relies on context.text, similar to behaving/personas/steps.py I set "{key}" to.

phantomjs parameters?

Is there an option to pass parameters (--ignore-ssl-errors=true) to phantomjs ?

tried it with a script, but phantomjs will not shutdown after completing the steps.

!/bin/bash

/opt/phantomjs/phantomjs $@ --ignore-ssl-errors=true

mailmock not compatible with python 3.6

error: uncaptured python exception, closing channel <smtpd.SMTPChannel connected 127.0.0.1:59782 at 0x7f0c411f0898> (<class 'TypeError'>:process_message() got an unexpected keyword argument 'mail_options'

method signature needs two additional parameters mail_options and rcpt_options
possibly other changes as well

missing wait_time=timeout in 'I should not see "text" within {timeout} seconds'

It seems to me that there is a missing wait_time=timeout argument to the code below.

@step(u'I should not see "{text}" within {timeout:d} seconds')
def should_not_see_within_timeout(context, text, timeout):
assert context.browser.is_text_not_present(text), u'Text was found'

The positive tests seems to be using it OK.

@step(u'I should see "{text}" within {timeout:d} seconds')
def should_see_within_timeout(context, text, timeout):
assert context.browser.is_text_present(text, wait_time=timeout), u'Text not found'

I've checked here that the wait_time can be used with the negative text present method.

http://splinter.cobrateam.info/docs/matchers.html

'I press' step does not escape single quotes within text

There is logic in behaving/web/steps/links.py to handle single quotes (which will disrupt XPath) within the specified link text, but this logic is not present in the 'I press "{name"}' step in behaving/web/steps/forms.py, so usage like

I press "Dave's Books"

will fail with "Element not found".

File uploads currently fail under Firefox, Chrome, and PhantomJS

splinter.Browser.attach_file(name, path) needs an absolute path, not a relative path.

The fix is as simple as inserting the following before line 184 in behaving\web\steps\forms.py

def i_attach(context, name, path):
    if not os.path.exists(path):
        path = os.path.join(context.attachment_dir, path)
        if not os.path.exists(path):
            assert False
    path = os.path.abspath(path)
    context.browser.attach_file(name, path)

I can do a pull request if you like as well

missing email configuartion

i have gmail account in testing
where and how i should set config for imap or pop3 config that let behaving connect and check for new mail
i can't find it in guide there is only one line about configuration
context.mail_path = os.path.join(os.path.dirname(mypackage.file), '../../var/mail/')
this like use /var/mail old style linux internal mailing system
please help about this

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.