Angular2 refresh API every x minutes to watch change in response - ajax

Is there a way, in Angular 2, to watch for change in API.
Here is my case:
I push a document to an API /document/upload
This API return a DOC id
Using a call to /document/DOC_ID, the API returns a JSON in this format:
"errorCode":0,
"docId":"585846a1afe8ad12e46a4e60",
"status":0
Status can be:
0 = pending
1 = signed
2 = validated
This status will be "changed" by a worker on the remote server which validate the file. This state is only "interrogated" through the API.
On my front-end, I've a component dedicated to display the state of my document:
<p>Current State: {fileState}</p>
On my component, how can i watch the change of status in the api call result : how can I place for example a call which will call the API every x minutes to verify the state and update the view accordingly?

You can write something like this:
checkStatus(minutes: number, docID: string) {
Observable.interval(minutes * 60 * 1000)
.switchMap(() => this.http.get(`/documents/${docID}`)
// handle http errors here to prevent
// breaking of interval observable
.catch(error => Observable.of(error))
.map(response => response.json())
.subscribe(data => {
this.fileState =
data.state === 0 ? 'pending' :
data.state === 1 : 'signed' : 'validated';
})
}
Don't forget to import observable operators:
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';

Related

How do I use next auth getServerSession in next js 13 beta server component in app directory

I'm using next auth v4 with next js 13 beta with server component, everything working fine. But I have a situation where I will need to know the logged user id, since I'm using next auth, I have access to session, I can use useSession() but then I will need to make the component a client component, So I want to use it on server, I can use getServerSession in api since I have access to req & res object, but in next js beta with new app dir, I can't do it. Please let me know if you know how to fix the issue. Thank you
import { getServerSession } from "next-auth";
import { authOptions } from "#/pages/api/auth/[...nextauth]";
const Test = async () => {
const user_id = 1; // How do I get user id from session, user_id is available in session
// I don't have access req & res object in server component.
const data = await getServerSession(request, response, authOptions);
console.log(data);
});
return (
<></>
);
};
export default Test;
Didn't find enough information
I found an answer, in next js 13 beta, you wont need to use request & response object, just use the authOptions, it will work
import { getServerSession } from "next-auth";
import { authOptions } from "#/pages/api/auth/[...nextauth]";
const Test = async () => {
const data = await getServerSession(authOptions);
console.log(data);
});
return (
<></>
);
};
export default Test;

How to make cypress wait for a response that depends on another response?

From response A (/list.json) my app receives a list of items. Based on the output of A, my app makes another set of requests B for individual items (/one.txt, /two.txt, ...).
Now in my test I want to make sure that all responses B return HTTP 200.
Waiting (cy.wait) for response A is fine. However, waiting for responses B is more difficult, because I have to start waiting just upon receiving response A where I learn about responses B.
I tried 2 options:
start waiting inside of cy.wait of response A - code,
start waiting outside of cy.wait of response A - code
Neither of those work. With option 1 I get
`cy.wait()` timed out waiting `5000ms` for the 1st request to the route: `one.txt`. No request ever occurred
And with option 2 I get a pass, even though /two.txt doesn't exist. Looks like cy.wait for responses B is added after the responses were received
Since all requests are triggered off the visit, and are dynamic, you need a single intercept that handles all requests.
To me that means adding some javascript and dynamic aliases.
// avoid status code 304, disable browser cache
Cypress.automation('remote:debugger:protocol', {
command: 'Network.clearBrowserCache'
})
describe('spec', () => {
it('test', () => {
let items = [];
cy.intercept('GET', '*', (req) => {
const slug = req.url.substring(req.url.lastIndexOf('/') + 1)
if (slug === 'list.json') {
req.alias = 'list'
}
if (items.includes(slug)) {
req.alias = 'item'
}
req.continue((res) => {
if (slug === 'list.json')) {
items = res.body;
}
})
})
cy.visit('https://demo-cypress.netlify.app');
cy.wait('#list') // wait for list
.then(() => { // now items is populated
for (let item of items) { // really just need the count
cy.wait('#item').then(interception => { // wait n-times
expect(interception.response.statusCode).to.eq(200);
})
}
})
})
})

The resource <URL> was preloaded using link preload but not used within a few seconds from the window's load event - Wix fetch error

I'm using Google Analytics API to query user account and view
to do so, I'm using multiple WIX fetch functions (each fetch function depends on the previous one), here is one of them:
export function GetGAView (access_token, account_id,webPropertyId){
const url1 = "https://www.googleapis.com/analytics/v3/management/accounts/"
const url2 = account_id
const url3 = "/webproperties/"
const url4 = webPropertyId
const url5 = "/profiles?oauth_token="
const url6 = access_token
const url =url1.concat(url2,url3,url4,url5,url6).toString()
console.log(url, 'view url')
return fetch(url, {"method": "get"})
.then( (httpResponse) => {
if (httpResponse.ok) {
return httpResponse.json();
} else {
return Promise.reject("Fetch did not succeed");
}
} )
.then(json => {//console.log(json)
return json
}
)
.catch(err => console.log(err));
}
4 of 11 working well (same function distinguished by account id and properties id)and 7 functions return the following error shown on the console :
The error
/ga/oauth2callback?code=4%2XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&scope=email+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics&authuser=0&prompt=none:1 **The resource https://static.parastorage.com/services/editor-elements/dist/componentSdks.a8951fd0.bundle.min.js was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally.**
What does this error mean? How to solve this issue?
The only place I found the same error is here
https://www.wix.com/corvid/forum/community-discussion/parastorage-link-preload-failure

