Geb: Warn when a page takes longer than expected - Test Context in Page Object - wait

We want to add some type of functionality that when a page takes longer than x seconds to load a warning is presented. We don't want that to throw a WaitTimeoutException, because the test can still execute cleanly, just longer than desired. We would still use the default timeout to throw our WaitTimeoutException after 20 seconds. This implies that x is less than 20. It's essentially a performance check on the page itself.
I've tried using the onLoad function:
void onLoad(Page previousPage) {
double warnSeconds = 0.001
LocalDateTime warnTime = LocalDateTime.now().plusMillis((int)(warnSeconds * 1000))
boolean warned = false
boolean pageReady = false
while(!warned && !pageReady) {
if(LocalDateTime.now() > warnTime) {
log.warn("${this.class.simpleName} took longer than ${warnSeconds} seconds to load")
warned = true
}
pageReady = js.exec('return document.readyState') == 'complete'
}
}
However:
"Sets this browser's page to be the given page, which has already been
initialised with this browser instance."
Any help would be great. Thanks.
______________________________________EDIT_______________________________________
Instead of using my own timer, used javascript window.performance. Now I'm looking to be able to access a variable in my test from my pages.
______________________________________EDIT_______________________________________
void onLoad(Page previousPage) {
def performance
//TODO system property page time
def pageTime = 8000
if (browser.driver instanceof InternetExplorerDriver) {
performance = js.exec('return JSON.stringify(window.performance.toJSON());')
} else {
performance = js.exec('return window.performance || window.webkitPerformance || window.mozPerformance ' +
'|| window.msPerformance;')
}
int time = performance['timing']['loadEventEnd'] - performance['timing']['fetchStart']
if (time > pageTime) {
String errorMessage = "${this.class.simpleName} took longer than ${pageTime} milliseconds " +
"to load. Took ${time} milliseconds."
log.error(errorMessage)
//TODO Soft Assert
}
}
New chunk of code to actually get the correct performance data instead of using my own timer. Now where I have //TODO Soft Assert, I have an object in my test that I want to access from my Page Object, but have no context. How can I get context?

Related

Cannot get Realm result for objects filtered by the latest (nsdate) value of a property of a collection property swift (the example is clearer)

