scipaper/src/test/page.interceptor.spec.ts

318 lines
11 KiB
TypeScript

import { HttpService } from "@nestjs/axios";
import { ConfigModule } from "@nestjs/config";
import { Test } from "@nestjs/testing";
import { Observable, of } from "rxjs";
import { EsTime, Order } from "src/core/domain";
import { PageDto } from "src/core/domain/dtos";
import { HttpResponseException } from "src/core/exceptions";
import { PageInterceptor } from "src/core/interceptors/page.interceptor";
const execCtxMock = {
switchToHttp: jest.fn().mockReturnThis(),
getRequest: jest.fn().mockReturnThis(),
getHandler: jest.fn().mockReturnThis(),
getArgs: jest.fn().mockReturnThis(),
getArgByIndex: jest.fn().mockReturnThis(),
switchToRpc: jest.fn().mockReturnThis(),
switchToWs: jest.fn().mockReturnThis(),
getType: jest.fn().mockReturnThis(),
getClass: jest.fn().mockReturnThis(),
};
const callHandlerMock = {
handle: jest.fn(),
};
describe('Unit tests for PageInterceptor', () => {
let pageInter: PageInterceptor;
let httpService: HttpService;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
providers: [
{
provide: HttpService,
useValue: {
post: jest.fn(),
delete: jest.fn()
},
},
PageInterceptor,
],
imports: [
ConfigModule.forRoot({
isGlobal: true,
cache: true,
expandVariables: true,
})
],
}).compile();
pageInter = moduleRef.get(PageInterceptor);
httpService = moduleRef.get(HttpService);
execCtxMock.getRequest.mockReturnValue({
query: {
query: 'thisIsMyQuery',
page: 1,
limit: 5,
order: Order.DESC
}
});
callHandlerMock.handle.mockReturnValue(
of({
hits: {
total: { value: 1 },
hits: [{}]
}
})
);
});
it('Should be defined', () => {
expect(pageInter).toBeDefined();
expect(httpService).toBeDefined();
});
describe('intercept()', () => {
let tmp;
beforeAll(() => {
tmp = pageInter.getPIT;
pageInter.getPIT = jest.fn().mockReturnValue({});
});
afterAll(() => {
pageInter.getPIT = tmp;
});
it('Should return a Promise', () => {
expect(pageInter.intercept(execCtxMock, callHandlerMock)).toBeInstanceOf(Promise);
});
it('Should return a Promise with Observable and PageDto inside', () => {
pageInter.intercept(execCtxMock, callHandlerMock).then((res) => {
expect(res).toBeInstanceOf(Observable);
res.subscribe((data) => {
expect(data).toBeInstanceOf(PageDto);
});
});
});
it('Should touch CallHandler.handle() method', () => {
let chHandleSpy = jest.spyOn(callHandlerMock, 'handle');
pageInter.intercept(execCtxMock, callHandlerMock);
expect(chHandleSpy).toBeCalled();
});
it('Should construct a page with proper data on it', () => {
callHandlerMock.handle.mockReturnValueOnce(
of({
hits: {
total: { value: 1 },
hits: [{
_source: {
dummy: 'dum'
}
}]
}
})
);
pageInter.intercept(execCtxMock, callHandlerMock).then((res) => {
res.subscribe((page) => {
expect(page.data.length).toBe(1);
expect(page.data[0]).toEqual({ dummy: 'dum' });
});
});
});
it('Should construct correct meta-data of the page', () => {
execCtxMock.getRequest.mockReturnValueOnce({
query: {
page: 5,
order: 'desc',
limit: 100,
}
});
callHandlerMock.handle.mockReturnValueOnce(
of({
hits: {
total: { value: 921 },
hits: []
}
})
);
pageInter.intercept(execCtxMock, callHandlerMock).then((res) => {
res.subscribe((page) => {
expect(page.meta).toEqual({
total: 921,
pagenum: 5,
order: 'desc',
hasNext: true,
hasPrev: true,
pagesize: 100
});
});
});
});
it('Should reverse the search results', () => {
execCtxMock.getRequest.mockReturnValueOnce({
query: {
page: 1,
order: 'desc',
limit: 3
}
});
pageInter['prevSearch']._prevPage = 3;
pageInter['prevSearch'].isSet = jest.fn().mockImplementationOnce(() => {
return true;
})
callHandlerMock.handle.mockReturnValueOnce(
of({
hits: {
total: { value: 1 },
hits: [
{ sort: ['1', 'less relevant'], _source: '1' },
{ sort: ['2', 'average'], _source: '2' },
{ sort: ['3', 'most relevant'], _source: '3' }
]
}
})
);
pageInter.intercept(execCtxMock, callHandlerMock).then((res) => {
res.subscribe((page) => {
expect(pageInter['prevSearch']._tiebreaker).toEqual(['1', 'less relevant']);
expect(page.data).toEqual(['3', '2', '1']);
});
});
});
});
describe('getPIT()', () => {
it('Should touch HttpService.post() method', () => {
let httpPostMock = jest.spyOn(httpService, 'post').mockReturnValueOnce(of({
data: {id: '2567'},
status: 0,
statusText: '',
headers: {},
config: {},
}));
pageInter.getPIT(1);
expect(httpPostMock).toHaveBeenCalled();
});
it('Should contain correct port in the URI from .env', () => {
let httpPostMock = jest.spyOn(httpService, 'post').mockReturnValueOnce(of({
data: {id: '2567'},
status: 0,
statusText: '',
headers: {},
config: {},
}));
pageInter.getPIT(1);
expect(httpPostMock).toHaveBeenCalledWith(`http://${process.env.ES_CONTAINER_NAME}:${process.env.ES_PORT}/papers/_pit?keep_alive=1m`);
});
it('Should touch HttpService with correct URI when time alive and time-unit are set', () => {
let httpPostMock = jest.spyOn(httpService, 'post').mockReturnValueOnce(of({
data: {id: '2567'},
status: 0,
statusText: '',
headers: {},
config: {},
}));
let time = 2;
let unit = EsTime.sec;
pageInter.getPIT(time, unit);
expect(httpPostMock).toHaveBeenCalledWith(`http://${process.env.ES_CONTAINER_NAME}:${process.env.ES_PORT}/papers/_pit?keep_alive=${time+unit}`);
});
it('Should return error exeception when HttpService fails', () => {
jest.spyOn(httpService, 'post').mockImplementationOnce(() => {
throw HttpResponseException;
});
expect(pageInter.getPIT(1)).rejects.toEqual(HttpResponseException);
});
it('Should return a non-empty string when HttpService request succeedes', () => {
jest.spyOn(httpService, 'post').mockReturnValueOnce(of({
data: {id: '2567', keep_alive: '1m'},
status: 0,
statusText: '',
headers: {},
config: {},
}));
expect(pageInter.getPIT(1)).resolves.toEqual({
id: '2567',
keep_alive: '1m',
});
});
});
describe('deletePIT()', () => {
it('Should touch HttpService.delete() method', () => {
let httpDeleteMock = jest.spyOn(httpService, 'delete').mockReturnValueOnce(
of({
data: {succeeded: true},
status: 0,
statusText: '',
headers: {},
config: {},
}));
pageInter.deletePIT('');
expect(httpDeleteMock).toHaveBeenCalled();
});
it('Should contain correct port in the URI from .env and passed PIT ID in the request body', () => {
let httpDeleteMock = jest.spyOn(httpService, 'delete').mockReturnValueOnce(
of({
data: { succeeded: true },
status: 0,
statusText: '',
headers: {},
config: {},
}));
pageInter.deletePIT('thisIsIDSpecified');
expect(httpDeleteMock).toHaveBeenCalledWith(`http://${process.env.ES_CONTAINER_NAME}:${process.env.ES_PORT}/_pit`, {
data: { id: 'thisIsIDSpecified' },
headers: { 'Content-Type': 'application/json' }
});
});
it('Should return error exeception when HttpService fails', () => {
jest.spyOn(httpService, 'delete').mockImplementationOnce(() => {
throw HttpResponseException;
});
expect(pageInter.deletePIT('')).rejects.toEqual(HttpResponseException);
});
it('Should return true when Elasticsearch successfully removed PIT', () => {
jest.spyOn(httpService, 'delete').mockReturnValueOnce(
of({
data: { succeeded: true },
status: 0,
statusText: '',
headers: {},
config: {},
}));
expect(pageInter.deletePIT('')).resolves.toBe(true);
});
});
});