Can I have an assertion that applies throughout an entire test instead of having an assertion at a particular instance/ after a particular action? - playwright

I am testing a website and I have this error message that shows up every once in a while when I'm executing the automation for the tests due to the websites load issues. The error message shows up only some of the times in random locations during the test. Sometimes it shows after I click on button x. The next time it'll happen when I click on button y. So it is hard to predict exactly when the error message will show. I do not want to have to write an assertion after every single action in my script (such as having the same assertion after every page.locator.click()) How can I do something like "If an error message with locator x shows up at any point during this entire test, fail the test and display this message"? The assertion I am currently using is await expect(locator,"Error Message").not.tobeVisible(), which is using a locator only visible in the error message. So the words "Error Message" is displayed and the test is failed, indicating that the failed test was a result of the error message. (The error message is occurring due to db load issues).
I can do an assertion such as
await page.locator.click();
await expect(locator,"Error Message").not.tobeVisible()
await page.locator.click();
await page.locator.click();
await page.locator.click();
but the assertion here only applies to checking for the error message after the first click. Sometimes it occurs after the 2nd click, 3rd click, etc. It's an error message from the website indicating load issues. So the test will fail eventually but I'd like to have the assertion of await expect(locator,"Error Message").not.tobeVisible() apply throughout the test and not have to do something like putting the assertion after every single action like this:
await page.locator.click();
await expect(locator,"Error Message").not.tobeVisible();
await page.locator.click();
await expect(locator,"Error Message").not.tobeVisible();
await page.locator.click();
await expect(locator,"Error Message").not.tobeVisible();
await page.locator.click();
await expect(locator,"Error Message").not.tobeVisible();
await expect(locator,"Error Message").not.tobeVisible() only checks for a particular instance when explicitly stated, and not constantly checking throughout the entire test.
It would be great to do be able to write an assertion of await expect(locator,"Error Message").not.tobeVisible() once so that it applies throughout the entire test, and not having to write it multiple times after each click/action due to the error messages unpredictable nature.

You can create one liner error message verifier and call in places where you know its most likely to occur:
async ValidateNoError() {
expect(await this.page.locator(Errorbannermessage).count()).toEqual(0);
}
This way you can easily delete/update/comment later as required.

Related

Transactions in Dart Mysql1

How do I perform a transaction in dart mysql1.
I tried doing this,
await pool.transactional((conn) async {});
But the key wait pool is showing this error
Undefined name 'pool'.
Try correcting the name to one that is defined, or defining the name.dartundefined_identifier
try this instead
await MySqlConnection.connect(MYSQL_SETTING).transaction((context) async {})

Can exceptions thrown in dart streams be handled by subscribers without closing the stream?

