Angular 2 AND Karma Test AND Async HTTP - http

so my problem is very easy to explain
this is my test spec
import {
describe,
expect,
it,
inject,
beforeEachProviders
} from 'angular2/testing_internal';
import {RestClient} from './rest.service';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/delay';
import {
HTTP_PROVIDERS
} from 'angular2/http';
export function main() {
describe('RestClient Service', () => {
beforeEachProviders( () => [HTTP_PROVIDERS, RestClient] );
it('is defined', inject( [RestClient], (client) =>{
client.get('http://jsonplaceholder.typicode.com/posts/1')
.delay(2000)
.toPromise()
.then((res) => {
console.log('test');
expect(res.length).toBeGreaterThan(1000);
});
}));
});
}
and this is the method in the "RestClient" class that return an Observable
public get(url:string): Observable<any> {
return this.http.get(url).map(res => res.json());
}
So, i start the test and the test return
START:
LOG: 'ciao'
RestClient Service
✔ is defined
PhantomJS 2.0.0 (Mac OS X 0.0.0) LOG: 'ciao'
Finished in 0.026 secs / 0.038 secs
SUMMARY:
✔ 2 tests completed
For Karma all work well and the test is passed correctly and is not true, and at the same time if i put a console.log into the "then" never is called.
Som i suppose that is a problem with Async calls, do you have any idea howto test in Angular2 Async Calls
i have used Inject and AsyncInject too.
I know that i can use a MockBackend but i need to test with external urls
thanks in advance for your help

injectAsync should solve your problem, but you need to return the promise:
it('is defined', injectAsync( [RestClient], (client) =>{
return client.get('http://jsonplaceholder.typicode.com/posts/1')
.delay(2000)
.toPromise()
.then((res) => {
console.log('test');
expect(res.length).toBeGreaterThan(1000);
});
}));

Related

How do I use API middlewares to protect API routes from unauthenticated users in Next.js?

