How to use RxJS 5 buffer function? - rxjs5

I googled a lot, tried to look at d.ts file but still cannot understand what is wrong. Cannot find example of RxJs5 how to use this function.
var source = Observable.fromEvent(document.body, 'keypress');
var delayedSource = source.delay(1000);
var obs = source
.buffer(() => {
return delayedSource;
})
.map((clickBuffer) => {
return clickBuffer.length;
});
I am getting error:
Error:(166, 15) TS2345: Argument of type '() => Observable<{}>' is not assignable to parameter of type 'Observable'.
Property '_isScalar' is missing in type '() => Observable<{}>'.
buffer.d.ts looks this, I guess I should understand from this, but I can't.
import { Observable } from '../Observable';
/**
* Buffers the incoming observable values until the passed `closingNotifier`
* emits a value, at which point it emits the buffer on the returned observable
* and starts a new buffer internally, awaiting the next time `closingNotifier`
* emits.
*
* <img src="./img/buffer.png" width="100%">
*
* #param {Observable<any>} closingNotifier an Observable that signals the
* buffer to be emitted} from the returned observable.
* #returns {Observable<T[]>} an Observable of buffers, which are arrays of
* values.
*/
export declare function buffer<T>(closingNotifier: Observable<any>): Observable<T[]>;
export interface BufferSignature<T> {
(closingNotifier: Observable<any>): Observable<T[]>;
}
This question came from this:
Counting keypresses per second with angular 2 Rxjs

Based on Benjamin Gruenbaum comment, this solves the problem:
var source = Observable.fromEvent(document.body, 'keypress');
var delayedSource = source.delay(1000);
var obs = source
.buffer(delayedSource)
.map((clickBuffer) => {
return clickBuffer.length;
})

Related

Cypress should not.exist or not.be.visible

