I'm trying to use Playwright and pytest to test my website. My code keeps crashing when it fails. Below I've explained the things I've tried and why it keeps crashing. I could hack out a solution that wouldn't crash (initialise test first), but it's sloppy and I know there's a much better way to do it.
My question: When an org is successfully created, a popup appears saying 'Organisation has been updated'. How can I do an assertion that this element has appeared, without crashing if it doesn't? Thank you.
My first attempt. This crashes because page.locator couldn't find the element it was expecting.
test = page.locator("text=Organisation has been updated").inner_html()
assert test != ''
My second attempt. This crashes as test is undefined
try:
test = page.locator("text=Organisation has been updated").inner_html()
except:
pass
assert test != ''
edit - added my pytest code
import pytest
import pyotp
#Super admin can add, edit and delete an organisation
def test_super_admin_add_organisation(page):
page.goto("https://website/login/")
page.locator("[aria-label=\"Email\"]").click()
[...]
page.wait_for_url("https://website.com.au/two-factor-verification/")
# Two-Factor Authentication
totp = pyotp.TOTP("otp")
page.locator("[aria-label=\"Two Factor Pin\"]").fill(totp.now())
with page.expect_navigation():
page.click('button:has-text("Verify")')
page.wait_for_url("https://website.com.au/organisations/")
page.locator("button:has-text(\"add\")").click()
page.locator("[aria-label=\"Organisation\"]").click()
page.locator("[aria-label=\"Organisation\"]").fill("test_org")
[...]
page.locator("button:has-text(\"save\")").click()
try:
org_added = ''
org_added = page.locator("text=Organisation has been updated. close").inner_html()
except:
pass
assert org_added != ''
Related
When I'm trying to read data from sqlalchemy df=pd.read_sql_table(table, con, schema) getting runtime error :
runtime/cgo: could not obtain pthread_keys
tried 0x115 0x116 0x117 0x118 0x119 0x11a 0x11b 0x11c 0x11d 0x11e 0x11f 0x120 0x121 0x122 0x123 0x124 0x125 0x126 0x127 0x128 0x129 0x12a 0x12b 0x12c 0x12d 0x12e 0x12f 0x130 0x131 0x132 0x133 0x134 0x135 0x136 0x137 0x138 0x139 0x13a 0x13b 0x13c 0x13d 0x13e 0x13f 0x140 0x141 0x142 0x143 0x144 0x145 0x146 0x147 0x148 0x149 0x14a 0x14b 0x14c 0x14d 0x14e 0x14f 0x150 0x151 0x152 0x153 0x154 0x155 0x156 0x157 0x158 0x159 0x15a 0x15b 0x15c 0x15d 0x15e 0x15f 0x160 0x161 0x162 0x163 0x164 0x165 0x166 0x167 0x168 0x169 0x16a 0x16b 0x16c 0x16d 0x16e 0x16f 0x170 0x171 0x172 0x173 0x174 0x175 0x176 0x177 0x178 0x179 0x17a 0x17b 0x17c 0x17d 0x17e 0x17f 0x180 0x181 0x182 0x183 0x184 0x185 0x186 0x187 0x188 0x189 0x18a 0x18b 0x18c 0x18d 0x18e 0x18f 0x190 0x191 0x192 0x193 0x194
Below is the code:
class TeradataWriter:
def __init__(self):
print("in init")
def read_data_from_teradata(self):
try:
print('Create main')
import pdb;pdb.set_trace()
eng = self.create_connection_engine()
df = pd.read_sql_table("table_name", eng, schema="schema")
print(df)
except Exception as ex:
print('Exception: %s', ex.with_traceback())
def create_connection_engine(self):
try:
return create_engine('teradatasql://' + constants.TERADATA_HOST + '/?user='+ constants.TERADATA_USER_NAME + '&password=' + constants.TERADATA_PWD, echo=False)
except Exception as ex:
LOGGER.error('Exception: %s', ex)
raise Exception(message_constants.ERROR_WHILE_CREATING_CONNECTION_WITH_TERADATA)
if __name__ == "__main__":
p = TeradataWriter()
p.write_dataframe_to_teradata()
Edit: This is fixed. I was finally able to get their support and engineering team to reproduce the issue. They now build the driver with a newer version of go. Upgrade to >= 17.0.3, and you shouldn't see anymore segfaults.
I think I finally figured out why this happens. According to this Go issue, it happens if "If the host process spawns threads prior to loading the shared library, the offset will have changed."
In my case, I was importing matplotlib.pyplot in IPython before calling code that loads the shared library. This starts an event loop and causes the conditions that lead to the segfault.
I changed my code to import matplotlib.pyplot after configuring the teradata driver, and it went away.
According to the Go issue, they just need to recompile the library with a newer version of Go, which I've asked them to do. We'll see what they say.
I have run in to same issue -
So to fix the problem, I moved connect statement to main and it kind of fixed. Its worth trying in your case.
I must be missing something as PyCharm is reporting a variable is unused but it is in fact used on the very next line.
Any idea why PyCharm reports this way? Is it a bug or did I do something that needs to be changed?
Code:
def start_mass_reassign(self):
try:
or_dns = cx_Oracle.makedsn('REDACTED', REDACTED, service_name='REDACTED')
con = cx_Oracle.connect(user=self.username.get(), password=self.password.get(), dsn=or_dns)
valid_login = True
except cx_Oracle.DatabaseError as e:
if 'invalid username/password' in str(e).lower():
print('Invalid login')
valid_login = False
else:
valid_login = False
raise
if valid_login:
# rest of code verified works fine.
Image of notification reported by PyCharm.
As suggested by lmiguelvargasf I did try to use different values but it did not get rid of the error.
You are getting an error because in the else branch, you are raising an exception, and that variable will never be used because the flow execution terminates when the exception is raised.
I have the strangest problem I have ever met in my life.
I have a part of my code that looks like this:
class AzureDevOpsServiceError(Exception):
pass
skip = ["auto"]
def retrieve_results():
print(variable_not_defined)
... # some useful implementation
if not "results" in skip:
try:
print("before")
retrieve_results()
print("after")
except AzureDevOpsServiceError as e:
print(f"Error raised: {e}")
Obviously, this shall raise an error because variable_not_defined is, well, not defined.
However, for some strange reasons, the code executes correctly and prints
before
after
I have tried to call the function with an argument (retrieve_results(1234)) or adding an argument in the function (def retrieve_results(arg1) and retrieve_results()): both modifications will trigger an exception, so obviously the function is called.
Anyone has got a similar issue and knows what happens?
FYI: this is actually what my implementation looks like:
from azure.devops.exceptions import AzureDevOpsServiceError
import logging
def _retrieve_manual_results(connect: Connectivity, data: DataForPickle) -> None:
"""Retrieve the list of Test Results"""
print("G" + ggggggggggggggggggggggggggggggggggggg)
logger = connect.logger
data.run_in_progress = [165644]
if __name__ == "__main__":
p = ...
connect = ...
data = ...
if not "results" in p.options.skip:
try:
print("........B.........")
_retrieve_manual_results(connect, data)
print("........A.........")
except AzureDevOpsServiceError as e:
logging.error(f"E004: Error while retrieving Test Results: {e}")
logging.debug("More details below...", exc_info=True)
As highlighted by #gmds, it was a problem of cache.
Deleting the .pyc file didn't do much.
However, I have found a solution:
Renaming the function (e.g. adding _)
Running the program
Renaming back (i.e. removing _ in the previous example)
Now, the issue is solved.
If anyone knows what is going behind the scene I am very interested.
I am attempting to modify the extremely helpful open keynotes button script to create a 'reload keynotes' button.
Currently i am trying to use the Reload Method of the KeyBasedTreeEntryTable class.
kt = DB.KeynoteTable.GetKeynoteTable(revit.doc)
kt_ref = kt.GetExternalFileReference()
path = DB.ModelPathUtils.ConvertModelPathToUserVisiblePath(
kt_ref.GetAbsolutePath()
)
reloader = DB.KeyBasedTreeEntryTable.Reload()
if not path:
forms.alert('No keynote file is assigned.')
else:
reloader
This is the error message that i am receiving.
TypeError: Reload() takes exactly 2 arguments (0 given)
I am stuck here and appreciate any help.
You can use Revit API to reload the keynotes, the method KeyBasedTreeEntryTable.Reload just needs a parameter to store warnings thrown during operation, this parameter can be None to make it easy.
Also KeyBasedTreeEntryTable should be an instance, the reload method is not static.
The cool thing is that you don't need to find any KeyBasedTreeEntryTable instance, because the KeynoteTable class inherits from KeyBasedTreeEntryTable, so the Reload method is already available with the kt instance in your script.
(This operation needs a transaction context too, like in the following examples)
Simple way
kt = DB.KeynoteTable.GetKeynoteTable(revit.doc)
t = DB.Transaction(revit.doc)
t.Start('Keynote Reload')
try:
result = kt.Reload(None)
t.Commit()
except:
t.RollBack()
forms.alert('Keynote Reloading : {}'.format(result))
# result can be 'Success', 'ResourceAlreadyCurrent' or 'Failure'
Complete way
kt = DB.KeynoteTable.GetKeynoteTable(revit.doc)
# create results object
res = DB.KeyBasedTreeEntriesLoadResults()
t = DB.Transaction(revit.doc)
t.Start('Keynote Reload')
try:
result = kt.Reload(res) # pass results object
t.Commit()
except:
t.RollBack()
# read results
failures = res.GetFailureMessages()
syntax_err = res.GetFileSyntaxErrors()
entries_err = res.GetKeyBasedTreeEntryErrors()
# res.GetFileReadErrors() returns files errors, should be already in failures Messages
warnings = ''
warnings += '\n'.join([message.GetDescriptionText() for message in failures])
if syntax_err:
warnings += '\n\nSyntax errors in the files :\n'
warnings += '\n'.join(syntax_err)
if entries_err:
warnings += '\nEntries with error :\n'
warnings += '\n'.join([key.GetEntry().Key for key in entries_err])
forms.alert('Keynote Reloading : {}\n{}'.format(result, warnings))
I've been thinking about switching from nose to behave for testing (mocha/chai etc have spoiled me). So far so good, but I can't seem to figure out any way of testing for exceptions besides:
#then("It throws a KeyError exception")
def step_impl(context):
try:
konfigure.load_env_mapping("baz", context.configs)
except KeyError, e:
assert (e.message == "No baz configuration found")
With nose I can annotate a test with
#raises(KeyError)
I can't find anything like this in behave (not in the source, not in the examples, not here). It sure would be grand to be able to specify exceptions that might be thrown in the scenario outlines.
Anyone been down this path?
I'm pretty new to BDD myself, but generally, the idea would be that the tests document what behaves the client can expect - not the step implementations. So I'd expect the canonical way to test this would be something like:
When I try to load config baz
Then it throws a KeyError with message "No baz configuration found"
With steps defined like:
#when('...')
def step(context):
try:
# do some loading here
context.exc = None
except Exception, e:
context.exc = e
#then('it throws a {type} with message "{msg}"')
def step(context, type, msg):
assert isinstance(context.exc, eval(type)), "Invalid exception - expected " + type
assert context.exc.message == msg, "Invalid message - expected " + msg
If that's a common pattern, you could just write your own decorator:
def catch_all(func):
def wrapper(context, *args, **kwargs):
try:
func(context, *args, **kwargs)
context.exc = None
except Exception, e:
context.exc = e
return wrapper
#when('... ...')
#catch_all
def step(context):
# do some loading here - same as before
This try/catch approach by Barry works, but I see some issues:
Adding a try/except to your steps means that errors will be hidden.
Adding an extra decorator is inelegant. I would like my decorator to be a modified #where
My suggestion is to
have the expect exception before the failing statement
in the try/catch, raise if the error was not expected
in the after_scenario, raise error if expected error not found.
use the modified given/when/then everywhere
Code:
def given(regexp):
return _wrapped_step(behave.given, regexp) #pylint: disable=no-member
def then(regexp):
return _wrapped_step(behave.then, regexp) #pylint: disable=no-member
def when(regexp):
return _wrapped_step(behave.when, regexp) #pylint: disable=no-member
def _wrapped_step(step_function, regexp):
def wrapper(func):
"""
This corresponds to, for step_function=given
#given(regexp)
#accept_expected_exception
def a_given_step_function(context, ...
"""
return step_function(regexp)(_accept_expected_exception(func))
return wrapper
def _accept_expected_exception(func):
"""
If an error is expected, check if it matches the error.
Otherwise raise it again.
"""
def wrapper(context, *args, **kwargs):
try:
func(context, *args, **kwargs)
except Exception, e: #pylint: disable=W0703
expected_fail = context.expected_fail
# Reset expected fail, only try matching once.
context.expected_fail = None
if expected_fail:
expected_fail.assert_exception(e)
else:
raise
return wrapper
class ErrorExpected(object):
def __init__(self, message):
self.message = message
def get_message_from_exception(self, exception):
return str(exception)
def assert_exception(self, exception):
actual_msg = self.get_message_from_exception(exception)
assert self.message == actual_msg, self.failmessage(exception)
def failmessage(self, exception):
msg = "Not getting expected error: {0}\nInstead got{1}"
msg = msg.format(self.message, self.get_message_from_exception(exception))
return msg
#given('the next step shall fail with')
def expect_fail(context):
if context.expected_fail:
msg = 'Already expecting failure:\n {0}'.format(context.expected_fail.message)
context.expected_fail = None
util.show_gherkin_error(msg)
context.expected_fail = ErrorExpected(context.text)
I import my modified given/then/when instead of behave, and add to my environment.py initiating context.expected fail before scenario and checking it after:
def after_scenario(context, scenario):
if context.expected_fail:
msg = "Expected failure not found: %s" % (context.expected_fail.message)
util.show_gherkin_error(msg)
The try / except approach you show is actually completely correct because it shows the way that you would actually use the code in real life. However, there's a reason that you don't completely like it. It leads to ugly problems with things like the following:
Scenario: correct password accepted
Given that I have a correct password
When I attempt to log in
Then I should get a prompt
Scenario: incorrect password rejected
Given that I have an incorrect password
When I attempt to log in
Then I should get an exception
If I write the step definition without try/except then the second scenario will fail. If I write it with try/except then the first scenario risks hiding an exception, especially if the exception happens after the prompt has already been printed.
Instead those scenarios should, IMHO, be written as something like
Scenario: correct password accepted
Given that I have a correct password
When I log in
Then I should get a prompt
Scenario: correct password accepted
Given that I have a correct password
When I try to log in
Then I should get an exception
The "I log in" step should not use try; The "I try to log in" matches neatly to try and gives away the fact that there might not be success.
Then there comes the question about code reuse between the two almost, but not quite identical steps. Probably we don't want to have two functions which both login. Apart from simply having a common other function you call, you could also do something like this near the end of your step file.
#when(u'{who} try to {what}')
def step_impl(context):
try:
context.execute_steps("when" + who + " " + what)
context.exception=None
except Exception as e:
context.exception=e
This will automatically convert all steps containing the word "try to" into steps with the same name but with try to deleted and then protect them with a try/except.
There are some questions about when you actually should deal with exceptions in BDD since they aren't user visible. It's not part of the answer to this question though so I've put them in a separate posting.
Behave is not in the assertion matcher business. Therefore, it does not provide a solution for this. There are already enough Python packages that solve this problem.
SEE ALSO: behave.example: Select an assertion matcher library