Test coverage for pagination and search service.
This commit is contained in:
parent
5eb20c4727
commit
26cd205738
@ -1,8 +1,7 @@
|
|||||||
import { HttpService } from "@nestjs/axios";
|
import { HttpService } from "@nestjs/axios";
|
||||||
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from "@nestjs/common";
|
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from "@nestjs/common";
|
||||||
import { Observable, map, take } from "rxjs";
|
import { Observable, map, take } from "rxjs";
|
||||||
import { EsResponseDto, PageDto } from "../domain/dtos";
|
import { PageDto } from "../domain/dtos";
|
||||||
import { EsHitDto } from "../domain/dtos/es-hit.dto";
|
|
||||||
import { EsQueryDto } from "../domain/dtos/es-query.dto";
|
import { EsQueryDto } from "../domain/dtos/es-query.dto";
|
||||||
import { RequestDto } from "../domain/dtos/request.dto";
|
import { RequestDto } from "../domain/dtos/request.dto";
|
||||||
import { SearchQueryDto } from "../domain/dtos/search-q.dto";
|
import { SearchQueryDto } from "../domain/dtos/search-q.dto";
|
||||||
@ -10,12 +9,11 @@ import { EsTime } from "../domain/enums/es-time.enum";
|
|||||||
import { Order } from "../domain/enums/page-order.enum";
|
import { Order } from "../domain/enums/page-order.enum";
|
||||||
import { PageMeta } from "../domain/interfaces";
|
import { PageMeta } from "../domain/interfaces";
|
||||||
import { EsPit } from "../domain/interfaces/es-pit.interface";
|
import { EsPit } from "../domain/interfaces/es-pit.interface";
|
||||||
import { SearchInfo } from "../domain/interfaces/search-info.interface";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Previous search data storage
|
* Previous search data storage
|
||||||
*/
|
*/
|
||||||
class PrevSearch implements SearchInfo {
|
class PrevSearch {
|
||||||
/**
|
/**
|
||||||
* Constructs an uninitialized object
|
* Constructs an uninitialized object
|
||||||
*/
|
*/
|
||||||
@ -28,17 +26,35 @@ class PrevSearch implements SearchInfo {
|
|||||||
/**
|
/**
|
||||||
* PIT object of the previous search
|
* PIT object of the previous search
|
||||||
*/
|
*/
|
||||||
pit: EsPit;
|
private pit: EsPit;
|
||||||
|
set _pit(pit: EsPit) {
|
||||||
|
this.pit = pit;
|
||||||
|
}
|
||||||
|
get _pit(): EsPit {
|
||||||
|
return this.pit;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tiebreaker and sort parameters
|
* Tiebreaker and sort parameters
|
||||||
*/
|
*/
|
||||||
tiebreaker: unknown[];
|
private tiebreaker: unknown[];
|
||||||
|
set _tiebreaker(tiebreaker: unknown[]) {
|
||||||
|
this.tiebreaker = tiebreaker;
|
||||||
|
}
|
||||||
|
get _tiebreaker(): unknown[] {
|
||||||
|
return this.tiebreaker;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of the previous page
|
* Number of the previous page
|
||||||
*/
|
*/
|
||||||
prevPage: number;
|
private prevPage: number;
|
||||||
|
set _prevPage(page: number) {
|
||||||
|
this.prevPage = page;
|
||||||
|
}
|
||||||
|
get _prevPage(): number {
|
||||||
|
return this.prevPage;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if there was the search before current one
|
* Checks if there was the search before current one
|
||||||
@ -89,23 +105,23 @@ export class PageInterceptor implements NestInterceptor {
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (this.prevSearch.isSet()) {
|
if (this.prevSearch.isSet()) {
|
||||||
request.es_query.pit = this.prevSearch.pit;
|
request.es_query.pit = this.prevSearch._pit;
|
||||||
request.es_query.search_after = this.prevSearch.tiebreaker;
|
request.es_query.search_after = this.prevSearch._tiebreaker;
|
||||||
|
|
||||||
let limit = !query?.limit ? 10 : query.limit;
|
let limit = !query?.limit ? 10 : query.limit;
|
||||||
request.es_query.size = limit * Math.abs(query.page - this.prevSearch.prevPage);
|
request.es_query.size = limit * Math.abs(query.page - this.prevSearch._prevPage);
|
||||||
|
|
||||||
if (query.page < this.prevSearch.prevPage) {
|
if (query.page < this.prevSearch._prevPage) {
|
||||||
request.es_query.sort = [{ _score: { order: 'asc' } }];
|
request.es_query.sort = [{ _score: { order: 'asc' } }];
|
||||||
request.es_query.size += limit - 1;
|
request.es_query.size += limit - 1;
|
||||||
reverse = true;
|
reverse = true;
|
||||||
} else if (query.page == this.prevSearch.prevPage) {
|
} else if (query.page == this.prevSearch._prevPage) {
|
||||||
// Caching should be HERE
|
// Caching should be HERE
|
||||||
request.es_query.sort = [{ _score: { order: 'asc' } }];
|
request.es_query.sort = [{ _score: { order: 'asc' } }];
|
||||||
reverse = true;
|
reverse = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.prevSearch.pit = request.es_query.pit = await this.getPIT(1);
|
this.prevSearch._pit = request.es_query.pit = await this.getPIT(1);
|
||||||
|
|
||||||
let limit = !query?.limit ? 10 : query.limit;
|
let limit = !query?.limit ? 10 : query.limit;
|
||||||
request.es_query.size = limit * query.page;
|
request.es_query.size = limit * query.page;
|
||||||
@ -116,24 +132,24 @@ export class PageInterceptor implements NestInterceptor {
|
|||||||
// Setting the page meta-data
|
// Setting the page meta-data
|
||||||
let meta: PageMeta = {
|
let meta: PageMeta = {
|
||||||
total: res.hits.total.value,
|
total: res.hits.total.value,
|
||||||
pagenum: !query?.page ? 1 : query.page,
|
pagenum: !query?.page ? 1 : +query.page,
|
||||||
order: query?.order?.toUpperCase() === Order.ASC ? Order.ASC : Order.DESC,
|
order: query?.order?.toUpperCase() === Order.ASC ? Order.ASC : Order.DESC,
|
||||||
|
pagesize: !query?.limit ? 10 : query.limit,
|
||||||
hasNext: undefined,
|
hasNext: undefined,
|
||||||
hasPrev: undefined,
|
hasPrev: undefined,
|
||||||
pagesize: !query?.limit ? 10 : query.limit,
|
|
||||||
};
|
};
|
||||||
meta.hasNext = meta.pagenum * meta.pagesize < meta.total ? true : false;
|
meta.hasNext = meta.pagenum * meta.pagesize < meta.total ? true : false;
|
||||||
meta.hasPrev = meta.pagenum != 1 ? true : false;
|
meta.hasPrev = meta.pagenum != 1 ? true : false;
|
||||||
|
|
||||||
// Saving the search info
|
// Saving the search info
|
||||||
this.prevSearch.pit.id = res.pit_id;
|
this.prevSearch._pit.id = res.pit_id;
|
||||||
this.prevSearch.tiebreaker = res.hits.hits[res.hits.hits.length - 1]?.sort;
|
this.prevSearch._tiebreaker = res.hits.hits[res.hits.hits.length - 1]?.sort;
|
||||||
this.prevSearch.prevPage = query.page;
|
this.prevSearch._prevPage = query.page;
|
||||||
|
|
||||||
// Check if the performed search is a backward search
|
// Check if the performed search is a backwards search
|
||||||
let data = res.hits.hits.slice(-meta.pagesize);
|
let data = res.hits.hits.slice(-meta.pagesize);
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
this.prevSearch.tiebreaker = data[0]?.sort;
|
this.prevSearch._tiebreaker = data[0]?.sort;
|
||||||
data.reverse();
|
data.reverse();
|
||||||
reverse = false;
|
reverse = false;
|
||||||
}
|
}
|
||||||
@ -165,12 +181,12 @@ export class PageInterceptor implements NestInterceptor {
|
|||||||
public async getPIT(alive: number, unit: EsTime = EsTime.min): Promise<EsPit> {
|
public async getPIT(alive: number, unit: EsTime = EsTime.min): Promise<EsPit> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
(this.httpService.post<EsPit>(`http://localhost:${this.ES_PORT}/papers/_pit?keep_alive=${alive+unit}`)
|
this.httpService.post<EsPit>(`http://localhost:${this.ES_PORT}/papers/_pit?keep_alive=${alive+unit}`)
|
||||||
.pipe(take(1), map(axiosRes => axiosRes.data))
|
.pipe(take(1), map(axiosRes => axiosRes.data))
|
||||||
.subscribe((res) => {
|
.subscribe((res: EsPit) => {
|
||||||
res.keep_alive = alive + unit;
|
res.keep_alive = alive + unit;
|
||||||
resolve(res);
|
resolve(res);
|
||||||
}));
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
|
82
src/test/e2e/papers.endpoint.spec.ts
Normal file
82
src/test/e2e/papers.endpoint.spec.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { Test, TestingModule } from "@nestjs/testing";
|
||||||
|
import { INestApplication } from "@nestjs/common";
|
||||||
|
import request from 'supertest'
|
||||||
|
import { AppModule } from "src/infrastructure/modules";
|
||||||
|
|
||||||
|
describe('E2E Testing of /papers', () => {
|
||||||
|
let app: INestApplication;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const moduleRef: TestingModule = await Test.createTestingModule({
|
||||||
|
imports: [AppModule],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
app = moduleRef.createNestApplication();
|
||||||
|
await app.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('GET /papers/{uuid} | Should return one exact item on page', async () => {
|
||||||
|
const test = await request(app.getHttpServer())
|
||||||
|
.get('/papers/eeeb2d01-8315-454e-b33f-3d6caa25db42') // ??? Fetch a random object from DB
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
// Checking received data
|
||||||
|
expect(test.body.data).toBeDefined();
|
||||||
|
|
||||||
|
expect(test.body.data.length).toBe(1);
|
||||||
|
expect(test.body.data[0].id).toBeDefined();
|
||||||
|
expect(test.body.data[0].title).toBeDefined();
|
||||||
|
expect(test.body.data[0].authors).toBeDefined();
|
||||||
|
expect(test.body.data[0].summary).toBeDefined();
|
||||||
|
expect(test.body.data[0].tags).toBeDefined();
|
||||||
|
expect(test.body.data[0].content).toBeDefined();
|
||||||
|
expect(test.body.data[0].id).toBe('eeeb2d01-8315-454e-b33f-3d6caa25db42');
|
||||||
|
|
||||||
|
// Checking received meta
|
||||||
|
expect(test.body.meta).toBeDefined();
|
||||||
|
|
||||||
|
expect(test.body.meta.total).toBeDefined();
|
||||||
|
expect(test.body.meta.pagenum).toBeDefined();
|
||||||
|
expect(test.body.meta.order).toBeDefined();
|
||||||
|
expect(test.body.meta.pagesize).toBeDefined();
|
||||||
|
expect(test.body.meta.hasNext).toBeDefined();
|
||||||
|
expect(test.body.meta.hasPrev).toBeDefined();
|
||||||
|
expect(test.body.meta.total).toBe(1);
|
||||||
|
expect(test.body.meta.pagenum).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('GET /papers/search? | Should return multiple items', async () => {
|
||||||
|
const test = await request(app.getHttpServer())
|
||||||
|
.get('/papers/search?query=at&page=1')
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
// Checking received data
|
||||||
|
expect(test.body.data).toBeDefined();
|
||||||
|
|
||||||
|
expect(test.body.data.length).toBeGreaterThan(0);
|
||||||
|
for (const paper of test.body.data) {
|
||||||
|
expect(paper.id).toBeDefined();
|
||||||
|
expect(paper.title).toBeDefined();
|
||||||
|
expect(paper.authors).toBeDefined();
|
||||||
|
expect(paper.summary).toBeDefined();
|
||||||
|
expect(paper.tags).toBeDefined();
|
||||||
|
expect(paper.content).toBeDefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking received meta
|
||||||
|
expect(test.body.meta).toBeDefined();
|
||||||
|
|
||||||
|
expect(test.body.meta.total).toBeDefined();
|
||||||
|
expect(test.body.meta.pagenum).toBeDefined();
|
||||||
|
expect(test.body.meta.order).toBeDefined();
|
||||||
|
expect(test.body.meta.pagesize).toBeDefined();
|
||||||
|
expect(test.body.meta.hasNext).toBeDefined();
|
||||||
|
expect(test.body.meta.hasPrev).toBeDefined();
|
||||||
|
expect(test.body.meta.total).toBeGreaterThan(0);
|
||||||
|
expect(test.body.meta.pagenum).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await app.close();
|
||||||
|
})
|
||||||
|
});
|
@ -1,12 +1,12 @@
|
|||||||
import { HttpModule } from "@nestjs/axios";
|
import { HttpService } from "@nestjs/axios";
|
||||||
|
import { ConfigModule } from "@nestjs/config";
|
||||||
|
import { ModuleRef } from "@nestjs/core";
|
||||||
import { Test } from "@nestjs/testing";
|
import { Test } from "@nestjs/testing";
|
||||||
import exp from "constants";
|
|
||||||
import { Observable, of } from "rxjs";
|
import { Observable, of } from "rxjs";
|
||||||
import { PapersController } from "src/application";
|
import { EsTime, Order } from "src/core/domain";
|
||||||
import { Order } from "src/core/domain";
|
import { PageDto } from "src/core/domain/dtos";
|
||||||
import { PageDto, SearchQueryDto } from "src/core/domain/dtos";
|
import { HttpResponseException } from "src/core/exceptions";
|
||||||
import { PageInterceptor } from "src/core/interceptors/page.interceptor";
|
import { PageInterceptor } from "src/core/interceptors/page.interceptor";
|
||||||
import { SearchService } from "src/core/services/common/search.service";
|
|
||||||
|
|
||||||
const execCtxMock = {
|
const execCtxMock = {
|
||||||
switchToHttp: jest.fn().mockReturnThis(),
|
switchToHttp: jest.fn().mockReturnThis(),
|
||||||
@ -26,18 +26,31 @@ const callHandlerMock = {
|
|||||||
|
|
||||||
describe('Unit tests for PageInterceptor', () => {
|
describe('Unit tests for PageInterceptor', () => {
|
||||||
let pageInter: PageInterceptor;
|
let pageInter: PageInterceptor;
|
||||||
let moduleRef;
|
let httpService: HttpService;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
moduleRef = await Test.createTestingModule({
|
const moduleRef = await Test.createTestingModule({
|
||||||
imports: [HttpModule],
|
providers: [
|
||||||
controllers: [PapersController],
|
{
|
||||||
providers: [SearchService, PageInterceptor],
|
provide: HttpService,
|
||||||
|
useValue: {
|
||||||
|
post: jest.fn(),
|
||||||
|
delete: jest.fn()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PageInterceptor,
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
ConfigModule.forRoot({
|
||||||
|
isGlobal: true,
|
||||||
|
cache: true,
|
||||||
|
expandVariables: true,
|
||||||
|
})
|
||||||
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
pageInter = moduleRef.get(PageInterceptor);
|
pageInter = moduleRef.get(PageInterceptor);
|
||||||
|
httpService = moduleRef.get(HttpService);
|
||||||
pageInter.getPIT = jest.fn().mockReturnValue({});
|
|
||||||
|
|
||||||
execCtxMock.getRequest.mockReturnValue({
|
execCtxMock.getRequest.mockReturnValue({
|
||||||
query: {
|
query: {
|
||||||
@ -48,19 +61,32 @@ describe('Unit tests for PageInterceptor', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
callHandlerMock.handle.mockReturnValueOnce(
|
callHandlerMock.handle.mockReturnValue(
|
||||||
of({
|
of({
|
||||||
|
hits: {
|
||||||
total: { value: 1 },
|
total: { value: 1 },
|
||||||
hits: { hits: [{}] }
|
hits: [{}]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be defined', () => {
|
it('Should be defined', () => {
|
||||||
expect(pageInter).toBeDefined();
|
expect(pageInter).toBeDefined();
|
||||||
|
expect(httpService).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('intercept()', () => {
|
describe('intercept()', () => {
|
||||||
|
let tmp;
|
||||||
|
beforeAll(() => {
|
||||||
|
tmp = pageInter.getPIT;
|
||||||
|
pageInter.getPIT = jest.fn().mockReturnValue({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
pageInter.getPIT = tmp;
|
||||||
|
});
|
||||||
|
|
||||||
it('Should return a Promise', () => {
|
it('Should return a Promise', () => {
|
||||||
expect(pageInter.intercept(execCtxMock, callHandlerMock)).toBeInstanceOf(Promise);
|
expect(pageInter.intercept(execCtxMock, callHandlerMock)).toBeInstanceOf(Promise);
|
||||||
});
|
});
|
||||||
@ -74,80 +100,233 @@ describe('Unit tests for PageInterceptor', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.todo('Should touch CallHandler.handle() method');
|
it('Should touch CallHandler.handle() method', () => {
|
||||||
|
let chHandleSpy = jest.spyOn(callHandlerMock, 'handle');
|
||||||
|
pageInter.intercept(execCtxMock, callHandlerMock);
|
||||||
// it('Should return an Observable with a page of type PageDto', (done) => {
|
expect(chHandleSpy).toBeCalled();
|
||||||
// executionContext.getRequest.mockReturnValue( { query: new SearchQueryDto('someQuery', 1, 10, 'desc') });
|
|
||||||
// callHandler.handle.mockReturnValue( of({
|
|
||||||
// total: { value: 1 },
|
|
||||||
// hits: [{},],
|
|
||||||
// }));
|
|
||||||
|
|
||||||
|
|
||||||
// expect(pageInter.intercept(executionContext, callHandler)).toBeInstanceOf(Promise);
|
|
||||||
// pageInter.intercept(executionContext, callHandler).then(res => res.subscribe((data) => {
|
|
||||||
// expect(data).toBeInstanceOf(PageDto);
|
|
||||||
// done();
|
|
||||||
// }));
|
|
||||||
// })
|
|
||||||
|
|
||||||
// it('Should hold content on the returned page', (done) => {
|
|
||||||
// executionContext.getRequest.mockReturnValueOnce( { query: new SearchQueryDto('someQuery', 1, 10, 'desc') });
|
|
||||||
// callHandler.handle.mockReturnValueOnce(of({
|
|
||||||
// total: { value: 1 },
|
|
||||||
// hits: [{dummy: 'dum'}],
|
|
||||||
// }));
|
|
||||||
|
|
||||||
// pageInter.intercept(executionContext, callHandler).then(res => res.subscribe((data) => {
|
|
||||||
// expect(data).toEqual({
|
|
||||||
// data: expect.anything(),
|
|
||||||
// meta: expect.anything(),
|
|
||||||
// });
|
|
||||||
// done();
|
|
||||||
// }));
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('Should have next page', (done) => {
|
|
||||||
// executionContext.getRequest.mockReturnValue({ query: new SearchQueryDto('someQuery', 1, 5, 'desc') });
|
|
||||||
// callHandler.handle.mockReturnValue(of({
|
|
||||||
// total: { value: 10 },
|
|
||||||
// hits: Array(10).fill({dummy: 'dum'}, 0, 10),
|
|
||||||
// }));
|
|
||||||
|
|
||||||
// pageInter.intercept(executionContext, callHandler).then(res => res.subscribe((data) => {
|
|
||||||
// expect(data.meta.hasNext).toEqual(true);
|
|
||||||
// expect(data.meta.hasPrev).toEqual(false);
|
|
||||||
// done();
|
|
||||||
// }));
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('Should have correct meta-data', (done) => {
|
|
||||||
// executionContext.getRequest.mockReturnValue({ query: new SearchQueryDto('someQuery', 2, 5, 'asc') });
|
|
||||||
// callHandler.handle.mockReturnValue(of({
|
|
||||||
// total: { value: 15 },
|
|
||||||
// hits: Array(15).fill({dummy: 'dum'}, 0, 15),
|
|
||||||
// }));
|
|
||||||
|
|
||||||
// pageInter.intercept(executionContext, callHandler).then(res => res.subscribe((data) => {
|
|
||||||
// expect(data.meta).toEqual({
|
|
||||||
// total: 15,
|
|
||||||
// pagenum: 2,
|
|
||||||
// order: Order.ASC,
|
|
||||||
// hasNext: true,
|
|
||||||
// hasPrev: true,
|
|
||||||
// pagesize: 5
|
|
||||||
// });
|
|
||||||
// done();
|
|
||||||
// }));
|
|
||||||
// });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// describe('getPIT()', () => {
|
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://localhost:${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://localhost:${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()', () => {
|
// describe('deletePIT()', () => {
|
||||||
|
// it('Should touch HttpService.delete() method', () => {
|
||||||
|
// let httpPostMock = jest.spyOn(httpService, 'delete').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://localhost:${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://localhost:${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',
|
||||||
|
// });
|
||||||
|
// });
|
||||||
// });
|
// });
|
||||||
});
|
});
|
@ -1,47 +0,0 @@
|
|||||||
import { Test, TestingModule } from "@nestjs/testing";
|
|
||||||
import { INestApplication } from "@nestjs/common";
|
|
||||||
import request from 'supertest'
|
|
||||||
import { AppModule } from "src/infrastructure/modules";
|
|
||||||
|
|
||||||
describe('E2E Testing of /papers', () => {
|
|
||||||
let app: INestApplication;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const moduleRef: TestingModule = await Test.createTestingModule({
|
|
||||||
imports: [AppModule],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
app = moduleRef.createNestApplication();
|
|
||||||
await app.init();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should return one exact item on page', async () => {
|
|
||||||
return request(app.getHttpServer())
|
|
||||||
.get('/papers/eeeb2d01-8315-454e-b33f-3d6caa25db42')
|
|
||||||
.expect(200)
|
|
||||||
.expect((res) => {
|
|
||||||
res.body.data.length === 1;
|
|
||||||
})
|
|
||||||
.expect((res) => {
|
|
||||||
res.body.data[0]._source.id === 'eeeb2d01-8315-454e-b33f-3d6caa25db42';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should return multiple items', async () => {
|
|
||||||
return request(app.getHttpServer())
|
|
||||||
.get('/papers/search?query=at&page=1')
|
|
||||||
.expect(200)
|
|
||||||
.expect((res) => {
|
|
||||||
res.body.data.length > 0;
|
|
||||||
})
|
|
||||||
.expect((res) => {
|
|
||||||
for (const value of res.body.data) {
|
|
||||||
if(Object.keys(value).length === 0) return false;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
await app.close();
|
|
||||||
})
|
|
||||||
});
|
|
@ -10,7 +10,6 @@ describe('Unit tests for SearchService', () => {
|
|||||||
let searchService: SearchService;
|
let searchService: SearchService;
|
||||||
let httpService: HttpService;
|
let httpService: HttpService;
|
||||||
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const moduleRef = await Test.createTestingModule({
|
const moduleRef = await Test.createTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
@ -114,7 +113,6 @@ describe('Unit tests for SearchService', () => {
|
|||||||
|
|
||||||
searchService.findByID('').catch((err) => {
|
searchService.findByID('').catch((err) => {
|
||||||
expect(err).toBeInstanceOf(GatewayTimeoutException);
|
expect(err).toBeInstanceOf(GatewayTimeoutException);
|
||||||
console.log(err)
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -211,7 +209,6 @@ describe('Unit tests for SearchService', () => {
|
|||||||
|
|
||||||
searchService.findByContext(null).catch((err) => {
|
searchService.findByContext(null).catch((err) => {
|
||||||
expect(err).toBeInstanceOf(GatewayTimeoutException);
|
expect(err).toBeInstanceOf(GatewayTimeoutException);
|
||||||
console.log(err)
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -228,79 +225,3 @@ describe('Unit tests for SearchService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* describe('getPIT()', () => {
|
|
||||||
it('Should touch HttpService.post() method', () => {
|
|
||||||
let postMock = jest.spyOn(httpService, 'post').mockReturnValue(of({
|
|
||||||
data: {id: '2567'},
|
|
||||||
status: 0,
|
|
||||||
statusText: '',
|
|
||||||
headers: {},
|
|
||||||
config: {},
|
|
||||||
}));
|
|
||||||
|
|
||||||
searchService.getPIT(1);
|
|
||||||
expect(postMock).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should contain correct port in the URI from .env', () => {
|
|
||||||
let postMock = jest.spyOn(httpService, 'post').mockReturnValue(of({
|
|
||||||
data: {id: '2567'},
|
|
||||||
status: 0,
|
|
||||||
statusText: '',
|
|
||||||
headers: {},
|
|
||||||
config: {},
|
|
||||||
}));
|
|
||||||
|
|
||||||
searchService.getPIT(1);
|
|
||||||
expect(postMock).toHaveBeenCalledWith(`http://localhost:${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 postMock = jest.spyOn(httpService, 'post').mockReturnValue(of({
|
|
||||||
data: {id: '2567'},
|
|
||||||
status: 0,
|
|
||||||
statusText: '',
|
|
||||||
headers: {},
|
|
||||||
config: {},
|
|
||||||
}));
|
|
||||||
|
|
||||||
let time = 2;
|
|
||||||
let unit = EsTime.sec;
|
|
||||||
|
|
||||||
searchService.getPIT(time, unit);
|
|
||||||
expect(postMock).toHaveBeenCalledWith(`http://localhost:${process.env.ES_PORT}/papers/_pit?keep_alive=${time+unit}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should return error exeception when HttpService fails', () => {
|
|
||||||
jest.spyOn(httpService, 'post').mockImplementation(() => {
|
|
||||||
throw HttpResponseException;
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(searchService.getPIT(1)).rejects.toEqual(HttpResponseException);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Should return a non-empty string when HttpService request succeedes', () => {
|
|
||||||
jest.spyOn(httpService, 'post').mockReturnValue(of({
|
|
||||||
data: {id: '2567', keep_alive: '1m'},
|
|
||||||
status: 0,
|
|
||||||
statusText: '',
|
|
||||||
headers: {},
|
|
||||||
config: {},
|
|
||||||
}));
|
|
||||||
|
|
||||||
expect(searchService.getPIT(1)).resolves.toEqual({
|
|
||||||
id: '2567',
|
|
||||||
keep_alive: '1m',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('deletePIT()', () => {
|
|
||||||
it.todo('Should fail to delete, because the requested PIT ID is invalid');
|
|
||||||
it.todo('Should call HttpService.delete() method with correct body');
|
|
||||||
});
|
|
||||||
*/
|
|
Loading…
x
Reference in New Issue
Block a user