Because of - imo - poor page design, I've found myself having problems verify the visibility or non-existance of one or more elements on a page.
The problem is that some of the elements does not exist, while some of them have CSS property display:none. But the existing test code checks for not.exist, which makes the test fail. But I cannot change to not.be.visible, since then it will fail on the other elements.
So: Is it possible to do an OR in an assertion? Somthing like
cy.get('blabla').should('not.be.visible').or.cy.get('blabla').should('not.exist');
The above line compiles, but yields an undefined on the second part, so it doesn't work.
Here's the code:
(I don't consider the code architecture important - the question is basically the OR thing.)
page.sjekkAtDellaanFelterVises(2, 2, [
DellaanFelter.formaal,
DellaanFelter.opprinneligLaanebelop,
DellaanFelter.utbetalingsdato,
DellaanFelter.restlaanInnfridd,
]);
public sjekkAtDellaanFelterVisesALT(sakRad: number, delLanRad: number, felter: DellaanFelter[]) {
this.sjekkFelter(felter, DellaanFelter, (felt: string) => this.delLanAccordionBody(sakRad, delLanRad).get(this.e2e(felt)));
}
#ts-ignore
public sjekkFelterALT<T, E extends Node = HTMLElement>(felter: T[], enumType, lookupFn: (felt: string) => Chainable<JQuery<E>>) {
this.valuesOfEnum(enumType).forEach(felt => {
this.sjekkFelt(felt, felter, enumType, lookupFn);
});
}
// #ts-ignore enumType fungerer fint i praksis ...
public sjekkFeltALT<T, E extends Node = HTMLElement>(felt: string, felter: T[], enumType, lookupFn: (felt: string) => Chainable<JQuery<E>>) {
if (felter.some(feltSomSkalVises => enumType[feltSomSkalVises] == felt)) {
lookupFn(felt).should('be.visible');
} else {
lookupFn(felt).should('not.exist');
}
}
Or is the solution to try and check if the elements exists first, then if they do, check the visibility?
The tl;dr is that there isn't going to be a simple solution here -- Cypress' get command has assertions, so you can't easily catch or eat those exceptions. If you try to get an element that doesn't exist, Cypress will have a failed assertion. Unfortunately, the best case would be to have deterministic behavior for each assertion.
More info on why Cypress behaves this way here.
I think your best case for doing this would be to write a custom Chai assertion, but I don't have any experience in doing anything like that. Here is Chai's documentation on doing so.
If you wanted to simplify your code, but knew which elements should not exist and which elements should not be visible, you could write a custom command to handle that.
Cypress.Commands.add('notExistOrNotVisible', (selector, isNotExist) => {
cy.get(selector).should(isNotExist ? 'not.exist' : 'not.be.visible');
});
cy.notExistOrNotVisible('foo', true); // asserts that `foo` does not exist
cy.notExistOrNotVisible('bar', false); // asserts that `bar` is not visible
I arbitrarily made not exist the positive case, but you could switch that and the logic in the should.
I was facing the same problem, with some modals being destroyed (i.e. removed from the DOM) on close and others being just hidden.
I found a way to kinda emulate an or by adding the visibility check as a filter to the selection, then asserting non-existence:
cy.get('my-selector').filter(':visible').should('not.exist')
The error messages in case of failure are not as self-explanatory ("expected :visible to not exist") and you have to read the log a bit further to understand. If you don't need the separation between selector and filter you can combine the both to make get a nicer error message ("expected my-selector:visible to not exist"):
cy.get('my-selector:visible').should('not.exist')
Hopefully this will help some of you. I've been working with Cypress for a while now and found these particular custom commands to be pretty useful. I hope they help you too. ( Check for visibility utilizes the checkExistence command as well. You can just use the cy.isVisible() command and it will automatically check if it's at least in the DOM before continuing ).
P.S. These commands are still being tweaked - be nice :)
Command for checking existence
/**
* #param {String} errorMessage The error message you want to throw for the function if no arg is used
*/
const isRequired = (errorMessage = '--- Parameter is required! ---') => { throw new Error(errorMessage); };
/**
* #description Check if an element, found through xpath selector, exists or not in the DOM
* #param {String} xpath Required. Xpath to pass into the function to check if it exists in the DOM
* #param {Object} ifFound Message to pass to cy.log() if found. Default message provided
* #param {String} ifNotFound Message to pass to cy.log() if not found. Default message provided
* #returns Boolean. True if found, False if not found
* #example cy.checkExistence("xpath here", "Found it!", "Did not find it!").then(result=>{if(result==true){ // do something } else { // do something else }})
*/
Cypress.Commands.add('checkExistence',(xpath=isRequired(), ifFound, ifNotFound )=>{
return cy.window().then((win) => {
return (function(){
let result = win.document.evaluate(xpath, win.document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue
if(result!=null && result!=undefined){
if ( ifFound != undefined ) {
cy.log( `_** ${ifFound} **_` );
}
return cy.wrap( true );
} else {
if ( ifNotFound != undefined ) {
cy.log( `_** ${ifNotFound} **_` );
}
return cy.wrap( false );
}
})();
});
})
Command for checking visibility
/**
* #param {String} errorMessage The error message you want to throw for the function if no arg is used
*/
const isRequired = (errorMessage = '--- Parameter is required! ---') => { throw new Error(errorMessage); };
/**
* #description Check to see if an element is visible or not, using xpath selector or JQuery element
* #param {String} Xpath Xpath string
* #param {Boolean} waitForVisibility Optional. False by default. Set to true to wait for element to become visible.
* #param {Number} timeout Optional. Timeout for waitForVisibility param.
* #returns Boolean. True if visible, False if not visible
* #example cy.isVisible("//div").then(result=>{})
*/
Cypress.Commands.add('isVisible', (Xpath=isRequired(), waitForVisibility=false, timeout)=>{
cy.checkExistence(Xpath).then(result=>{
if(result==true){
cy.xpath(Xpath).then($element => {
if ($element.is(':visible')){
return cy.wrap(true)
} else {
if(waitForVisibility===true){
if(!timeout){
cy.logSpecial('wave',3, `Must provide value for timeout. Recieved ${timeout}`, true)
} else {
cy.log(`Waiting for element to become visible within ${timeout / 1000} seconds...`, true).then(()=>{
let accrued;
let interval = 250;
(function retry(){
if ($element.is(':visible')){
return cy.wrap(true)
} else {
accrued = accrued + interval;
if(accrued>=timeout){
cy.log(`Timeout waiting for element to become visible. Waited ${timeout / 1000} seconds.`)
return cy.wrap(false)
} else {
cy.wait(interval)
cy.wrap(retry())
}
}
})();
})
}
} else {
return cy.wrap(false)
}
}
})
} else {
cy.log(`Element does not exist in the DOM. Skipping visibility check...`).then(()=>{
if(throwError==true){
throw new Error (`Element of xpath ${Xpath} was not visible.`)
}
return cy.wrap(false)
})
}
})
})

rxjs collects the values sent by Subject and then sends the past values as an array

rxjs collects the values sent by Subject and then sends the past values as an array
import { Subject } from "rxjs";
const list$ = new Subject<number>();
list$
.pipe(/* Which pipeline should I use to achieve the following log information */)
.subscribe(console.log);
list$.next(1); // log: [1]
list$.next(2); // log: [1,2]
In RxJS .pipe() is where you list a series of operators. Each operator is a pure functinon that receives the emitted value from the previous observable (or operator), and returns a new value for the next operator.
Because of the utility that operators provide, the subscription method can be kept rather simple, or completely empty.
Given your requirement to convert each emitted value to an array, I would recommend the scan() operator. Similar to Array.reduce(), the scan() operator gives you an aggregate value you can add to for each emission from the source observable (in this case, your subject).
const list = new Subject<number>();
list.pipe(
scan((numArray, number)=>
[...numArray, number], [] as number[]
)
).subscribe(numArray=>console.log(numArray));
list.next(1); // [1]
list.next(2); // [1,2]
The reason I didn't include $ in the variable name, is that this is typically reserved only for public observables (not subjects or subscriptions, which shouldn't be exposed to other classes/modules/files).
I customized Observable to solve the problem, but I want to know how to use the pipe that comes with rxjs
import { Observable, Subject } from "rxjs";
const list$ = new Subject<number>();
var observable = new Observable((subscribe) => {
const cache = [];
const sub = list$.subscribe((v) => {
cache.push(v);
subscribe.next(cache);
});
return function unsubscribe() {
sub.unsubscribe();
};
});
const sub = observable.subscribe(console.log);
list$.next(1); // log: [1]
list$.next(2); // log: [1,2]

