def set_up_browser(ctx: Context) -> None: """Setup the browser we will use with selenium for testing""" if os.getenv("BROWSER", "Chrome") == "Firefox": ctx.driver = webdriver.Firefox() else: _instantiate_chromedriver(ctx) ctx.default_window_size = ctx.driver.get_window_size()
def execute_scenario_by_steps(ctx: Context, scenario: Scenario) -> None: """ This function executes each step in a scenario with the ctx.execute steps method. We are doing this in place of scenario.run(ctx._runner) because that hacks the context runner which confuses the behave reporter and formatter causing assertion errors. This is a much smoother way to run steps in the before and after hook. Args: ctx: The behave context scenario: The behave scenario object """ # Set an empty list of steps to run parsed_steps = [] # For each step put the step in the parsed list for step in scenario.steps: parsed_steps.append(f"{step.keyword} {step.name}") # check to see if we have a table with our step. If we do make sure we put the headings # and rows into the parsed steps list so we execute the full step if step.table: heading_string = "" for heading in step.table.headings: heading_string += f"{heading}|" parsed_steps.append(f"|{heading_string}") for row in step.table.rows: row_string = "|".join(row.cells) parsed_steps.append(f"|{row_string}|") steps_string = "\n".join(parsed_steps) LOGGER.info(f"Steps run in setup or teardown scenario:\n{steps_string}") ctx.execute_steps(steps_string)
def create_trusty_uat_lxd_image(context: Context) -> None: """Create a trusty lxd image with ubuntu-advantage-tools installed This will launch a container, install ubuntu-advantage-tools, and publish the image. The image's name is stored in context.image_name for use within step code. :param context: A `behave.runner.Context`; this will have `image_name` set on it. """ def image_cleanup() -> None: if context.config.image_clean: subprocess.run(["lxc", "image", "delete", context.image_name]) else: print("Image cleanup disabled, not deleting:", context.image_name) if context.reuse_container: print(" Reusing the existent container: ", context.reuse_container) else: now = datetime.datetime.now() context.image_name = "behave-image-" + now.strftime("%s%f") build_container_name = "behave-image-build-" + now.strftime("%s%f") launch_lxd_container(context, "ubuntu:trusty", build_container_name) _install_uat_in_container(build_container_name) _capture_container_as_image(build_container_name, context.image_name) context.add_cleanup(image_cleanup)
def run_setup_teardown_tags(ctx: Context, feature: Feature) -> None: """ Finds setup and teardown tags on scenarios in feature files. If present it handles them separately than normal tags Args: ctx: The behave context feature: The behave feature """ remaining_scenarios = [] ctx.teardown_scenarios = [] # Check each feature to see if we have setup or teardown tags. Else they are normal scenarios for scenario in feature.scenarios: # Pipe the feature and scenario into the context so we can use it downstream in child steps ctx.feature = feature ctx.scenario = scenario if "setup" in scenario.tags: LOGGER.info( "Setup scenario detected. Running it before the rest of the feature." ) # Run the steps in the setup scenario as setup execute_scenario_by_steps(ctx, scenario) elif "teardown" in scenario.tags: LOGGER.info( "Teardown scenario detected. Saving it so we can run as cleanup after the rest of the feature." ) ctx.teardown_scenarios.append(scenario) else: remaining_scenarios.append(scenario) feature.scenarios = remaining_scenarios
def test_async_step_passes(self): """ENSURE: Failures in async-steps are detected correctly.""" step_container = SimpleStepContainer() with use_step_import_modules(step_container): # -- STEP-DEFINITIONS EXAMPLE (as MODULE SNIPPET): # VARIANT 1: Use async def step_impl() from behave import given, when from behave.api.async_step import async_run_until_complete @given('an async-step passes') @async_run_until_complete async def given_async_step_passes(context): context.traced_steps.append("async-step1") @when('an async-step passes') @async_run_until_complete async def when_async_step_passes(context): context.traced_steps.append("async-step2") # -- RUN ASYNC-STEP: Verify that async-steps can be executed. context = Context(runner=Runner(config={})) context.traced_steps = [] given_async_step_passes(context) when_async_step_passes(context) assert context.traced_steps == ["async-step1", "async-step2"]
def step_impl(context: Context): for row in context.table: answer, expected = row['answer'], row.get('expected', 'right') question = current_question(context) recent_answer: StudyController.RecordedAnswer = \ context.study_controller.record_answer_and_get_status( question_number=question.question_number, quiz=question.quiz, selection=answer, session_id=None ) if expected in 'wrong': assert_that(recent_answer.correct, is_(False)) else: assert_that(recent_answer.correct, is_(True)) context.recent_answer = recent_answer more_questions = recent_answer.next_question_number if more_questions: new_question = context.study_controller.prepare_quiz_question_document( recent_answer.quiz, recent_answer.next_question_number ) context.current_question = new_question
def sso_should_be_signed_out_from_sso_account(context: Context, supplier_alias: str): """Sign out from SSO.""" actor = get_actor(context, supplier_alias) session = actor.session # Step 1 - Get to the Sign Out confirmation page next_param = URLs.PROFILE_LANDING.absolute response = sso.logout.go_to(session, next_param=next_param) context.response = response # Step 2 - check if Supplier is on Log Out page & extract CSRF token sso.logout.should_be_here(response) token = extract_csrf_middleware_token(response) update_actor(context, supplier_alias, csrfmiddlewaretoken=token) # Step 3 - log out next_param = URLs.PROFILE_LANDING.absolute response = sso.logout.logout(session, token, next_param=next_param) context.response = response # Step 4 - check if Supplier is on SSO landing page profile.about.should_be_here(response) profile.about.should_be_logged_out(response) # Step 5 - reset requests Session object reset_actor_session(context, supplier_alias)
def step_generic_modify_request_json(ctx: Context, target_key: str, value: str) -> None: """Modifies the request data in the behave context to have the actual value of the given string representation. Args: ctx: The behave context target_key: The key whose value is to be modified value: A string representation of what the new value should be """ LOGGER.debug( f"Attempting to modify the JSON request payload at: {target_key} to be: {value}." ) desired_value = CommonBehave.interpolate_context_attributes(ctx, value) parsed_key = CommonBehave.interpolate_context_attributes(ctx, target_key) if desired_value.lower() in ("none", "null"): ctx.request_data = modify_json_value(ctx.request_data, parsed_key, None) elif desired_value.lower() in ("invalid", "empty", "empty string"): ctx.request_data = modify_json_value(ctx.request_data, parsed_key, "") elif desired_value.lower() in "uuid": ctx.request_data = modify_json_value(ctx.request_data, parsed_key, str(uuid.uuid4())) else: ctx.request_data = modify_json_value(ctx.request_data, parsed_key, desired_value) LOGGER.debug("Successfully updated JSON request payload.")
def execute_scenario_by_steps(ctx: Context, scenario: Scenario) -> None: """Step executor for setup and teardown tagged scenarios Args: ctx: The behave context scenario: The behave scenario object """ # Set an empty list of steps to run parsed_steps = [] # For each step put the step in the parsed list for step in scenario.steps: parsed_steps.append(f"{step.keyword} {step.name}") # check to see if we have a table with our step. If we do make sure we put the headings # and rows into the parsed steps list so we execute the full step if step.table: heading_string = "" for heading in step.table.headings: heading_string += f"{heading}|" parsed_steps.append(f"|{heading_string}") for row in step.table.rows: row_string = "|".join(row.cells) parsed_steps.append(f"|{row_string}|") steps_string = "\n".join(parsed_steps) for step in parsed_steps: print(ansicolor.green(f" {step}")) # noqa print("\n") # noqa ctx.execute_steps(steps_string)
def before_all(context: Context): os.environ["APPLICATION_ENV"] = "test" from pepy.infrastructure import container from pepy.infrastructure.web import app context.container = container context.client = app.test_client()
def test_on_cleanup_error__may_be_called_several_times_per_cleanup(self): def bad_cleanup1(): raise RuntimeError("CLEANUP_1") def bad_cleanup2(): raise RuntimeError("CLEANUP_2") class CleanupErrorCollector(object): def __init__(self): self.collected = [] def __call__(self, context, cleanup_func, exception): self.collected.append((context, cleanup_func, exception)) context = Context(runner=Mock()) collect_cleanup_error = CleanupErrorCollector() with pytest.raises(RuntimeError): with scoped_context_layer(context): context.on_cleanup_error = collect_cleanup_error context.add_cleanup(bad_cleanup1) context.add_cleanup(bad_cleanup2) expected = [ (context, bad_cleanup2, RuntimeError("CLEANUP_2")), (context, bad_cleanup1, RuntimeError("CLEANUP_1")), ] assert len(collect_cleanup_error.collected) == 2 assert collect_cleanup_error.collected[0][:-1] == expected[0][:-1] assert collect_cleanup_error.collected[1][:-1] == expected[1][:-1]
def launch_lxd_container( context: Context, image_name: str, container_name: str ) -> None: """Launch a container from an image and wait for it to boot This will also register a cleanup with behave so the container will be removed before test execution completes. :param context: A `behave.runner.Context`; used only for registering cleanups. :param container_name: The name to be used for the launched container. """ subprocess.run(["lxc", "launch", image_name, container_name]) def cleanup_container() -> None: if not context.config.destroy_instances: print("Leaving lxd container running: {}".format(container_name)) else: subprocess.run(["lxc", "delete", "-f", container_name]) context.add_cleanup(cleanup_container) wait_for_boot(container_name)
def after_feature(context: Context, feature: Feature): if "UsesCustomParameters" in feature.tags: # after a feature that uses custom parameters, clear all custom parameters in each agent for agent in ["Acme", "Bob", "Faber", "Mallory"]: context.execute_steps( f'Given "{agent}" is running with parameters ' + '"{}"' )
def the_string_is_encoded(context: Context, plain_text: str): """ Args: context: The feature context. plain_text: The text to encode. """ context.plain_text = plain_text context.cypher_text = context.mark.encode(plain_text)
def step_impl(context: Context, acronym: str, year: str): luy = LearningUnitYear.objects.get(acronym=acronym, academic_year__year=int(year[:4])) url = reverse('learning_unit', args=[luy.pk]) context.current_page = LearningUnitPage( driver=context.browser, base_url=context.get_url(url)).open() context.test.assertEqual(context.browser.current_url, context.get_url(url))
def before_all(context: Context): # setup global variables context.env = get_env(context.config.userdata["env"]) context.driver = get_driver(context.config.userdata["browser"]) # setup page_objects context.login_page = LoginPage(context) context.main_page = MainPage(context) context.question_page = QuestionPage(context)
def step_impl_run(context: Context) -> None: bc: BackupContext = context.backup_context with patch("subprocess.run") as mockrun: context.result = bc.run(["fakeprog"]) mockrun.assert_called_once_with(["fakeprog"], capture_output=True, env=ANY) context.script_env = mockrun.call_args[1]["env"]
def test_add_cleanup_with_known_layer(self): my_cleanup = Mock(spec=cleanup_func) context = Context(runner=Mock()) with scoped_context_layer(context, layer="scenario"): context.add_cleanup(my_cleanup, layer="scenario") my_cleanup.assert_not_called() # CALLS-HERE: context._pop() my_cleanup.assert_called_once()
def before_scenario(context: Context, scenario: Scenario): logging.debug(f"Starting scenario: {scenario.name}") context.scenario_data = initialize_scenario_data() session_name = f"{scenario.feature.name} -> {scenario.name}" mobile = True if "mobile" in scenario.tags else False context.driver = start_driver_session(session_name, DRIVER_CAPABILITIES, mobile=mobile)
def test_add_cleanup_with_unknown_layer_raises_lookup_error(self): """Cleanup function is not registered""" my_cleanup = Mock(spec=cleanup_func) context = Context(runner=Mock()) with scoped_context_layer(context): # CALLS-HERE: context._push() with pytest.raises(LookupError) as error: context.add_cleanup(my_cleanup, layer="other") my_cleanup.assert_not_called()
def test_add_cleanup_with_known_layer_and_kwargs(self): my_cleanup = Mock(spec=cleanup_func_with_args) context = Context(runner=Mock()) with scoped_context_layer(context, layer="scenario"): context.add_cleanup(my_cleanup, layer="scenario", name="alice") my_cleanup.assert_not_called() # CALLS-HERE: context._pop() my_cleanup.assert_called_once_with(name="alice")
def test_add_cleanup_with_args(self): my_cleanup = Mock(spec=cleanup_func_with_args) context = Context(runner=Mock()) with scoped_context_layer(context): context.add_cleanup(my_cleanup, 1, 2, 3) my_cleanup.assert_not_called() # CALLS-HERE: context._pop() my_cleanup.assert_called_once_with(1, 2, 3)
def step_impl(context: Context, acronym: str, year: str): egy = EducationGroupYear.objects.get(acronym=acronym, academic_year__year=int(year[:4])) url = reverse('education_group_read', args=[egy.pk, egy.pk]) context.current_page = EducationGroupPage( driver=context.browser, base_url=context.get_url(url)).open() context.test.assertEqual(context.browser.current_url, context.get_url(url))
def test_cleanup_func_is_called_when_context_frame_is_popped(self): my_cleanup = Mock(spec=cleanup_func) context = Context(runner=Mock()) with scoped_context_layer(context): # CALLS-HERE: context._push() context.add_cleanup(my_cleanup) # -- ENSURE: Not called before context._pop() my_cleanup.assert_not_called() # CALLS-HERE: context._pop() my_cleanup.assert_called_once()
def the_files_should_exist(context: runner.Context) -> None: """Check a list of files that should have been created. Args: context: Behave runner context with a list of files. """ for target_file in context.table: context.execute_steps(u'then the file "{}" should exist'.format(target_file["file"]))
def test_add_cleanup_with_known_deeper_layer3(self): my_cleanup = Mock(spec=cleanup_func) context = Context(runner=Mock()) with scoped_context_layer(context, layer="testrun"): with scoped_context_layer(context, layer="feature"): with scoped_context_layer(context, layer="scenario"): context.add_cleanup(my_cleanup, layer="feature") my_cleanup.assert_not_called() my_cleanup.assert_called_once() # LEFT: layer="feature" my_cleanup.assert_called_once()
def step_impl(context: Context): session_store = SessionStore(TinyDB(storage=MemoryStorage)) quiz_store = QuizStore(context.temporary_directory.name) quizzology = Quizzology(quiz_store, session_store) study_controller: StudyController = StudyController(quizzology) context.study_controller = study_controller author_controller: AuthorController = AuthorController(quizzology) context.author_controller = author_controller
def before_all(context: Context): remote_desired_capabilities = CONFIG["environments"][TASK_ID] local_desired_capabilities = CONFIG["capabilities"] for key in CONFIG["capabilities"]: if key not in remote_desired_capabilities: remote_desired_capabilities[key] = CONFIG["capabilities"][key] context.remote_desired_capabilities = remote_desired_capabilities context.local_desired_capabilities = local_desired_capabilities context.config.setup_logging(configfile=".behave_logging")
def test_add_cleanup__rejects_noncallable_cleanup_func(self): class NonCallable(object): pass non_callable = NonCallable() context = Context(runner=Mock()) with pytest.raises(AssertionError) as e: with scoped_context_layer(context): context.add_cleanup(non_callable) assert "REQUIRES: callable(cleanup_func)" in str(e.value)
def step_impl(context: Context): context.user = FacultyManagerFactory( user__username="******", user__first_name="Keyser", user__last_name="Söze", user__password="******").user page = LoginPage(driver=context.browser, base_url=context.get_url('/login/')).open() page.login("usual_suspect", 'Roger_Verbal_Kint') context.test.assertEqual(context.browser.current_url, context.get_url('/'))
def __init__(self,runner): Context.__init__(self,runner) self.should_run = True
def before_all(context: runner.Context): context.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)