I Have the following model
class Process: Object {
#objc dynamic var processID:Int = 1
let steps = List<Step>()
}
class Step: Object {
#objc private dynamic var stepCode: Int = 0
#objc dynamic var stepDateUTC: Date? = nil
var stepType: ProcessStepType {
get {
return ProcessStepType(rawValue: stepCode) ?? .created
}
set {
stepCode = newValue.rawValue
}
}
}
enum ProcessStepType: Int { // to review - real value
case created = 0
case scheduled = 1
case processing = 2
case paused = 3
case finished = 4
}
A process can start, processing , paused , resume (to be in step processing again), pause , resume again,etc. the current step is the one with the latest stepDateUTC
I am trying to get all Processes, having for last step ,a step of stepType processing "processing ", ie. where for the last stepDate, stepCode is 2 .
I came with the following predicate... which doesn't work. Any idea of the right perform to perform such query ?
my best trial is the one. Is it possible to get to this result via one realm query .
let processes = realm.objects(Process.self).filter(NSPredicate(format: "ANY steps.stepCode = 2 AND NOT (ANY steps.stepCode = 4)")
let ongoingprocesses = processes.filter(){$0.steps.sorted(byKeyPath: "stepDateUTC", ascending: false).first!.stepType == .processing}
what I hoped would work
NSPredicate(format: "steps[LAST].stepCode = \(TicketStepType.processing.rawValue)")
I understand [LAST] is not supported by realm (as per the cheatsheet). but is there anyway around I could achieve my goal through a realm query?
There are a few ways to approach this and it doesn't appear the date property is relevant because lists are stored in sequential order (as long as they are not altered), so the last element in the List was added last.
This first piece of code will filter for processes where the last element is 'processing'. I coded this long-handed so the flow is more understandable.
let results = realm.objects(Process.self).filter { p in
let lastIndex = p.steps.count - 1
let step = p.steps[lastIndex]
let type = step.stepType
if type == .processing {
return true
}
return false
}
Note that Realm objects are lazily loaded - which means thousands of objects have a low memory impact. By filtering using Swift, the objects are filtered in memory so the impact is more significant.
The second piece of code is what I would suggest as it makes filtering much simpler, but would require a slight change to the Process model.
class Process: Object {
#objc dynamic var processID:Int = 1
let stepHistory = List<Step>() //RENAMED: the history of the steps
#objc dynamic var name = ""
//ADDED: new property tracks current step
#objc dynamic var current_step = ProcessStepType.created.index
}
My thought here is that the Process model keeps a 'history' of steps that have occurred so far, and then what the current_step is.
I also modified the ProcessStepType enum to make it more filterable friendly.
enum ProcessStepType: Int { // to review - real value
case created = 0
case scheduled = 1
case processing = 2
case paused = 3
case finished = 4
//this is used when filtering
var index: Int {
switch self {
case .created:
return 0
case .scheduled:
return 1
case .processing:
return 2
case .paused:
return 3
case .finished:
return 4
}
}
}
Then to return all processes where the last step in the list is 'processing' here's the filter
let results2 = realm.objects(Process.self).filter("current_step == %#", ProcessStepType.processing.index)
The final thought is to add some code to the Process model so when a step is added to the list, the current_step var is also updated. Coding that is left to the OP.

Access last value from a SignalProducer when terminated

I have a signal producer, when it's terminated I would like to know if a value was sent, I only need the last one, seems so simple ...
let myProducer: SignalProducer<MyObject, MyError> = getMyProducer()
myProducer.on(terminated: {
// I need the last value here
// Or I need to know if value was never called
}).start()
I've tried to store the value in a local var :
let myProducer: SignalProducer<MyObject, MyError> = getMyProducer()
var myValue: MyObject?
myProducer.on(value: { value in
myValue = value
}, terminated: {
guard let value = myValue else {
// value was never called
return
}
// value was called
}).start()
But sometimes terminated is called while value has been called but myValue is still nil...
First, are you really sure that you want the terminated event?
Under normal conditions, an event stream ends with a completed event. Exceptions are failed when a failure has occurred and interrupted, when the observation was ended before the stream could complete normally (E.g. cancellation).
Second: Can your SignalProducer fail, and in the failure case, do you still want the last value sent before the failure?
If not, its as easy as using the take(last:) operator:
enum MyError: Error {
case testError
}
let (signal, input) = Signal<Int, MyError>.pipe()
let observer = Signal<Int, MyError>.Observer(
value: { print("value: \($0)") },
failed: { print("error: \($0)") },
completed: { print("completed") },
interrupted: { print("interrupted") }
)
signal
.take(last: 1)
.observe(observer)
input.send(value: 1) // Nothing printed
input.send(value: 2) // Nothing printed
input.send(value: 3) // Nothing printed
input.sendCompleted() // value 3 printed
I'm using a Signal here so I can manually send events to it just for demonstration, the same works for SignalProducer as well.
Note: If we send interrupted or a failed event, the last value 3 will not be sent because those to terminating events short circuit the normal flow.
If your SignalProducer can fail, and you still want to get the last value before the failure, you can use flatMapError to ignore the Error before the last operator:
signal
.flatMapError { _ in
return .empty
}
.take(last: 1)
.observe(observer)
my answer :
producer
.flatMapError { _ in SignalProducer<Value, NoError>.empty }
.collect()
startWithResult( { result in
case let .success(results):
done(with: results.last)
case let .failure(error):
() // should not happen as errors are flatmapped
})

Robot Framework: Timed out waiting for page load

We have run our Robot Framework environment nearly one year without any problems, but now we get the error message:
TimeoutException: Message: Timed out waiting for page load.
Stacktrace:
at Utils.initWebLoadingListener/< (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver#googlecode.com/components/driver-component.js:9089)
at WebLoadingListener/e (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver#googlecode.com/components/driver-component.js:5145)
at WebLoadingListener/< (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver#googlecode.com/components/driver-component.js:5153)
at fxdriver.Timer.prototype.setTimeout/<.notify (file:///tmp/tmp77bOby/webdriver-py-profilecopy/extensions/fxdriver#googlecode.com/components/driver-component.js:625)
What could be problem? I checked the disk space and there are disk space left.
A timeout error can have a laundry list of possible issues. Loading a page after a year of smooth operation narrows it down a little, but there are still many possibilities. Connection speeds sometimes change, sometimes the page you're loading up has added features that cause it to take longer to load or was just written poorly so it loads slowly... you get the idea. Without the code of the page or your code to look at, I can only suggest two fixes.
First, in the code of Selenium2Library, there is a timeout variable somewhere that can be set with Set Selenium Timeout. The default is 5 seconds, but if your page is taking longer to load, then increasing it might solve your problem. This assumes that your page loads at a reasonable rate in manual testing and that opening it is the least of your concerns.
Second, it's possible that you're testing an AngularJS application, not a normal website. If that's true, then you're going to want to use ExtendedSelenium2Library, not Selenium2Library. ExtendedSelenium2Library is better-equipped to deal with AngularJS applications and includes code to wait for Angular applications to load.
The old webdriver.xpi is buggy about page load handling. Timers are not correctly canceled, resulting in random windows switches and memory leaks. I copy here some replacement code that may be useful to anybody.
var WebLoadingListener = function(a, b, c, d) {
if ("none" == Utils.getPageLoadStrategy()) {
b(!1, !0);
} else {
this.logger = fxdriver.logging.getLogger("fxdriver.WebLoadingListener");
this.loadingListenerTimer = new fxdriver.Timer;
this.browser = a;
var self = this;
var e = function(a, c) {
self.destroy ();
b(a, c);
};
this.handler = buildHandler(a, e, d);
a.addProgressListener(this.handler);
-1 == c && (c = 18E5);
this.loadingListenerTimer.setTimeout(function() {
e(!0);
}, c);
WebLoadingListener.listeners [this.handler] = this;
goog.log.warning(this.logger, "WebLoadingListener created [" + Object.keys (WebLoadingListener.listeners).length + "] " + d.document.location);
}
};
WebLoadingListener.listeners = {};
WebLoadingListener.removeListener = function(a, b) {
if (b.constructor !== WebLoadingListener) {
b = WebLoadingListener.listeners [b];
}
b.destroy ();
};
WebLoadingListener.prototype.destroy = function() {
if (this.browser) {
this.loadingListenerTimer.cancel();
this.browser.removeProgressListener && this.handler && this.browser.removeProgressListener(this.handler);
delete WebLoadingListener.listeners [this.handler]
this.loadingListenerTimer = undefined;
this.browser = undefined;
goog.log.warning(this.logger, "WebLoadingListener destroyed [" + Object.keys (WebLoadingListener.listeners).length + "]");
}
};
enter code here

IIS performance improve

Currently:
I have a ASP NET project, which utilises several ASHX.
it runs barely acceptable with daily 50000 login api calls(and each login comes diff amount of other API calls)
but now it takes >1min with daily 150,000 login api calls.
to t/shoot the problem, these thing I done on 1 of the API with sproc call which only retrieve data:
1) I run it in another brand new instance, in local-machine, it runs less than 100milisec; current web-instance runs > 1min
2) I run the sproc alone in SSMS, it take < 1sec; current web-instance runs > 1min
3) I did local parameter assignment on that particular sproc, to prevent parameter sniffing and re-built and re-exec, same result.
4) the part the serialize the Json(newtonsoft) uses static, also very fast, less than 1 sec.
I ran "http://tools.pingdom.com/fpt/" and indeed very slow; but I am not sure why it's slow.
I tried to use "DebugView" ("https://technet.microsoft.com/en-us/library/bb896647.aspx"), since it can write plenty log without file-locking, but not sure how to put it works for web application.
Anyway/ tool to capture the independent begin_request & end_request time externally and accurately? (I tried to put the time span in Global.asax, but get some null parameters sometimes) Best if anyone has the idea to pinpoint the part that caused it.
sample timespan test:
private string single_detail(HttpContext context)
{
PlayDetailApiResult o = new PlayDetailApiResult
{
...
};
string json = generateJsonFromObj(o); // init default
try
{
{
{
long current = 0;
DateTime dtStart = DateTime.Now;
// call sp
int ret = plmainsql.getPracticeQualificationTimeLeft(...);
DateTime dtEnd = DateTime.Now;
TimeSpan ts = dtEnd - dtStart;
LoggingHelper.GetInstance().Debug("single_detail getPracticeQualificationTimeLeft's duration(ms): " + ts.TotalMilliseconds);
if (ret != 0)
{
o.Code = ...;
}
}
DateTime dtStart_1 = DateTime.Now;
json = generateJsonFromObj(o);
DateTime dtEnd_1 = DateTime.Now;
TimeSpan ts_1 = dtEnd_1 - dtStart_1;
LoggingHelper.GetInstance().Debug("single_detail generateJsonFromObj's duration(ms): " + ts_1.TotalMilliseconds);
}
}
catch (Exception ex)
{
LoggingHelper.GetInstance().Debug("single_detail : " + ex.Message + "|" + ex.StackTrace);
}
finally
{
}
return json;
}
most of the result:
2015-03-04 18:45:29,263 [163] DEBUG LoggingHelper single_detail getPracticeQualificationTimeLeft's duration(ms): 5.8594
2015-03-04 18:45:29,264 [163] DEBUG LoggingHelper single_detail generateJsonFromObj's duration(ms): 0
these thing I noted.
1) computer's processor usage and memory usage: memory is at 70%, which i think still is not peak
2) check if Gzip compression is enabled : my json runs on mobile (iOS/Android/WM); some code changes needed, and not tested to prevent any compress-decompress issue; as compression also increase CPU usage at the same time
You can also try miniprofiler. It is very easy to use and displays the execution time for every step or function you want to monitor.
Check out http://miniprofiler.com/