Unexpected Promise <state> pending being returned using axios [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I'm hoping somebody can point out the error of my ways here.
I have two functions at the moment. One is getData and it's an async function that simply makes an API call requesting data. The second function is getRandomCategories that encapsulates the getData function call and holds the value of that async operation in a variable called res. The rest of the code within getRandomCategories manipulates the response data to an array of numbers where each number represents a category.
When I use the debugger statement in the getRandomCategories function (right before the return statement within the try block) I'm getting the data type I'm expecting from my variable named apiCallCategoryArray - it's an array of numbers each representing a category. Life is good.
Here's the rub. When I call getRandomCategories expecting the dataArray variable (at the bottom of the code snippet) to hold an array of numbers - I'm getting a Promise back with its state pending??
I'm not understanding why the value for apiCallCategoryArray variable is showing up as my expected value using the debugger (and thus I'm returning it within the function) but I'm not able to access that value when I call the function. Why am I getting a Promise back with a pending state? What am I missing?
Here's my code below:
async function getData(endpoint, query, value) {
return await axios.get(
`http://jservice.io/api/${endpoint}?&${query}=${value}`
)
}
// createa a function that will return 6 random categories
async function getRandomCategories() {
try {
const res = await getData('categories', 'count', 50)
const data = res.data;
const categories = filterCategoryData(data); // I'm filtering for category id with clues_count === 5
const categoryIdArr = mapCategoryIds(categories); // an array of just category Ids
const shuffledCategoryIds = shuffle(categoryIdArr);
const apiCallCategoryArray = takeFirstXItems(shuffledCategoryIds, 6);
debugger// the value is what I'm expecting an array of numbers with length = 6
return apiCallCategoryArray
} catch (err) {
console.log(err);
}
}
//Solution one: Does not work. I'm getting a promise back instead of an array of numbers
const dataArray = getRandomCategories()
console.log(dataArray) // Promise { <state>: "pending" }
// expected return value [12231, 12344, 343245,124041, 12344, 348855] array of numbers
// Solution two: Does not work either. I'm still getttng a promise back instead of an array of numbers
const dataArray2 = getRandomCategories().then((array) => {
return array
})
console.log(dataArray2) // Promise { <state>: "pending" }
// expected return value [12231, 12344, 343245,124041, 12344, 348855] array of numbers
My objective is for my dataArray variable to hold an array of numbers (not a Promise with pending) returned by calling getRandomCategories(). So I can use this value for other functions in my code.
Thanks in advance for your time and responses.
you need to use use async, await to get back your Promise data. like this
async function test(){
let dataArray2 = await getRandomCategories();
console.log(dataArray2);
};

