Can RxJS/Most Observable be integrated? - gun

I would like to be able to use an Observables library of sorts to integrate with other parts of my system.
It looks like having Observables streams would work nicely with gun. :)

Apart from using a library integration, another solution is to build your own Observables from Gun instances. See this codesandbox for example: https://codesandbox.io/s/pYj4OM8m1
const user$ = name => // returns a new observable
Observable.create(o =>
gun.get(name).on(v => {
o.next(v); // passes any new values to the observers
console.log(v);
}),
);
// now you can do rx stuff on the stream of values
user$('something'))
.map(({ name }) => ({ name: name.toUpperCase() }))
.filter(({ name }) => name.length > 0)

It looks like a guy named #ctrlplusb ;) made an extension for this: https://github.com/ctrlplusb/gun-most . Nice one!

Related

Ngrx waiting for Multiple API calls in effect

I'm super new about ngrx and I'm trying to develop an effect to dispatch multiple calls to my API to retrive a child list of objects.
Here my code.
loadMyChildren$ = createEffect (() => this.actions$.pipe(
ofType(SomeActions.loadMyChildren),
switchMap(({parentsObjArr}) => {
const obsList$: Observable<ChildModel>[] = parentsObjArr.result.map(parentsObj => this.childrenService.loadTimeSeries(parentsObj));
let childrenArr: ChildModel[] = [];
const source$ = zip(obsList$);
source$.subscribe((res) =>{
childrenArr = res;
}, err => { console.log(err); });
console.log('childrenArr', childrenArr)
return [
SomeActions.loadChildrenSuccess({childrenArr}),
SomeActionsTwo.loadParentsSuccess({parentsObjArr})
]
}),
catchError((err) => {
return of(SomeActions.loadMyChildrenFailed)
})
)
Unfortunately my effect seem doesn't wait for my API requests complete on "zip" (I tried also combineLatest and forkJoin) before dispatching the actions on the return array... "console.log" of my objects array is always empty and the store, consequently, does not keep any data.
What I'm wrong?
rxjs 6.6.0
angular 13.2.3
It's not good practise to manualy subscribe inside switchMap.
You are right, your code returns action before your API requests completes, you need to manipultate the stream without subscribing inside.
I would refactor your coude, so source$ is returned in switchMap, but its result is maped to desired ngrx actions with props that you wanted.
It would looked something like that:
switchMap(({parentsObjArr}) =>
zip(parentsObjArr.result.map(parentsObj => this.childrenService.loadTimeSeries(parentsObj)))
.pipe(
map(child => [
SomeActions.loadChildrenSuccess({child}),
SomeActionsTwo.loadParentsSuccess({parentsObjArr})
]
)
)
)

Understanding then() in Cypress

I am reading through the documentation in Cypress and I think I have an idea as to what then() does. It works like promises, where a promise returns another promise, but with then(), we are returning a new subject.
If we look at the code example below, we are using then() because we are returning a new variable, which in this case is called target.
Am I understanding this correctly? If not, can someone correct me?
it.only('Marks an incomplete item complete', () => {
//we'll need a route to stub the api call that updates our item
cy.fixture('todos')
.then(todos => {
//target is a single todo, taken from the head of the array. We can use this to define our route
const target = Cypress._.head(todos)
cy.route(
"PUT",
`api/todos/${target.id}`,
//Here we are mergin original item with an object literal
Cypress._.merge(target, {isComplete: true})
)
})
.then is used to receive the results from cy.fixture('todos'). The variable target is not significant in this code.
In your code sample, the variable that is returned from cy.fixture is named todos - the spacing of the code may be throwing you off here? The .then call is attached to the cy.fixture() call
// These 2 code blocks are the same - just different spacing
cy.fixture('todos')
.then(todos => {});
cy.fixture('todos').then(todos => {});
https://docs.cypress.io/api/commands/fixture.html#Usage
cy.fixture('logo.png').then((logo) => {
// load data from logo.png
})
Using .then() allows you to use the yielded subject in a callback function and should be used when you need to manipulate some values or do some actions.
To put it simply, it is used to play around with the yield of the previous command and work around with it in that case. THEN() command is handy and helpful in debugging the yield of the previous command.
const baseURL = "https://jsonplaceholder.typicode.com";
describe("Get Call-Expect+ normal req", () => {
it("GetPostById-Expect", () => {
cy.request(baseURL + "/posts/1").as("GetPostById");
cy.get("#GetPostById").then((response) => {
//response: status
expect(response.status).to.equal(200);
expect(response.status).to.eq(200);
});
});
Refer: https://docs.cypress.io/api/commands/then#Promises

How to populate the store and sequentially await return using Redux Observable?

I am attempting to use Redux Observable to call an action to fetch some data, wait for its return, then fetch some more data that relies on it.
I have an epic which populates a store from a fetch FetchTodos. This listens for the FETCH_TODOS action and then calls my todos API and populates {todos: [] } =
I also have a comments section in my store todoComments. However, I would like to only populate todoComments once FETCH_TODOS has returned and populated the store.
In imperative code, this might look like:
let todos = await api.get('/todos');
await dispatch("FETCH_TODO_COMPLETE", todos)
let firstId = getState().todos[0].id
let comments = await api.get(`/todos/${firstId}/comments')
await dispatch("FETCH_COMMENTS_COMPLETE", { todo_id: firstId, comments})
The closest I saw to this was this issue in the Redux Observable Repo, but I could not understand how to do this efficiently. This is a pretty common scenario for me.
I would like to reuse as much code as possible. In this example, I may dispatch FETCH_TODOS from multiple components.
How would i accomplish this with Redux-Observable?
Based on our conversation in the comments:
In redux-observable, you can sequence things in numerous ways. You could do it all in one epic using normal RxJS, or you could split them into multiple ones. If you split them, the subsequent epic would listen for the signal that the previous one has completed its task. Something like this:
// this assumes you make your `api.get` helper return an Observable
// instead of a Promise which is highly advisable.
// If it doesn't, you could do:
// Observable.from(api.get('/url'))
// but Promises are not truly cancellable which can cause max
// concurrent connections issues
const fetchTodosEpic = action$ =>
action$.ofType('FETCH_TODOS')
.switchMap(() =>
api.get('/todos')
.map(todos => ({
type: 'FETCH_TODOS_COMPLETE',
todos
}))
);
const fetchComments = action$ =>
action$.ofType('FETCH_TODOS_COMPLETE')
.switchMap(({ todos }) =>
api.get(`/todos/${todos[0].id}/comments`)
.map(comments => ({
type: 'FETCH_COMMENTS_COMPLETE',
comments
}))
);

jest snapshot testing: how to ignore part of the snapshot file in jest test results

Problem: ignore some part of the .snap file test results
the question here: there are some components in my test that have a random values and i don't really care about testing them. is there any way to ignore part of my X.snap file? so when i run tests in the future it won't give me test fail results.
Now you can also use property matcher for these cases.
By example to be able to use snapshot with these object :
const obj = {
id: dynamic(),
foo: 'bar',
other: 'value',
val: 1,
};
You can use :
expect(obj).toMatchSnapshot({
id: expect.any(String),
});
Jest will just check that id is a String and will process the other fields in the snapshot as usual.
Actually, you need to mock the moving parts.
As stated in jest docs:
Your tests should be deterministic. That is, running the same tests multiple times on a component that has not changed should produce the same results every time. You're responsible for making sure your generated snapshots do not include platform specific or other non-deterministic data.
If it's something related to time, you could use
Date.now = jest.fn(() => 1482363367071);
I know it's quite old question but I know one more solution. You can modify property you want to ignore, so it will be always constant instead of random / dynamic. This is best for cases when you are using third party code and thus may not be able to control the non deterministic property generation
Example:
import React from 'react';
import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import Card from './Card';
import toJSON from 'enzyme-to-json';
Enzyme.configure({ adapter: new Adapter() });
describe('<Card />', () => {
it('renders <Card /> component', () => {
const card = shallow(
<Card
baseChance={1}
name={`test name`}
description={`long description`}
imageURL={'https://d2ph5fj80uercy.cloudfront.net/03/cat1425.jpg'}
id={0}
canBeIgnored={false}
isPassive={false}
/>
);
const snapshot = toJSON(card);
// for some reason snapshot.node.props.style.backgroundColor = "#cfc5f6"
// does not work, seems the prop is being set later
Object.defineProperty(snapshot.node.props.style, 'backgroundColor', { value: "#cfc5f6", writable: false });
// second expect statement is enaugh but this is the prop we care about:
expect(snapshot.node.props.style.backgroundColor).toBe("#cfc5f6");
expect(snapshot).toMatchSnapshot();
});
});
You can ignore some parts in the snapshot tests replacing the properties in the HTML. Using jest with testing-library, it would look something like this:
it('should match snapshot', async () => {
expect(removeUnstableHtmlProperties(await screen.findByTestId('main-container'))).toMatchSnapshot();
});
function removeUnstableHtmlProperties(htmlElement: HTMLElement) {
const domHTML = prettyDOM(htmlElement, Infinity);
if (!domHTML) return undefined;
return domHTML.replace(/id(.*)"(.*)"/g, '');
}
I used this to override moment's fromNow to make my snapshots deterministic:
import moment, {Moment} from "moment";
moment.fn.fromNow = jest.fn(function (this: Moment) {
const withoutSuffix = false;
return this.from(moment("2023-01-12T20:14:00"), withoutSuffix);
});

How to throttle background task based on InteractionManager?

I have a list of projects in a Redux store. When new location data arrives from the GPS I'm updating the distance to each project in the list. Currently I'm throttling the update to 5 second intervals.
If the update coincides exactly with a navigation transition (using Ex-navigation) I get a non-smooth transition.
I would like to throttle based on a time interval and on data from InteractionManager.
Here is the current code:
let throttledProjectUpdate = _.throttle((position) => {
dispatch(ProjectState.projectNewLongLat(position.coords.longitude, position.coords.latitude))
}, 5000)
let watchId = navigator.geolocation.watchPosition((position) => {
dispatch(sensorGeoNewPositionAction(position))
throttledProjectUpdate(position)
});
I would like to do something like this:
let throttledProjectUpdate = _.throttle((position) => {
InteractionManager.runAfterInteractions(() =>
dispatch(ProjectState.projectNewLongLat(position.coords.longitude, position.coords.latitude))
);
}, 5000)
let watchId = navigator.geolocation.watchPosition((position) => {
dispatch(sensorGeoNewPositionAction(position))
throttledProjectUpdate(position)
});
But a few things are stopping me:
Is this really possible? I.e is InteractionManager a singleton which I can require from everywhere?
It feels wrong to mix GUI stuff with my background state updating
How should I solved this?