I'm having problems with EarlGrey's synchronization feature. I'm trying to create a simple test example for my app that basically checks if the login button shows up.
func testExample() {
let success = GREYCondition(name: "Wait for action view controller", block: { () -> Bool in
if let rootVC = UIApplication.shared.keyWindow?.rootViewController, rootVC is ValuePropsViewController {
return true
}
else {
return false
}
}).wait(withTimeout: 10)
GREYAssertTrue(success, reason: "Action view controller should appear within 5 seconds")
EarlGrey.select(elementWithMatcher: grey_accessibilityID("loginButton")).assert(grey_sufficientlyVisible())
}
However, it always times out and I get the following error message. I check the screenshots and the correct screen is showing at failure.
Exception Name: AssertionFailedException
Exception Reason: Timed out while waiting to perform assertion.
Exception with Assertion: {
"Assertion Criteria" : "assertWithMatcher: matcherForSufficientlyVisible(>=0.750000)",
"Element Matcher" : "(respondsToSelector(accessibilityIdentifier) && accessibilityID('loginButton'))"
}
Exception Details: Error Trace: [
{
"Description" : "Failed to execute block because idling resources below are busy.",
"Description Glossary" : {
"animateWithDuration:delay:options:animations:completion:" : "<NSObject: 0x610000203a30> caused the App to be in busy state for 6.8 seconds.",
"performSelector #selector(tick) on VAAppDelegate" : "Delayed performSelector caused the App to be in busy state for 2 seconds."
},
"Domain" : "com.google.earlgrey.GREYUIThreadExecutorErrorDomain",
"Code" : "0",
"File Name" : "GREYUIThreadExecutor.m",
"Function Name" : "-[GREYUIThreadExecutor executeSyncWithTimeout:block:error:]",
"Line" : "235",
"TestCase Class" : "EarlGreyVidaTests.MyFirstEarlGreyTest",
"TestCase Method" : "testExample"
},
{
"Description" : "Failed to execute assertion within 30 seconds.",
"Domain" : "com.google.earlgrey.ElementInteractionErrorDomain",
"Code" : "4",
"File Name" : "GREYElementInteraction.m",
"Function Name" : "-[GREYElementInteraction assert:error:]",
"Line" : "418",
"TestCase Class" : "EarlGreyVidaTests.MyFirstEarlGreyTest",
"TestCase Method" : "testExample"
}
]
It works if I turn off synchronization:
GREYConfiguration.sharedInstance().setValue(false, forConfigKey: kGREYConfigKeySynchronizationEnabled)
Is there something I'm doing wrong? All my tests seem to work well with synchronization off. Should I keep it off?
You shouldn't turn the synchronization off - that's what makes EarlGrey EarlGrey, and makes your tests stable and useful.
However, it looks like you have some animations or delayed performSelector that EarlGrey is tracking to make it always think your app is busy. one thing you can tweak is, if you look at the header, GREYConfiguration.h, you can find various config variables you may change according to your app's behaviour.
Disclaimer: I am part of EarlGrey's team.
Related
My situation is the following:
I developed a game, where people can save their progress via google cloud. I'm releasing big content-updates, resulting in many people returning to my game at the same time, trying to get their savegame.
This overload causing my customers to get stucked in the savegame-loading process - not able to start playing with their progress.
Here's an updated 4 days screenshot of the cloud-api-dashboard
(And here's the old "12 hours" screenshot of the cloud-api-dashboard)
more informations about the Project:
The game keeps using the "save in cloud"-function in the background on some stages of the game to provide players with the functionality to play on two diffrent devices.
I'm using Unity 2019.3.9f1 and the Asset "Easy Mobile Pro 2.17.3" for the Game-Service-Feature.
The "Google Play Games Plugin" has the version "0.10.12" and can be found on github
more informations about the Cloud-Situation:
The OAuth "user type" is "External" (and can't be changed)
The OAuth user cap display shows "0/100" for the user-cap
And The OAuth rate limits is displaying this for the token-grant-rate (highest "Average Token Grant Rate" is 3,33 of 10.000 as limit)
All used quotas are within the limit. The project reaches
1/10 of "queries per day" (1.000.000.000 max) and
1/2 of "queries per 100 sec" (20.000 max).
more informations about the Error-Trace in the cloud-API:
On my search for a better Error-Log I tried to find “Cloud Logging”-tools in the “Google Cloud Platform”-console. But every section i tried won’t display anything:
“Logging” (Operations tool) is empty
“Cloud Logging API” says: “no data available for the selected time frame.”
“Cloud Debugger API” says: “no data available for the selected time frame.”
I can't find a more detailed variant of the errors as this (the "Metrics"-Section in the "Google Drive API"):
Is there anything I miss to get a better insight?
more informations about the Core-Code
As I mentioned, I’m using “EasyMobilePro”, so I have one “SaveGame”-Var and 8 calls for google and apple as well. I already contacted their support: They assured me that those calls are unchangeable & kind of rock solid (so it can’t be caused from their code) and I should try to contact google if the problem is not on my side.
The 5 calls from EasyMobile for cloudsave are:
bool “GameServices.IsInitialized()”
void “GameServices.OpenWithAutomaticConflictResolution”
void “GameServices.WriteSavedGameData”
void “GameServices.ReadSavedGameData”
void “GameServices.DeleteSavedGame”
The 3 calls from EasyMobile for cloud-login are:
void “GameServices.Init()”
delegate “GameServices.UserLoginSucceeded”
delegate “GameServices.UserLoginFailed”
The Process, that causes the Issue:
I call “GameService.Init()”, the user logs in (no problem)
On that “LoginSuccess”-Callback I call my Function “HandleFirstCloudOpening”:
//This Method is Called, after the player Pressed "Save/ Load" on the StartScreen
//The button is disabled imidiately (and will be re-enabled if an error/fail happens)
public void TryCallUserLogin() {
if (!IsLoginInit) {
EasyMobile.GameServices.UserLoginFailed += HandleLoginFail;
EasyMobile.GameServices.UserLoginSucceeded += HandleFirstCloudOpening;
IsLoginInit = true;
}
if (!IsGameServiceInitialized) {
EasyMobile.GameServices.Init();
} else { //This "else" is only be called, if the "Init" was successfull, but the player don't have a connected savegame
HandleFirstCloudOpening();
}
}
private void HandleLoginFail() {
//(...) Show ErrorPopup, let the player try to login again
}
private void HandleFirstCloudOpening() {
if (currentSaveState != CloudSaveState.NONE) {
CloudStateConflictDebug(CloudSaveState.OPENING);
return;
}
currentSaveState = CloudSaveState.OPENING;
EasyMobile.GameServices.SavedGames.OpenWithAutomaticConflictResolution(cloudSaveNameReference, UseFirstTimeOpenedSavedGame);
}
private void UseFirstTimeOpenedSavedGame(EasyMobile.SavedGame _savedGame, string _error) {
currentSaveState = CloudSaveState.NONE;
if (string.IsNullOrEmpty(_error)) {
cloudSaveGame = _savedGame;
ReadDataFromCloud(cloudSaveGame);
} else {
ErrorPopupWithCloseButton("cloud_open", "failed with error: " + _error);
}
}
private void ReadDataFromCloud(EasyMobile.SavedGame _savedGame) {
if (_savedGame.IsOpen) {
currentSaveState = CloudSaveState.LOADING;
EasyMobile.GameServices.SavedGames.ReadSavedGameData(_savedGame, UseSucessfullLoadedCloudSaveGame);
} else { //backup function if the fresh-opened savegame is "closed" for some reason (can happen later while "saving" ingame)
HandleFirstCloudOpening();
}
}
private void UseSucessfullLoadedCloudSaveGame(EasyMobile.SavedGame _game, byte[] _cloudData, string error) {
if (!string.IsNullOrEmpty(error)) {
ErrorPopupWithCloseButton("cloud_read", "Reading saved game data failed: " + error);
return;
}
if (_cloudData.Length > 0) {
//A function, that converts the saved bytes to my useable Savegame-Data
//having a "try&catch": if it fails, it useses the callback with the param "null"
SaveGameToByteConverter.LoadFromBytes<CoreSaveData>(_cloudData, UseSucessfullConvertedSavegameData);
} else {
//this will "fail", causing the use of the callback with the param "null"
SaveGameToByteConverter.LoadFromBytes<CoreSaveData>(null, UseSucessfullConvertedSavegameData);
}
}
private void UseSucessfullConvertedSavegameData(CoreSaveData _convertedSaveGame) {
//Has a Loaded & normal SaveGame in his cloud
if (_convertedSaveGame != null) {
//Loaded Save matches verify-conditions
if (CheckLoadedSaveIsVerified(_convertedSaveGame)) {
OverrideGameSaveDatawithLoaded(_convertedSaveGame);
ReloadCurrentScene();
return;
} else { //This happens if the cloud-save doesn't pass my verification-process
ErrorPopupWithCloseButton("cloud_loadedSave", "Couldn't find a compatible Savegame!");
return;
}
} else { //User uses Cloud-save for the frist Time or has an unusable savegame and gets a "new" (lost his old data)
TrySaveGameToCloud((bool _saved) => {
SaveAllGameFilesLocally();
});
}
}
I shrunk the code by removing most of my “if error happens, do XY”, since there are many and they would extend the reprex. If necessary I can provide a more detailed (but more complicated) code.
current conclusion
I can't find any issue on my side, that wouldn't have been fixed with a "restart of the game" or woudln't been covered by an error-popup for the user. It's like they are queued because of the amount of users and need to wait way too long for a response. Some users told us they had to wait & tried "x hours" (it's variable from 2h to 36h) and then they passed to play with their progress (so it worked). But some players mentioned they couldn't play again on the next day (same problem). Like their "access-token" only holds for a day?
Edit-History:
(1) updated the first dash-board-picture to match the ongoing situation
(1) added "more informations about the cloud-situation"
(1) can't find a more detailed error-log
(2) removed most pictures as displayables (kept the links)
(2) added "more informations about the Error-Trace in the cloud-API"
(2) added "more informations about the Core-Code" and a Reprex
(2) added "current conclusion"
I've used the go AWS sdk to create a cluster and added a job flow step to it.
However the execution of the step always fails when I do it programatically.
An interesting point to notice is that when I attach the jar from the UI, it successfully executes.
So when the jar is attached from the UI, this is the outcome of the step execution(it runs successfully and moves to the COMPLETED state):
(Copying the full text)
JAR location : command-runner.jar
Main class : None Arguments :
spark-submit --deploy-mode cluster --class Hello
s3://mdv-testing/Util-assembly-1.0.jar Action on failure: Continue
However, this is the output of the step when I try programatically:
Status :FAILED Reason : Main Class not found.
Log File : s3://mdv-testing/awsLogs/j-3RW9K14BS6GLO/steps/s-337M25MLV3BHT/stderr.gz
Details : Caused by: java.lang.ClassNotFoundException: scala.reflect.api.TypeCreator
JAR location : s3://mdv-testing/Util-assembly-1.0.jar Main class : None > Arguments : spark-submit "--class Hello"
Action on failure: Cancel and wait
I tried various combinations for the arguments and realised that the command-runner.jar was never present.
I accordingly made changes to the code and send the command-runner.jar as the argument now. This now reflects the same details as the step that executes successfully.
This is the revised output:
Status :FAILED Reason : Unknown Error.
Log File : s3://mdv-testing/awsLogs/j-3RW9K14BS6GLO/steps/s-3NI5ZO15VTWQK/
JAR location : command-runner.jar
Main class : None
Arguments : "spark-submit --deploy-mode cluster --class Hello
s3://mdv-testing/Util-assembly-1.0.jar
Action on failure: Cancel and wait
Go Code
package main
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/emr"
)
func main() {
sess := session.New(&aws.Config{Region: aws.String("us-east-1")})
svc := emr.New(sess)
params := &emr.AddJobFlowStepsInput{
JobFlowId: aws.String("j-3RW9K14BS6aaa"),
Steps: []*emr.StepConfig{
{
ActionOnFailure: aws.String("CANCEL_AND_WAIT"), //TERMINATE_CLUSTER"),
HadoopJarStep: &emr.HadoopJarStepConfig{
Args: []*string{
aws.String("spark-submit --deploy-mode cluster --class Hello s3://mdv-testing/Util-assembly-1.0.jar"),
},
Jar: aws.String("command-runner.jar"), },
Name: aws.String("ReportJarExecution"),
},
},
}
resp, err := svc.AddJobFlowSteps(params)
if err != nil {
// Print the error, cast err to awserr. sError to get the Code and
// Message from an error.
fmt.Println(err.Error())
return
}
// Pretty-print the response data.
fmt.Println(resp)
}
Can someone please help me !!! I think I'm pretty close to the solution but it is evading me big time :(
I managed to solve this issue.
For anyone who is struggling with something similar, the answer is that we need to send the arguments separately in an array.
I have an issue with my fix engine which I can't quite get to the bottom of.
I ran the following test:
I sent multiple requests to the fix server(for example-new order single), let's say 20 at a time.
Then when I receive the execution reports back, the Quickfix engine takes a long time to process them, it processes a few than halts/stops for a 150 ms or so and continues(so it takes about 1 ms per message, but with long pauses). I used a packet sniffer to check the network stream and it show no such delays, all messages arrive in 2-3 ms span.
I removed all my logic, and set the session setting on bare minimum to avoid any extra work, and memory allocations.
I ran this test many times, and it shows the same results each time.
I use the engine log file timestamps to read message time.
Heres the .cfg file
[DEFAULT]
ConnectionType=initiator
ReconnectInterval=2
FileStorePath=store
FileLogPath=Log
StartTime=06:00:00
EndTime=03:00:00
UseDataDictionary=N
ValidateLengthAndChecksum=N
ValidateFieldsOutOfOrder=N
ValidateFieldsHaveValues=N
ValidateUserDefinedFields=N
SocketTcpNoDelay=Y
DataDictionary=FixSpec/FIX44.xml
SocketConnectHost=x.x.x.x
SocketConnectPort=xxxxx
LogoutTimeout=5
ResetOnLogon=Y
UseMassCancel=N
UseMassStatus=N
ResetOnDisconnect=Y
HeartBtInt=30
[SESSION]
BeginString=FIX.4.4
SenderCompID=xxxxx
TargetCompID=xxx
here is my FromApp:
public void FromApp(Message message, SessionID sessionId)
{
try
{
Crack(message, sessionId);
}
catch (UnsupportedMessageType ex)
{
UnSupportedMessage?.Invoke(this, message);
}
}
And My ExecutionReport handler
public void OnMessage(ExecutionReport m, SessionID s)
{
}
I removed all logic from my Application to avoid unnecessary noise.
Example log output:
20160811-07:10:44.541 : 8=FIX.4.49=24135=856=xxxxx49=XXX34=452=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-355=AAPL54=138=159=540=244=50.00000017=8916296071=xxxxx22=248=202180515=USD20=039=0150=037=89162960860=20160811-07:10:44.57210=129
20160811-07:10:44.545 : 8=FIX.4.49=24135=856=xxxxx49=XXX34=552=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-455=AAPL54=138=159=540=244=50.00000017=8916296091=xxxxx22=248=202180515=USD20=039=0150=037=89162961060=20160811-07:10:44.57410=128
20160811-07:10:44.546 : 8=FIX.4.49=24135=856=xxxxx49=XXX34=652=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-555=AAPL54=138=159=540=244=50.00000017=8916296111=xxxxx22=248=202180515=USD20=039=0150=037=89162961260=20160811-07:10:44.57710=128
20160811-07:10:44.549 : 8=FIX.4.49=24135=856=xxxxx49=XXX34=752=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-655=AAPL54=138=159=540=244=50.00000017=8916296131=xxxxx22=248=202180515=USD20=039=0150=037=89162961460=20160811-07:10:44.58010=128
20160811-07:10:44.551 : 8=FIX.4.49=24135=856=xxxxx49=XXX34=852=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-755=AAPL54=138=159=540=244=50.00000017=8916296151=xxxxx22=248=202180515=USD20=039=0150=037=89162961660=20160811-07:10:44.58310=137
20160811-07:10:44.554 : 8=FIX.4.49=24135=856=xxxxx49=XXX34=952=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-855=AAPL54=138=159=540=244=50.00000017=8916296171=xxxxx22=248=202180515=USD20=039=0150=037=89162961860=20160811-07:10:44.58510=145
20160811-07:10:44.557 : 8=FIX.4.49=24235=856=xxxxx49=XXX34=1052=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-955=AAPL54=138=159=540=244=50.00000017=8916296191=xxxxx22=248=202180515=USD20=039=0150=037=89162962060=20160811-07:10:44.58810=185
20160811-07:10:44.560 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=1152=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-1055=AAPL54=138=159=540=244=50.00000017=8916296211=xxxxx22=248=202180515=USD20=039=0150=037=89162962260=20160811-07:10:44.59110=216
20160811-07:10:44.562 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=1252=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-1155=AAPL54=138=159=540=244=50.00000017=8916296231=xxxxx22=248=202180515=USD20=039=0150=037=89162962460=20160811-07:10:44.59410=225
20160811-07:10:44.565 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=1352=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-1255=AAPL54=138=159=540=244=50.00000017=8916296251=xxxxx22=248=202180515=USD20=039=0150=037=89162962660=20160811-07:10:44.59610=233
20160811-07:10:44.693 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=1452=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-1355=AAPL54=138=159=540=244=50.00000017=8916296271=xxxxx22=248=202180515=USD20=039=0150=037=89162962860=20160811-07:10:44.59910=242
20160811-07:10:44.693 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=1552=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-1455=AAPL54=138=159=540=244=50.00000017=8916296291=xxxxx22=248=202180515=USD20=039=0150=037=89162963060=20160811-07:10:44.60210=224
20160811-07:10:44.693 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=1652=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-1555=AAPL54=138=159=540=244=50.00000017=8916296311=xxxxx22=248=202180515=USD20=039=0150=037=89162963260=20160811-07:10:44.60510=224
20160811-07:10:44.699 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=1752=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-1655=AAPL54=138=159=540=244=50.00000017=8916296331=xxxxx22=248=202180515=USD20=039=0150=037=89162963460=20160811-07:10:44.60910=234
20160811-07:10:44.699 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=1852=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-1755=AAPL54=138=159=540=244=50.00000017=8916296351=xxxxx22=248=202180515=USD20=039=0150=037=89162963660=20160811-07:10:44.61310=235
20160811-07:10:44.699 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=1952=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-1855=AAPL54=138=159=540=244=50.00000017=8916296371=xxxxx22=248=202180515=USD20=039=0150=037=89162963860=20160811-07:10:44.61710=245
20160811-07:10:44.699 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=2052=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-1955=AAPL54=138=159=540=244=50.00000017=8916296391=xxxxx22=248=202180515=USD20=039=0150=037=89162964060=20160811-07:10:44.62110=228
20160811-07:10:44.699 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=2152=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-2055=AAPL54=138=159=540=244=50.00000017=8916296411=xxxxx22=248=202180515=USD20=039=0150=037=89162964260=20160811-07:10:44.71410=219
20160811-07:10:44.699 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=2252=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-2155=AAPL54=138=159=540=244=50.00000017=8916296431=xxxxx22=248=202180515=USD20=039=0150=037=89162964460=20160811-07:10:44.71610=227
20160811-07:10:44.700 : 8=FIX.4.49=24335=856=xxxxx49=XXX34=2352=20160811-07:10:4432=031=0.000000151=114=06=0.00000011=rA0Ny-2255=AAPL54=138=159=540=244=50.00000017=8916296451=xxxxx22=248=202180515=USD20=039=0150=037=89162964660=20160811-07:10:44.72010=228
Any ideas?
Is this normal behavior?
Where would you look for solutions?
Any thoughts on what is going on under the hood there?
I'm wondering why I get the following behaviour when running this script. I have the script loaded in PowerShell ISE (v4 host) and have the Pester module loaded. I run the script by pressing F5.
function Test-Pester {
throw("An error")
}
Describe "what happens when a function throws an error" {
Context "we test with Should Throw" {
It "Throws an error" {
{ Test-Pester } | Should Throw
}
}
Context "we test using a try-catch construct" {
$ErrorSeen = $false
try {
Test-Pester
}
catch {
$ErrorSeen = $true
}
It "is handled by try-catch" {
$ErrorSeen | Should Be $true
}
}
Context "we test using trap" {
trap {
$ErrorSeen = $true
}
$ErrorSeen = $false
Test-Pester
It "is handled by trap" {
$ErrorSeen | Should Be $true
}
}
}
I then get the following output:
Describing what happens when a function throws an error
Context we test with Should Throw
[+] Throws an error 536ms
Context we test using a try-catch construct
[+] is handled by try-catch 246ms
Context we test using trap
An error
At C:\Test-Pester.ps1:2 char:7
+ throw("An error")
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (An error:String) [], RuntimeException
+ FullyQualifiedErrorId : An error
[-] is handled by trap 702ms
Expected: {True}
But was: {False}
at line: 40 in C:\Test-Pester.ps1
40: $ErrorSeen | Should Be $true
Question
Why is the trap{} apparently not running in the final test?
Here are two solutions to the problem based on the comments/suggested answers from #PetSerAl and #Eris. I have also read and appreciated the answer given to this question:
Why are variable assignments within a Trap block not visible outside it?
Solution 1
Although variables set in the script can be read within the trap, whatever you do within the trap happens to a copy of that variable, i.e. only in the scope that is local to the trap. In this solution we evaluate a reference to $ErrorSeen so that when we set the value of the variable, we are actually setting the value of the variable that exists in the parent scope.
Adding a continue to the trap suppresses the ErrorRecord details, cleaning up the output of the test.
Describe "what happens when a function throws an error" {
Context "we test using trap" {
$ErrorSeen = $false
trap {
Write-Warning "Error trapped"
([Ref]$ErrorSeen).Value = $true
continue
}
Test-Pester
It "is handled by trap" {
$ErrorSeen | Should Be $true
}
}
}
Solution 2
Along the same lines as the first solution, the problem can be solved by explicitly setting the scope of the $ErrorSeen variable (1) when it is first created and (2) when used within the trap {}. I have used the Script scope here, but Global also seems to work.
Same principle applies here: we need to avoid the problem where changes to the variable within the trap only happen to a local copy of the variable.
Describe "what happens when a function throws an error" {
Context "we test using trap" {
$Script:ErrorSeen = $false
trap {
Write-Warning "Error trapped"
$Script:ErrorSeen = $true
continue
}
Test-Pester
It "is handled by trap" {
$ErrorSeen | Should Be $true
}
}
}
According to this blog, you need to tell your trap to do something to the control flow:
The [...] thing you notice is that when you run this as script, you will receive both your error message and the red PowerShell error message.
. 'C:\Scripts\test.ps1'
Something terrible happened!
Attempted to divide by zero.
At C:\Scripts\test.ps1:2 Char:3
+ 1/ <<<< null
This is because your Trap did not really handle the exception. To handle an exception, you need to add the "Continue" statement to your trap:
trap { 'Something terrible happened!'; continue }
1/$null
Now, the trap works as expected. It does whatever you specified in the trap script block, and PowerShell does not get to see the exception anymore. You no longer get the red error message.
I need to fix this problem. I have tests in protractor, but they fail because the commands execute before the page loads. I used sleep function to try to solve this problem, but this is not the better way and in some moments this fails too.
I tried the following global function, but in some moments the error "Element is not clickable at point (39, 109). Other element would receive the click:" is displayed to me, even the button has been clicked:
global.waitForElementToBeLoaded = function(locator, identifier){
var elementToFind = locator(identifier);
browser.wait(function(){
return browser.driver.isElementPresent(elementToFind).then(function(found){
return found;
});
}, 60000, "The test execution timed out waiting for " + elementToFind);
expect(browser.driver.isElementPresent(elementToFind)).toBeTruthy();
return browser.element(locator(identifier));
};
I'm confused with your code snippet. Shouldn't wait timeout and msg be inside browser.wait
browser.wait(function(){
return browser.driver.isElementPresent(elementToFind).then(function(found){
return found;
}, 60000, "The test execution timed out waiting for " + identifier);
Also sometimes just isElementPresent is not enough, you may need to couple it up with isDisplayed(), like below. Unfortunately there is no once size fits all condition for waits, sometimes you may want to wait for visibility of element, sometimes invisibility, click-ability etc. selenium-webdriver provides many useful methods as part of until object you can leverage them on case by case basis.
browser.wait(function(){
return browser.driver.isElementPresent(elementToFind).then(function(found){
if(found) {
return browser.driver.isDisplayed(elementToFind).then(function(displayed) {
return displayed;
}
}
return found;
}, 60000, "The test execution timed out waiting for " + identifier);
I've found this to be useful in those kind of situations where I need something to happen after the page loads.
browser.wait(protractor.until.titleIs("Some Page"), 10000,
"✗ Failed to wait for the page to load").then(function(){
// DO Stuff
});