Cannot create async method which return ElementArrayFinder for E2E tests

I have a class where I want to make a async method which will return ElementArrayFinder. I need exactly this type, not ElementFinder[] because my waiters based on it and I can wait element which isn't present now in DOM. Below you can find a simple example of the structure. At row 'return this.collection;' i have an error:
[ts]
Type 'any[]' is not assignable to type 'ElementArrayFinder'.
Property 'browser_' is missing in type 'any[]'.
I tried to cast result in a different way and tried to use Promise.resolve, but no success. Could somebody help me with this case?
export class Test {
private grid1: ElementFinder;
private grid2: ElementFinder;
get collection1(): ElementArrayFinder {
return this.grid1
.element(by.css('tbody'))
.all(by.tagName('tr'));
}
get collection2(): ElementArrayFinder {
return this.grid2
.element(by.css('tbody'))
.all(by.tagName('tr'));
}
public async getCollection(): Promise<ElementArrayFinder> {
if (await this.collection.count() === 0) {
return this.collection1;
}
return this.collection2;
}
}
Bug report
Node Version: v8.2.1
Protractor Version: 5.2.0
I found the answer in file element.d.ts file.
/**
* Retrieve the elements represented by the ElementArrayFinder. The input
* function is passed to the resulting promise, which resolves to an
* array of ElementFinders.
*
* #alias element.all(locator).then(thenFunction)
* #view
* <ul class="items">
* <li>First</li>
* <li>Second</li>
* <li>Third</li>
* </ul>
*
* #example
* element.all(by.css('.items li')).then(function(arr) {
* expect(arr.length).toEqual(3);
* });
*
* // Or using the shortcut $$() notation instead of element.all(by.css()):
*
* $$('.items li').then(function(arr) {
* expect(arr.length).toEqual(3);
* });
*
* #param {function(Array.<ElementFinder>)} fn
* #param {function(Error)} errorFn
*
* #returns {!webdriver.promise.Promise} A promise which will resolve to
* an array of ElementFinders represented by the ElementArrayFinder.
*/
then<T>(fn?: (value: ElementFinder[] | any[]) => T | wdpromise.IThenable<T>, errorFn?: (error: any) => any): wdpromise.Promise<T>;
Based on this documentation ElementArrayFinder type is resolved by .then to the ElementFinder[]. That's why I cannot create method which return ElementArrayFinder type in promise, but can create method which simply return ElementArrayFinder type.

d3 selector for immediate children

