Reputation: 910
I have a simple interceptor that deletes a field from response:
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
export interface Response<T> {
data: T;
}
@Injectable()
export class Transform<T> implements NestInterceptor<T, Response<T>> {
intercept(
context: ExecutionContext,
next: CallHandler,
): Observable<Response<T>> {
return next.handle().pipe(
map((response) => {
delete response?.value?.name;
return response;
}),
);
}
}
How can I write test case for this? Basically, I wanted to test if 'name' is deleted from response. I wrote the following test case but response is coming as undefined:
it('should delete `name` from response if present', async () => {
transformInterceptor = new TransformRepoResponse();
const context = {
switchToHttp: () => ({
getRequest: () => jest.fn(),
}),
};
const next = {
handle: jest.fn().mockReturnValue({
pipe: jest.fn(),
}),
};
requestMock.method = 'GET';
const response = await transformInterceptor.intercept(context, next);
expect(response.value.name).toBe(undefined);
});
Upvotes: 0
Views: 1221
Reputation: 3548
This worked for me for your example:
import { CallHandler } from '@nestjs/common';
import { lastValueFrom, of } from 'rxjs';
import { createMocks } from 'node-mocks-http';
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
describe('Transform Interceptor test', () => {
let transformInterceptor: Transform<any>;
beforeEach(() => {
transformInterceptor = new Transform();
});
it('should be defined', () => {
expect(transformInterceptor).toBeDefined();
});
it('should remove the name', async () => {
const { req, res } = createMocks();
const testContext = new ExecutionContextHost([req, res]);
const nextSpy: CallHandler<any> = {
handle: () =>
of({ what: 'ever', value: { name: 'Mario', something: 'else' } }),
};
await expect(
lastValueFrom(transformInterceptor.intercept(testContext, nextSpy)),
).resolves.toEqual({ what: 'ever', value: { something: 'else' } });
});
});
I found good hint for this solution here: https://github.com/leosuncin/nest-api-example/blob/master/src/auth/interceptors/token.interceptor.spec.ts
Upvotes: 0
Reputation: 70570
Interceptors aren't async
so you can't await
their response without using lastValueFrom()
as a wrapper. Also, your next.handle()
should return an observable that will be acted on by the .pipe
. Something like
it('should delete `name` from response if present', (done) => {
transformInterceptor = new TransformRepoResponse();
const context = {
switchToHttp: () => ({
getRequest: () => jest.fn(),
}),
};
const next = {
handle: jest.fn().mockReturnValue(of({
value: {
name: 'name-field',
foo: 'foo-field',
}
}),
};
requestMock.method = 'GET';
let errors = []
transformInterceptor.intercept(context, next).subscribe({
next: (data) => {
try {
expect(data).toEqual({
value: { foo: 'foo-field' }
})
} catch (err) {
errors.push(err);
}
complete: () => done(errors.length ? errors.join(' ') : undefined)
}
})
});
Now you're testing the interceptor as an observable, you only expect one value so using the next
of subscribe
is fine, and you're telling Jest that the test is finished when the observable completes. You're also persisting any errors that happen by catching them in the next
and using them as part of the done
call if they exist.
Upvotes: 2