How to wait for a successful response in Cypress tests

Background
I use 3 back-end servers to provide fault tolerance for one of my online SaaS application. All important API calls, such as getting user data, contact all 3 servers and use value of first successfully resolved response, if any.
export function getSuccessValueOrThrow$<T>(
observables$: Observable<T>[],
tryUntilMillies = 30000,
): Observable<T> {
return race(
...observables$.map(observable$ => {
return observable$.pipe(
timeout(tryUntilMillies),
catchError(err => {
return of(err).pipe(delay(5000), mergeMap(_err => throwError(_err)));
}),
);
})
);
}
getSuccessValueOrThrow$ get called as following:
const shuffledApiDomainList = ['server1-domain', 'server2-domain', 'server3-domain';
const sessionInfo = await RequestUtils.getSuccessValueOrThrow(
...(shuffledApiDomainList.map(shuffledDomain => this.http.get<SessionDetails>(`${shuffledDomain}/file/converter/comm/session/info`))),
).toPromise();
Note: if one request resolve faster than others, usually the case, race rxjs function will cancel the other two requests. On Chrome dev network tab it will look like bellow where first request sent out was cancelled due to being too slow.
Question:
I use /file/converter/comm/session/info (lets call it Endpoint 1) to get some data related to a user. This request dispatched to all 3 back-end servers. If one resolve, then remaining 2 request will be cancelled, i.e. they will return null.
On my Cypress E2E test I have
cy.route('GET', '/file/converter/comm/session/info').as('getSessionInfo');
cy.visit('https://www.ps2pdf.com/compress-mp4');
cy.wait('#getSessionInfo').its('status').should('eq', 200)
This sometimes fails if the since getSessionInfo alias was hooked on to a request that ultimately get cancelled by getSuccessValueOrThrow$ because it wasn't the request that succeeded.Bellow image shows how 1 out of 3 request aliased with getSessionInfo succeeded but the test failed since the first request failed.
In Cypress, how do I wait for a successful i.e. status = 200 request?
Approach 1
Use .should() callback and repeat the cy.wait call if status was not 200:
function waitFor200(routeAlias, retries = 2) {
cy.wait(routeAlias).then(xhr => {
if (xhr.status === 200) return // OK
else if (retries > 0) waitFor200(routeAlias, retries - 1); // wait for the next response
else throw "All requests returned non-200 response";
})
}
// Usage example.
// Note that no assertions are chained here,
// the check has been performed inside this function already.
waitFor200('#getSessionInfo');
// Proceed with your test
cy.get('button').click(); // ...
Approach 2
Revise what it is that you want to test in the first place.
Chances are - there is something on the page that tells the user about a successful operation. E.g. show/hide a spinner or a progress bar, or just that the page content is updated to show new data fetched from the backend.
So in this approach you would remove cy.wait() altogether, and focus on what the user sees on the page - do some assertions on the actual page content.
cy.wait() yields an object containing the HTTP request and response properties of the XHR. The error you're getting is because you're looking for property status in the XHR object, but it is a property of the Response Object. You first have to get to the Response Object:
cy.wait('#getSessionInfo').should(xhr => {
expect(xhr.response).to.have.property('status', 200);
});
Edit: Since our backend uses graphql, all calls use the single /graphql endpoint. So I had to come up with a solution to differentiate each call.
I did that by using the onResponse() method of cy.route() and accumulating the data in Cypress environment object:
cy.route({
method: 'GET',
url: '/file/converter/comm/session/info',
onResponse(xhr) {
if (xhr.status === 200) {
Cypress.env('sessionInfo200') = xhr;
}
}
})
You can then use it like this:
cy.wrap(Cypress.env()).should('have.property', 'sessionInfo200');
I wait like this:
const isOk = cy.wait("#getSessionInfo").then((xhr) => {
return (xhr.status === 200);
});

koa session expire event

Am trying to log a message when a koa session expires. But adding a listener for the expire event doesnt seem to work for me.
Following is the sample code. Set 2 mins as maxAge for the session.
import koa from 'koa';
import serve from 'koa-static';
import route from 'koa-route';
import session from 'koa-session';
import mount from 'koa-mount';
let pub = new koa();
let parse = new koa();
let app = new koa();
app.keys = ['test'];
const CONFIG = {
key: 'sess',
maxAge: 2000
};
parse.use(ctx => {
// ignore favicon
if (ctx.path === '/test') return;
let n = ctx.session.views || 0;
ctx.session.views = ++n;
ctx.body = n + ' views';
console.log(ctx.session);
});
pub.use(serve('./public'));
app.use(session(CONFIG,app));
app.on('expired',(key,value,ctx) => console.log(key));
app.use(mount('/',pub));
app.use(mount('/parse',parse));
app.listen(8080);
Here everytime i refresh the page after 2 seconds in browser i can see the "views" value set back to 1 meaning the previous session had expired. But the log statement as part of the expired event is not getting hit. May be the way am adding the event listener is wrong. Can someone please help?
After having a look at library files, koajs/session -> context.js
if (value._expire && value._expire < Date.now()) {
debug('expired session');
this.emit('expired', { key, value, ctx });
return false;
}
where emit is:
emit(event, data) {
setImmediate(() => {
this.app.emit(`session:${event}`, data);
});
}
So I think in your code you shouldchange the name you are trying to capture the event with:
app.on('session:expired',(key,value,ctx) => console.log(key));
If key is containing a value, you should see something printing out in the console :)

Resources