I can obviously do this:
d3.selectAll('div#some-div>ul')
But what if I'm using a DOM node or existing D3 selection:
d3.select(this).selectAll('ul')
will get me all descendent ULs. So, if
var div = d3.select('div')
got me this node:
<div>
<ul>
<li>foo
<ul><li>bar</li></ul>
</li>
<ul>
</div>
Then
var uls = div.selectAll('ul')
will get me two ULs. I guess I could distinguish a top level one like:
uls.filter(function() { return this.parentNode === div.node() }
So, I've answered my own question. Maybe it will be useful to someone. Or maybe someone can recommend a less ugly solution.
Even better, Alain Dumesny, whose answer below is belatedly selected as correct, posted this as an issue to D3 and got the problem fixed, kludge-free, at the source! (I would copy it in here for convenience, but then people might not scroll down and cast greatly deserved upvotes for his heroic feat.)
I wouldn't have expected this to work, but it looks like D3 will sub-select any element that is a child of the selection and matches the selector - so this works:
d3.select(this).selectAll('div > ul');
See http://jsfiddle.net/g3aay/2/
If anyone is still interested, d3.select(this.childNodes) was helping me to solve my problem for picking all immediate children. Alternatively, you can use
selection.select(function(){
return this.childNodes;
})
d3 selection v2.0 should now have this built in with new selection.selectChildren() / selection.selectChild() methods - see https://github.com/d3/d3-selection/issues/243
#nrabinowitz's solution doesn't work all the time.
In my case, I was trying to do d3.select(this).selectAll(".childNode > *").
So I was trying to get all the immediate children of .childNode. The problem is that this was a nested stack, so .childNode could also appear in the children, which was causing problems.
The best way I found is:
var child = d3.select(this).select(".childNode");
var sel = d3.select(this).selectAll(".childNode > *").filter(function() {
return this.parentNode == child.node();
});
The selectAll method relies on the querySelectorAll native method (in v4 at least).
It means you can use the :scope pseudo selector :
var uls = div.selectAll(':scope > ul')
the :scope pseudo selector is currently a draft specification and is not supported in all browsers yet. More information on :scope pseudo selector available on MDN
Based on the solution by Sigfrid, here is something I added to the prototype, in a project I work on.
/**
* Helper that allows to select direct children.
* See https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
*
* #param {string} selector
* #returns {Selection}
*/
d3.selectAll('__nonexisting__').__proto__.MYPREFIX_selectChildren = function (selector) {
var expectedParent = this.node();
return this.selectAll(selector).filter(
function() {
return this.parentNode === expectedParent;
}
);
};
The way that I grab the prototype object looks a bit clumsy. Perhaps there is a better way.
The "MYPREFIX_" is meant to prevent name clashes.
The jsdoc #returns {Selection} is ambiguous, unfortunately this type is declared within a closure and has no global name referenceable by jsdoc (afaik).
Once this file is included, you can then do this:
d3.select('#some_id').MYPREFIX_selectChildren('ul')
Looks like d3 used to have some functions built to address this exact problem- but for one reason or another they were removed.
By pasting this code into your program, you can add them back in again:
function childMatcher(selector) {
return function(node) {
return node.matches(selector);
};
}
function children() {
return this.children;
}
function childrenFilter(match) {
return function() {
return Array.prototype.filter.call(this.children, match);
};
}
/**
* Runs the css selector only on the immediate children.
* See: https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
* Use: https://github.com/d3/d3-selection/commit/04e9e758c80161ed6b7b951081a5d5785229a8e6
*
* Example Input: selectChildren("form")
*/
d3.selection.prototype.selectChildren = function(match) {
return this.selectAll(match == null ? children
: childrenFilter(typeof match === "function" ? match : childMatcher(match)));
}
function childFind(match) {
return function() {
return Array.prototype.find.call(this.children, match);
};
}
function childFirst() {
return this.firstElementChild;
}
/**
* Runs the css selector only on the immediate children and returns only the first match.
* See: https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
* Use: https://github.com/d3/d3-selection/commit/04e9e758c80161ed6b7b951081a5d5785229a8e6
*
* Example Input: selectChild("form")
*/
d3.selection.prototype.selectChild = function(match) {
return this.select(match == null ? childFirst
: childFind(typeof match === "function" ? match : childMatcher(match)));
}
If you are using typescript, then here is the function declaration you can include in the same file:
declare module "d3" {
interface Selection<GElement extends d3.BaseType, Datum, PElement extends d3.BaseType, PDatum> {
selectChild(match: string | null | Function): Selection<GElement, Datum, PElement, PDatum>;
selectChildren(match: string | null | Function): Selection<GElement, Datum, PElement, PDatum>;
}
}
Here's a fiddle that implements this: https://jsfiddle.net/Kade333/drw3k49j/12/
For whatever it's worth after four years, ​d3.selectAll('#id > *') can be used, e.g. in ​d3.selectAll('#id > *').remove() to remove all children of an element with id=id

Resources