Short example of what I'm having trouble understanding:
Stream<int> getNumbersWithException() async* {
for (var i = 0; i < 10; i++) {
yield i;
if (i == 3) throw Exception();
}
}
With usage:
getNumbersWithException()
.handleError((x) => print('Exception caught for $x'))
.listen((event) {
print('Observed: $event');
});
This will stop at 3 with the output:
Observed: 0
Observed: 1
Observed: 2
Observed: 3
Exception caught for Exception: foo
From the documentation (https://dart.dev/tutorials/language/streams) and (https://api.dart.dev/stable/2.9.1/dart-async/Stream/handleError.html), this is as expected, as exceptions thrown will automatically close the stream.
Does this mean that the correct way to handle exceptions in a stream, so that subscriptions can be long-lived in such an event, is to handle the exception inside the stream itself? That it is not possible to do so from the outside?
Is this the same for broadcast streams?
If I'm thinking about this in the wrong way, what are some pointers to start thinking right?
I'm currently thinking of streams as being a source of asynchronous data events that occasionally might be error events. From the documentation and examples, it all looks neat, but I'm thinking that wanting to handle errors and otherwise continue observing the data stream is a normal use case. I'm having a hard time writing the code to do so. But, I might be going about this wrong. Any insights will be much appreciated.
Edit: I can add that I've tried various things like using a stream transformer, with the same result:
var transformer = StreamTransformer<int, dynamic>.fromHandlers(
handleData: (data, sink) => sink.add(data),
handleError: (error, stackTrace, sink) =>
print('Exception caught for $error'),
handleDone: (sink) => sink.close(),
);
getNumbersWithException().transform(transformer).listen((data) {
print('Observed: $data');
});
Also, listen() has an optional argument cancelOnError that looks promising, but it defaults to false, so no cigar here.
The generator method
Stream<int> getNumbersWithException() async* {
for (var i = 0; i < 10; i++) {
yield i;
if (i == 3) throw Exception();
}
}
will terminate when you throw an exception.
The throw works normally, it doesn't directly add the exception to the stream. So, it propagates out through the loop and the method body, until the entire method body ends with the thrown exception.
At that point the unhandled exception is added to the stream, and then the stream is closed because the body has ended.
So, the problem is not with the handling, but with the generation of the stream.
You must indeed handle the error locally to avoid it ending the stream generating body.
You can't add more than one error to a stream using throw in an async* method, and the error will be the last thing that stream does.
The availabe hack to actually emit more than one error is to yield the exception:
if (i == 3) yield* () async* { throw Exception(); }();
// or: yield* Stream.fromFuture(Future.error(Exception());
That will emit an exception directly into the generated stream without throwing it locally and ending the generator method body.

When a TestMethod fails repeat once

I'm writing coded UI test's for an ASP.NET MVC web application. I'm using Visual Studio 2012.
Basically I have a bunch of test methods like below:
I use a ordered test file to run all of them at once in the order I would like.
The problem is that the way the tests work is that if one test fails, it is marked as ref/failed in the output, and often a test will work if I run it again. I want to be able to set my ordered test to run and if a test method fails it will automatically try to run that test method one more time.
How do I do this? I was thinking of putting an if statement at the end of each test method, like:
if(TestFailed) {
RecallTest();
}
I would use some sort of counter, but how do I write the above in a coded UI test?
There are several ways you can handle this. The most obvious is something like this:
[TestMethod]
public void myTestMethod()
{
int iteration = 0;
if (iteration < 2)
{
try
{
// the usual test code goes here
}
catch (Exception)
{
// handles any exception kind
iteration++;
myTestMethod();
}
}
}
This will recursively call the test method only if the method fails. You can set it to catch any exception (Exception) or to catch specific exceptions only - just change the exception kind in the catch block.
This is typically discouraged in CodedUI tests because it can interact badly with the test runner's built in exception reporting (I'd recommend looking at adding logging to report that you got a failure). It will give you the one-time only rerun, however (Caveat: I haven't actually tried this myself - you might need to tweak the code to ensure that your test cleanup occurs depending on your test code).
Try using the playback error handling:
Playback.PlaybackError += Playback_PlaybackError;
This way you can register an event handler that is called every time the playback encounters an error.
In the event handling method you can tell the playback to repeat the action that threw the error:
static void Playback_PlaybackError(object sender, PlaybackErrorEventArgs e)
{
e.Result = PlaybackErrorOptions.Retry;
}
A counter can be added to prevent an endless loop of error and retry.

In Dart, if I use Future.wait with a list of Futures and an error is thrown on one of the Futures, what happens to the other Futures?

If I have the following code:
Future<int> a = new Future(() { print('a'); return 1; });
Future<int> b = new Future.error('Error!');
Future<int> c = new Future(() { print('c'); return 3; });
Future.wait([a, b, c])
.then((List<int> values) => print(values))
.catchError((e) => print(e));
What is printed?
Does the error caught by catchError have any idea of what Future died? Or which Futures remain?
Determining what is printed is pretty easy by running it (do you not have a Dart VM handy?):
a
c
AsyncError: 'Error!'
The documentation for Future.wait() says:
Wait for all the given futures to complete and collect their values.
Returns a future which will complete once all the futures in a list are complete. If any of the futures in the list completes with an error, the resulting future also completes with an error. Otherwise the value of the returned future will be a list of all the values that were produced.
e.error is the value that was created with ('Error!', in this case), so by setting that to something indicating which Future has the error, you can see which Future "died". Of course, if you're not the one creating the error, that doesn't help.
In general, I think you use Future.wait() on a List like this when an error in any of them would be handled similarly. Needing to know which one failed might be a sign that you don't want to wait() on all of them together.
Update: I just realized the question title asks a question not asked in the question body: What happens to the other Futures?
The other Futures keep running. The Future returned by wait() throws whichever error it receives as soon as it receives it, so all return values are lost, and if any of the other Futures throws an error, it isn't caught, but each Future still runs until returning or throwing an error.
AFAIK, you won't know precisely which Future generated the error. But, you can query the error object and get some useful information:
Future.wait([a, b, c])
.then((List<int> values) => print(values))
.catchError((e) {
print(e.error);
print(e.stackTrace);
print(e.runtimeType);
print(e.error.runtimeType);
});
Running this prints:
a
c
Error!
null
AsyncError
String
This tells us that the original error was a String. I don't know how useful that is to you, but its something.

Query failed and the error.message is the data

A friend's query was failing. Fortunately, he was catching it in his fail callback (you DO have a fail callback for every server call, right?). Here's kind of what he had:
var getPersons = function(personsObservable) {
return EntityQuery.from('Person')
.using(manager).execute()
.then(querySucceeded).fail(queryFailed);
}
function queryFailed(error) {
var msg = 'Error retreiving data. ' + error.message;
logError(msg, error);
throw error;
}
The error.message simply showed the JSON data ... which looked a bit like this:
"[{"$id":"1","$type":"Person, ProjectName","Id":12,"FirstName":"Bob","LastName":"Smith","Email":"bs#contoso.com","Blog":"http://bs.contoso.com","Twitter": ..."
WAT?
He examined the error.XHR which provides the full AJAX XHR object used for this query. He could see that the HTTP Status Code was a 200 ... meaning that everything was cool from the server. The fact that he had real data pretty much said the same thing.
So why is Breeze failing? How does he diagnose the problem?
Breeze might be failing. But there's a good chance that the problem lies elsewhere. Usually if Breeze fails, there is a meaningful error message. This error message is not meaningful. But it does provide clues.
Check your success callback first
The fail callback can be invoked (1) if the operation fails or (2) if the success callback fails. If the operation fails, you've got a Breeze-related problem. If the success callback fails, you probably have an application code problem.
To determine which, put a breakpoint on the first line of the success callback (in his case, the first line of querySucceeded). If you hit the breakpoint, you know Breeze has done its bit and has handed off to you. Step through your callback to find the mistakes which are most likely yours and, therefore, easy to fix.
Check your custom EntityType constructors and initializers
In his case it did not get to the success callback. So something went wrong as Breeze tried to make cached entities out of the JSON data from the server. What could that be?
There are many potential causes. Could be a Breeze bug. Always best, though, to eliminate pilot error first. Did you write a custom constructor or initializer for this EntityType?
He did. He had an initializer that added a fullName calculated property to his Person. It looked sort of like this:
metadataStore.registerEntityTypeCtor('Person', null, personInitializer);
function personInitializer(person) {
person.fullName = ko.computed(function () {
return entity.firstName() + ' ' + person.lastName();
});
}
He didn't see a problem. But following diagnostic procedure, he put a breakpoint on the initializer.
Sure enough ... he had a typo ...
// "entity" does not exist. Null object error
return entity.firstName() + ' ' + person.lastName();
As soon as he changed entity to person, all was well.
I can't explain at the moment why the null object reference manifested as a Q promise fail error with the JSON Person data in the message. Strange stuff happens in JavaScript. But the clues were there:
server delivered the data
failed before getting to the success callback
data are about Person
have a Person initializer (or constructor)
Read the clues and you'll know where to look.
Hope this tip saves you from gray hair and a bald head.

Resources