I have a next.js app that has several API routes that I am hoping to protect from users who are not logged in. Using next-auth, I understand that I can add the following code to each API route to achieve this.
import { getSession } from 'next-auth/client'
export default async (req, res) => {
const session = await getSession({ req })
if (session) {
res.send({ content: 'This is protected content. You can access this content because you are signed in.' })
} else {
res.send({ error: 'You must be sign in to view the protected content on this page.' })
}
}
However, I was wondering if it is possible to use API middlewares, so I am not repeating the same code over and over again? I read through the Next.js API middlewares documentation (https://nextjs.org/docs/api-routes/api-middlewares) and did the following:
import Cors from 'cors';
import { getSession } from 'next-auth/react';
function initMiddleware(middleware) {
return (req, res) =>
new Promise((resolve, reject) => {
middleware(req, res, async (result) => {
const session = await getSession({ req });
if (!session) {
return reject(result);
}
return resolve(result);
});
});
}
const cors = initMiddleware(
Cors({
methods: ['GET', 'POST', 'OPTIONS'],
})
);
export default async function handler(req, res) {
await cors(req, res);
\* fetching from database *\
Although it works, the following error is returned when I tried to access the API route when unauthenticated, and it feels like I'm not doing it properly.
error - null
wait - compiling /_error (client and server)...
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:561:11)
at DevServer.renderError (/Users/alextung/Desktop/Projects/askit/node_modules/next/dist/server/next-server.js:1677:17)
at DevServer.run (/Users/alextung/Desktop/Projects/askit/node_modules/next/dist/server/dev/next-dev-server.js:452:35)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async DevServer.handleRequest (/Users/alextung/Desktop/Projects/askit/node_modules/next/dist/server/next-server.js:325:20) {
code: 'ERR_HTTP_HEADERS_SENT'
}
error - Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Would really appreciate some help on this given that this is my first time working with middlewares. Thank you!

Testing async mapDispatchToProps actions with Jest/Enzyme gives error

I am trying to test my mapDispatchToProps actions when an async function is dispatched. I almost tried every possible solution I found and nothing worked so far. I'm always getting the same error:
I'm getting this error:
TypeError: store.dispatch(...).then is not a function
I tried the solution included in redux-mock-store https://github.com/dmitry-zaets/redux-mock-store. I included my middlewares to my mockStore, but it didn't fix the issue.
I tried the solution proposed by Michael Peyper here Testing dispatched actions in Redux thunk with Jest.
We created a function to build the mockStore so I tried to create my mockStore directly within my test file instead, but they both returned the same error.
I can't put all the solutions I tried here because it would take me weeks, but it gives you an idea.
Here's the code for my test:
describe('Component async actions', () => {
const middlewares = [thunk, queryMiddleware];
const createMockStore = configureStore(middlewares);
const store = createMockStore();
afterEach(() => {
jest.clearAllMocks();
});
const someData = {};
const expectedActions = {
type: ADD_DATA,
payload: someData
};
it('should handle addData', () => {
return store.dispatch(actions.addData(someData)).then(() => {
expect(store.getActions()[0]).toEqual(expectedAction);
});
});
});
Here's my mapDispatchToProps:
function mapDispatchToProps(dispatch) {
return {
addData: data => dispatch(addData(data))
.then(({ status }) => {
dispatch(showNotification({ status }));
}),
};
};
I would like to at least be able to get to the expect part and fix this if there's any error in my test, but I can't get passed the dispatch().then
Again, here's the error I get each time: TypeError: store.dispatch(...).then is not a function
Thanks in advance!
I don't know if anyone will get this problem, but I found a solution.
First of all, I had to add my thunk middleware to my createStore from redux-mock-store.
import thunk from 'redux-thunk';
...
const createMockStore = createStore([thunk]);
Then I did a mock of my addData function like this:
import { addData } from 'path/to/addData';
...
jest.mock('path/to/addData');
and I added this code within my test:
addData.mockReturnValue(() =>
new Promise((resolve) => resolve({ status: 200 }));
));
It works!

Why does Redux Promise Middleware not dispatch a rejected action for my example code?

I use fetch-mock, redux-mock-store, promise-middleware to test the redux implementation of my application. I have following code:
import configureMockStore from 'redux-mock-store';
import promiseMiddleware from 'redux-promise-middleware';
import fetchMock from 'fetch-mock';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import { bindActionCreators } from 'redux';
import { ACTION_1, hostNameSearchActions }
from '../../../src/actions/hostNameSearchActions';
const middlewares = [thunk, promiseMiddleware(), createLogger()];
let mockStore = configureMockStore(middlewares);
const SERVICE_URL = 'http://url_to_the_service';
describe('Testing thunk actions', () => {
let store = mockStore({ hostData: { key1 :'value'} });
const aHostNameSearch = bindActionCreators({ ...hostNameSearchActions }, store.dispatch).hostNameSearch;
afterEach(() => {
fetchMock.reset();
fetchMock.restore();
mockStore = configureMockStore(middlewares);
store = mockStore({ hostData: { key1 :'value'} });
});
it('ACTION_1_PENDING, ACTION_1_REJECTED dispatched, payload matches expected payload', (done) => {
fetchMock
.mock(`${SERVICE_URL}`,
404 );
const expectedActions = [
{ type: `${ACTION_1}_PENDING` },
{ type: `${ACTION_1}_REJECTED`, payload: {error: 'test.body.error.message'}}
];
aHostNameSearch().then(() => {
expect(store.getActions()).toEqual(expectedActions);
done();
});
});
});
The problem is that 404 call I am mocking with retchMock always ends up being resolved as ACTION_1_FULFILLED. why would this be the case? Am I mocking the call incorrectly?
Redux Promise Middleware always dispatches a rejected action when given a rejected action. If your mocked action always ends up being a fulfilled action, when you expect a rejected action, it is because the promise payload is fulfilled.
This can happen if you have any side-effects (e.g., any functions that use the then method on the promise) and don't properly pass the error up to the middleware. Without more context, though, it's impossible to give you a definitive answer. It would be helpful if you included your hostNameSearchActions.