Capturing Cmd-C (or Ctrl-C) keyboard event from modular Flex application in browser or AIR

It seems that it is impossible to capture the keyboard event normally used for copy when running a Flex application in the browser or as an AIR app, presumably because the browser or OS is intercepting it first.
Is there a way to tell the browser or OS to let the event through?
For example, on an AdvancedDataGrid I have set the keyUp event to handleCaseListKeyUp(event), which calls the following function:
private function handleCaseListKeyUp(event:KeyboardEvent):void
{
var char:String = String.fromCharCode(event.charCode).toUpperCase();
if (event.ctrlKey && char == "C")
{
trace("Ctrl-C");
copyCasesToClipboard();
return;
}
if (!event.ctrlKey && char == "C")
{
trace("C");
copyCasesToClipboard();
return;
}
// Didn't match event to capture, just drop out.
trace("charCode: " + event.charCode);
trace("char: " + char);
trace("keyCode: " + event.keyCode);
trace("ctrlKey: " + event.ctrlKey);
trace("altKey: " + event.altKey);
trace("shiftKey: " + event.shiftKey);
}
When run, I can never get the release of the "C" key while also pressing the command key (which shows up as KeyboardEvent.ctrlKey). I get the following trace results:
charCode: 0
char:
keyCode: 17
ctrlKey: false
altKey: false
shiftKey: false
As you can see, the only event I can capture is the release of the command key, the release of the "C" key while holding the command key isn't even sent.
Has anyone successfully implemented standard copy and paste keyboard handling?
Am I destined to just use the "C" key on it's own (as shown in the code example) or make a copy button available?
Or do I need to create the listener manually at a higher level and pass the event down into my modular application's guts?
I did a test where I listened for key up events on the stage and noticed that (on my Mac) I could capture control-c, control-v, etc. just fine, but anything involving command (the  key) wasn't captured until I released the command key, and then ctrlKey was false (even though the docs says that ctrlKey should be true for the command key on the Mac), and the charCode was 0. Pretty useless, in short.
Another incredibly annoying thing that I just realized is that ctrl-c can't be captured by event.ctrlKey && event.keyCode = Keyboard.C (or ...event.charCode == 67), instead you have to test for charCode or keyCode being 3. It kind of makes sense for charCode since ctrl-c is 3 in the ASCII table, but it doesn't make sense for keyCode, which is supposed to represent the key on the keyboard, not the typed character. The same goes for all other key combos (because every ctrl combo has an ASCII equivalent).
Edit Found a bug in the Flex bug system about this: https://bugs.adobe.com/jira/browse/FP-375
I've found one workaround to this one based on the capture sequence. When you press Cmd+A, for example, the sequence is:
type: KEY_DOWN, keyCode 15
type: KEY_UP, keyCode 15
type: KEY_DOWN, keyCode 65
So everytime you get keyCode 15 down and then up and the next capture is down you can assume that the user pressed the key combination. My implementation end up like this:
protected var lastKeys:Array;
this.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyHandler, false, 0, true);
this.stage.addEventListener(KeyboardEvent.KEY_UP, keyHandler, false, 0, true);
private function getCmdKey(ev:KeyboardEvent):Boolean {
this.lastKeys.push(ev);
this.lastKeys = this.lastKeys.splice(Math.max(0, this.lastKeys.length-3), 3);
if (this.lastKeys.length < 3) return false;
if (ev.keyCode != 15 && ev.type == KeyboardEvent.KEY_UP) {
var firstKey:KeyboardEvent = this.lastKeys[0] as KeyboardEvent;
var secondKey:KeyboardEvent = this.lastKeys[1] as KeyboardEvent;
if (firstKey.keyCode == 15 && firstKey.type == KeyboardEvent.KEY_DOWN &&
secondKey.keyCode == 15 && secondKey.type == KeyboardEvent.KEY_UP) {
return true;
}
}
return false;
}
private function keyHandler(ev:KeyboardEvent):void {
var cmdKey:Boolean = this.getCmdKey(ev.clone() as KeyboardEvent);
var ctrlKey:Boolean = ev.ctrlKey || cmdKey;
if (ctrlKey) {
if (ev.keyCode == 65) {
// ctrl + "a"-- select all!
}
}
}
For me, the following works:
private var _ctrlHoldFlag:Boolean = false;
// Do something if CTRL was held down and C was pressed
// Otherwise release the ctrl flag if it was pressed
public function onKey_Up(event:KeyboardEvent):void {
var keycode_c:uint = 67;
if (_ctrlHoldFlag && event.keyCode == keycode_c)
{
//do whatever you need on CTRL-C
}
if (event.ctrlKey)
{
_ctrlHoldFlag = false;
}
}
// Track ctrl key down press
public function onKey_Down(event:KeyboardEvent):void
{
if (event.ctrlKey)
{
_ctrlHoldFlag = true;
}
}

Resources