I need to validate that one of the elements I am searching for appears on the page.
if one of them appears the expect statement should evaluate to true.
I have pressed f12 and validated that the 'downloadReferencesRow' along with one of the other elements is appearing. but cypress it timing out.
Does my code look ok?
var numberOfElements = 0;
cy.get('downloadReferencesRow').then((body) =>{
if (body.find('createApplicationReferencesPresent').length > 0) {
numberOfElements +=1;
}
if (body.find('createApplicationNoReferencesPresent').length > 0) {
numberOfElements +=1;
}
});
expect(numberOfElements).eq(1);
The code has mixed synchronous and asynchronous commands, which is problematic.
You can more easily do it with jQuery multiple selectors
cy.get('createApplicationReferencesPresent,createApplicationNoReferencesPresent')
.then($els => {
const numberOfElements = $els.length // 1 or 2 - fails if neither present
})
Like all conditional testing, it only works if the page is stable.
Related
I want to setup kendoNumericTextBox to allow user input any integer number and set step to 1000. But when user enters any value and use spinner, it should update to next multiple of step.
For example:
enter 123, press spin up, value will be 1000
enter 1234, press spin up, value vill be 2000
Is it possible or only way is to handle spin event and modify value from there?
UPDATE:
Ok, guys, thnx for help.
I have this spin handler now and it seems to be working as expected.
function onSpin(e)
{
var currentvalue = kendo.parseInt(this.value());
if (currentvalue > 0)
{
this.value(Math.floor(currentvalue / this.step()) * this.step());
}
if (currentvalue < 0)
{
this.value(Math.ceil(currentvalue / this.step()) * this.step());
}
}
I have provided a dojo below with a potential solution for you:
https://dojo.telerik.com/UQohUjaP/2
I have created a function that will work on the spin and on change value so that it will step the value up/down on the value that you set e.g. 1000
the function is fairly simple and for brevity I have taken out the log statements here:
function onChange() {
var currentvalue = kendo.parseInt(this.value());
if (currentvalue > 0) {
currentvalue = Math.ceil(currentvalue / this.step()) * this.step();
} else if (currentvalue < 0) {
currentvalue = Math.floor(currentvalue / this.step()) * this.step();
} else {
currentvalue = 0;
}
this.value(currentvalue);
}
Unfortunately there doesn't seem to be a simple way of figuring out if the value has gone up or down so I am basically checking to see if the value is greater than 1 or less than 1 and then calculating the ceiling or the floor for the value and then stepping it in the right direction. in order to cater for zero we have a special condition which just sets the value to 0 assuming that is a valid value in your scenario
As you say, it's possible by listening to the spin event:
$("#numerictextbox").kendoNumericTextBox({
min: 0,
spin: function(e) {
var isUp = e.sender._key === 38,
isDown = e.sender._key === 40;
var m = Math.trunc(this.value()/1000),
value = isUp ? m + 1 : m;
this.value(value * 1000);
}
});
I doubt there's something out of the box, because your needs seem somewhat unusual.
I have just tried Optimizely. The problem is it will show different variations to a user. Sometimes we don't expect this behaviour. For example if I change color to red from blue, Optimizely will randomly select between the orginal (blue) and the variation (red) for the same user which is inconsistent. How can I make Optimizely to always show the same variation to a user?
Place the following code in your Experiment JavaScript:
setCookie = function (c_name,value,exdays) {
var exdate=new Date();
exdate.setDate(exdate.getDate() + exdays);
var expires = exdate.toUTCString();
var isIE8 = (document.documentMode !== undefined);
if (exdays == 0) {
expires = (isIE8 == true) ? "" : "0";
}
var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+expires);
document.cookie=c_name + "=" + c_value;
}
Within each variant (e.g. Blue Variant, Red Variant, etc.), call setCookie and check whether the cookie exists for a user in that particular variant. If the cookie does exist, then run whatever code you want that particular variant to run. Below is an example of setting a cookie called tester that will expire after 30 days.
setCookie('tester',true,30);
if(document.cookie.indexOf('tester')>-1){
//RUN YOUR CODE HERE IF THIS VISITOR HAS THIS COOKIE
}
Hi there I am an engineer at Optimizely,
You could alternatively try the Fullstack product, which is more developer-oriented. With this you get an SDK that you install with your bundle and you implement your testing logic using code.
Example:
npm install optimizely-client-sdk
const optimizely = require('optimizely-client-sdk');
const optimizelyClient = optimizely.createInstance({
datafile: {} // this is your experiment config which you get from the Optimizely UI
});
const variation = optimizelyClient.activate('color_experiment', 'user_1');
if (variation === 'blue') {
// do something for blue
} else if (variation === 'red') {
// do something for red
} else {
// default case
}
And as long as you pass in the exact same user_id as the second argument to activate, you are guaranteed to always get the same variation for that user.
For more information or details on getting started please take a look at: https://developers.optimizely.com/x/solutions/sdks/getting-started/index.html?language=javascript
Also keep in mind that Optimizely gets blocked by adblockers, it can happen if a user turns their adblocker on after they've been on the page and served up an experiment to see - they would get the original version.
In RxJS version 2.2.26
The following code produced a stream that would emit the number of clicks (double click, triple click etc..)
var multiClickStream = clickStream
.buffer(function() { return clickStream.throttle(250); })
.map(function(list) { return list.length; })
.filter(function(x) { return x >= 2; });
In RxJS version 4.0.6
This code no longer produces the desired result.
How can I get that same functionality in RxJS 4.0.6?
Working 2.2.26 Example
Broken 4.0.6 Example
There is actually a much better way to find double clicks via RxJs:
var mouseDowns = Rx.Observable.fromEvent(button, "mousedown");
var doubleClicks = mouseDowns.timeInterval()
.scan<number>((acc, val) => val.interval < 250 ? acc + 1 : 0, 0)
.filter(val => val == 1);
The benefit of this is that you don't need to wait for the full 250ms to recognize the double click - if the user has only 120ms between clicks there is a noticable delay between the double click and the resulting action.
Notice, that through counting up (with .scan()) and filtering to the first count we can limit our stream to just double-clicks and ignore every fast click after that - so click click click will not result in two double clicks.
Just in case someone is wondering on how to do the same thing with RxJS 5 (5.0.0-beta.10), this is how I got it working:
const single$ = Rx.Observable.fromEvent(button, 'click');
single$
.bufferWhen(() => single$.debounceTime(250))
.map(list => list.length)
.filter(length => length >= 2)
.subscribe(totalClicks => {
console.log(`multi clicks total: ${totalClicks}`);
});
I spent a lot of time trying to figure this out as I'm also learning Reactive Programming (with RxJS) so, if you see a problem with this implementation or know of a better way to do the same thing, I'll be very glad to know!
Detect single or double-clicks, but not multi-clicks
Here's a solution I came up with that creates a stream of single or double clicks (not anything more, so no triple clicks). The purpose is to detect multiple double clicks in quick succession, but also to receive notifications of single clicks.
let click$ = Observable.fromEvent(theElement, "click");
let trigger$ = click$.exhaustMap(r =>
click$.merge(Observable.timer(250)).take(1));
let multiclick$ = click$.buffer(trigger$).map(r => r.length);
The reasoning is this, we use the buffer operator to group clicks, and design a buffer trigger event as follows: Every time a click happens, we start a race between two observables:
A 250 msec timer
The original click stream
Once this race concludes (we use take(1) because we are only interested in the first event) we emit the buffer trigger event. What does this do? It makes the buffering stop either when a 2nd click arrives, or when 250 msec have elapsed.
We use the exhaustMap operator to suppress the creation of another race while one is already going on. This would otherwise occur for the 2nd click in a double-click pair.
Here's another take (produces N doubleclicks if the user quickly clicks 2*N times):
const clicks = fromEvent(document, 'click');
const doubleclicks = clicks.pipe(
exhaustMap(() => clicks.pipe(takeUntil(interval(250)))),
);
This answer is inspired by #Aviad P.
I believe the following code is the right answer. It meets all these requirements.
It differentiates single-click, double-click, and triple-click.
No unrecognized clicks will be streamed. i.e. If you click the mouse 6 times quickly, you will get 2 triple-clicks. If you click 5 times, you get one triple-click and one double-click. etc
triple-click will be fired immediately, no need to wait for the whole time-window complete.
No clicks will be lost.
It's easy to make it accept four-click, five-click...
const btn = document.querySelector('#btn');
const click$ = Rx.Observable.fromEvent(btn, "click");
const trigger$ =
click$.exhaustMap(r =>
click$
.take(2)
.last()
.race(click$
.startWith(0)
.debounceTime(500)
.take(1))
);
click$
.buffer(trigger$)
.map(l => l.length)
.map(x => ({
1: 'single',
2: 'double',
3: 'tripple'
}[x]))
.map(c => c + '-click')
.subscribe(log);
Rx.Observable.fromEvent(document.querySelector('#reset'), 'click')
.subscribe(clearLog);
function log(message) {
document.querySelector('.log-content').innerHTML += ('<div>' + message + '</div>');
}
function clearLog() {
document.querySelector('.log-content').innerHTML = null;
}
.log {
padding: 1rem;
background-color: lightgrey;
margin: 0.5rem 0;
}
.log-content {
border-top: 1px solid grey;
margin-top: 0.5rem;
min-height: 2rem;
}
.log-header {
display: flex;
justify-content: space-between;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.7/Rx.js"></script>
<button id='btn'>Click Me</button>
<button type="button" id='reset'> Reset </button>
<div class='log' id='logpanel'>
<div class='log-header'>
Log:
</div>
<div class="log-content"></div>
</div>
A more generic solution: starting from a source observable, detect and propagate when this observable quickly emits the exact same value (at least) twice quickly in a row:
var scheduler = Rx.Scheduler.default; // replace with TestScheduler for unit tests
var events = // some observable
var doubleClickedEvents = events
/* Collect the current and previous value */
.startWith(null) // startWith null is necessary if the double click happens immediately
.pairwise()
.map(pair => ({ previous: pair[0], current: pair[1] })
/* Time the interval between selections. */
.timeInterval(scheduler)
/* Only accept two events when they happen within 500ms */
.filter(timedPair => timedPair.interval < 500)
.map(timedPair => timedPair.value)
/* Only accept two events when they contain the same value */
.filter(pair => pair.previous && pair.previous === pair.current)
.map(pair => pair.current)
/* Throttle output. This way, triple and quadruple clicks are filtered out */
.throttle(500, scheduler)
The difference with the provided solutions is:
Like Wolfgang's solution, this observable will immediately emit the value at the exact moment a 'double click' happens, not after a debounce time of 500ms
Does not needlessly accumulate the amount of clicks. If you ever need to implement 'Triple-click' behavior, then Wolfgang's solution is better. But for double click behavior, this can be replaced with startWith(null).pairwise()
Uses throttle to hold back multiple double clicks.
Actually propagates the values that are emitted from the original events, not just a 'signal'.
throttle was changed to debounce starting in RxJS 3 I believe.
There was a big debate about this way back when because the original naming scheme didn't actually match with other implementations of Rx or the actual definition.
https://github.com/Reactive-Extensions/RxJS/issues/284
And it even managed to confuse people further down the road in the reimplementation of RxJS 5:
https://github.com/ReactiveX/rxjs/issues/480
Found a way fit better to distinguish between single / double click. (So I can get either Single-Click or Double-Click, but not both)
For double click, this handled fast double click 2*N times produce N events:
Observable.prototype.doubleEvent = function(timing = 150, count = 2, evt = this) { /// flexibility to handle multiple events > 2
return this.exhaustMap( () => /// take over tapping event,
evt.takeUntil( Observable.timer(timing) ) /// until time up,
.take(count-1) /// or until matching count.
);
}
Note: argument evt = this make doubleEvent works with startWith(), to take this Observable correctly.
Usage:
this.onTap
.doubleEvent()
.subscribe( (result) => console.log('double click!') );
For distinguish between single / double click:
Observable.prototype.singleEvent = function(timing = 150) {
return this.mergeMap( /// parallel all single click event
() => Observable.timer(timing) /// fire event when time up
);
}
Observable.prototype.singleOrDoubleEvent = function(timing = 150) {
return this.exhaustMap( (e) => /// take over tapping event
Observable.race( /// wait until single or double event raise
this.startWith(e).doubleEvent(timing, 2, this)
.take(1).mapTo(1),
this.startWith(e).singleEvent(timing)
.take(1).mapTo(0),
)
);
}
Usage:
this.onTap
.singleOrDoubleEvent()
.subscribe( (result) => console.log('click result: ', result===1 ? 'double click' : 'single click') );
I'm working with along with an online tutorial and trying to understand the code below. What I don't get is why this works more than two times. When the loop has been executed two times i == len and the condition i < len isn't true anymore. So how come it's possible to toggle the different clases more than two times?
My guess is that when the condition is false i gets set to 0 again, did I understand that correctly? Hope someone can help me, I didn't find an explanation of this particular problem anywhere online.
HTML
<button>Normal</button>
<button>Changed</button>
CSS
.normal {background-color: white;color:black;}
.changed {background-color: black;color:white;}
JavaScript
(function() {
var buttons = document.getElementsByTagName("button");
for (var i = 0, len = buttons.length; i < len; i +=1)
buttons[i].onclick = function() {
var className = this.innerHTML.toLowerCase();
document.body.className = className;
}}
}());
The for loop gets excecuted only once and iterates through all buttons.
In the for loops body, you define an onclick function for each button.
So, before you can click anywhere the loop already has finished, and added an onclick function to each single button, which will be called everytime, you click on that button.
With button[i].onclick = function() {...} you add an event handler function to the buttons click event.
You should read more about event handlers in general.
Based on the issue in this question (ajaxStop was firing twice), I wrote the following ajaxStop event.
var ajaxCount = 0;
$(document).ajaxStop(function () {
ajaxCount += 1;
console.debug('calling ajaxStop, iteration ' + ajaxCount);
if (ajaxCount == 2) {
$('.fieldLoading').hide();
$('.fieldValue').show();
}
});
9 times out of 10 it works exactly as expected. The debug console shows "calling ajaxStop, iteration 1" as soon as the page loads. Then, after everything else fires, it shows "calling ajaxStop, iteration 2". This is what I expect. However, about 5 or 10 percent of the time it only displays iteration 1, after everything has fired (which means no data is shown).
I suggest adding an ajaxSend() handler to count the number of ajax requests and converting the ajaxStop() to an ajaxComplete(). Rather than performing:
if (ajaxCount == 2)
You can then do:
if (ajaxStopCount == ajaxStartCount)
Additionally, you could modify your counters to count ACTIVE requests (decrement the counter on ajaxComplete, increment it on ajaxSend (your loading dialog might disappear between requests, but will re-appear as soon as another request begins; I wouldn't image much of a delay between hiding/showing, but that depends on your code organization).
Add another handler for errors, and you should be set.
I ended up using a queue like so:
var ajaxQueue = $({});
$.ajaxQueue = function (ajaxOpts) {
// Hold the original complete function.
var oldComplete = ajaxOpts.complete;
// Queue our ajax request.
ajaxQueue.queue(function (next) {
// Create a complete callback to fire the next event in the queue.
ajaxOpts.complete = function () {
// Fire the original complete if it was there.
if (oldComplete) {
oldComplete.apply(this, arguments);
}
// Run the next query in the queue.
next();
};
// Run the query.
$.ajax(ajaxOpts);
});
};
Now I just call all my ajax events as ajaxQueue() instead of ajax(). Then, I have a $(document).ajaxStop() that I use to finish everything up.