Support for async/await in Meteor tests

I can't seem to be able to test a meteor method when it's written using async/await.
server/methods.js
Meteor.methods({
async f() {
const result = await new Promise((resolve) =>
setTimeout(() => resolve("i'm done"), 500));
return result;
}
})
server/methods.test.js
import {Meteor} from 'meteor/meteor';
import "./methods";
describe("f", () => {
it("should return _i'm done_", done => {
Meteor.call("f", (err, res) => {
// MY PROBLEM: res equals {}
done(err);
});
});
});
There is nothing special about my setup. This is the command I use to start my tests, meteor version is 1.4.2
meteor test --driver-package dispatch:mocha

How to cancel a HTTPRequest in Angular 2?

How to cancel a HTTPRequest in Angular 2?
I know how to reject the request promise only.
return new Promise((resolve, reject) => {
this.currentLoading.set(url, {resolve, reject});
this.http.get(url, {headers: reqHeaders})
.subscribe(
(res) => {
res = res.json();
this.currentLoading.delete(url);
this.cache.set(url, res);
resolve(res);
}
);
});
You can use the following simple solution:
if ( this.subscription ) {
this.subscription.unsubscribe();
}
this.subscription = this.http.get( 'awesomeApi' )
.subscribe((res)=> {
// your awesome code..
})
You can call unsubscribe
let sub = this.http.get(url, {headers: reqHeaders})
.subscribe(
(res) => {
res = res.json();
this.currentLoading.delete(url);
this.cache.set(url, res);
resolve(res);
}
);
sub.unsubscribe();
More info here: http://www.syntaxsuccess.com/viewarticle/angular-2.0-and-http
You can use SwitchMap on the observable which will cancel any previous request's responses and only request the latest:
https://www.learnrxjs.io/operators/transformation/switchmap.html
A little late for the party, but here is my take:
import { Injectable } from '#angular/core'
import { Http } from '#angular/http'
import { Observable } from 'rxjs/Observable'
import { Subscriber } from 'rxjs/Subscriber'
#Injectable ()
export class SomeHttpServiceService {
private subscriber: Subscriber<any>
constructor(private http: Http){ }
public cancelableRequest() {
let o = new Observable(obs => subscriber = obs)
return this.http.get('someurl').takeUntil(o)
.toPromise() //I dont like observables
.then(res => {
o.unsubscribe
return res
})
}
public cancelRequest() {
subscriber.error('whatever')
}
}
This allows you to manually cancel a request. I sometimes end up with an observable or promise that will make changes to a result on the page. If the request was initiated automatically (user didn't type anyting in a field for x millis) being able to abort the request is nice (user is suddenly typing something again)...
takeUntil should also work with a simple timeout (Observable.timer) if that is what you are looking for
https://www.learnrxjs.io/learn-rxjs/operators/filtering/takeuntil
Use switchMap [docs], which will cancel all in-flight requests and use only the latest.
get(endpoint: string): Observable<any> {
const headers: Observable<{url: string, headers: HttpHeaders}> = this.getConfig();
return headers.pipe(
switchMap(obj => this.http.get(`${obj.url}${endpoint}`, { headers: obj.headers, params: params }) ),
shareReplay(1)
);
}
shareReplay will emit the latest value for any late subscribers.
This is a great thread, and I have a little more info to provide. I have an API call that could potentially go on for a very long time. So I needed the previous request to cancel with a timeout. I just figured out today that I can add a timeout operator to the pipe function. Once the timeout completes its count, that will cancel the previous HTTP request.
Example...
return this.exampleHttpRequest()
.pipe(
timeout(3000),
catchError(err => console.log(error)
)

Resources