api/src/__tests__/dealQueries.test.ts
import * as moment from 'moment';
import * as sinon from 'sinon';
import { graphqlRequest } from '../db/connection';
import {
boardFactory,
companyFactory,
conformityFactory,
customerFactory,
dealFactory,
fieldFactory,
notificationFactory,
pipelineFactory,
pipelineLabelFactory,
productFactory,
segmentFactory,
stageFactory,
userFactory
} from '../db/factories';
import {
Boards,
Deals,
PipelineLabels,
Pipelines,
Products,
Stages,
Users
} from '../db/models';
import * as elk from '../elasticsearch';
import './setup.ts';
import { BOARD_STATUSES } from '../db/models/definitions/constants';
const generateProductsData = async () => {
const field1 = await fieldFactory({ contentType: 'product' });
if (!field1) {
throw new Error('Field not found');
}
const customFieldsData = [{ field: field1._id, value: 'text' }];
const product = await productFactory({ customFieldsData });
const productNoCustomData = await productFactory();
const productId = product._id;
const productsData = [
{
productId,
currency: 'USD',
amount: 200,
tickUsed: true
},
{
productId,
currency: 'USD'
},
{
productId: productNoCustomData._id
},
{
productId: undefined
}
];
return {
productsData,
productId
};
};
describe('dealQueries', () => {
const commonDealFields = `
_id
name
stageId
assignedUserIds
amount
closeDate
description
companies { _id }
customers { _id }
products
productsData
assignedUsers
labels { _id }
hasNotified
isWatched
stage { _id }
boardId
pipeline { _id }
userId
createdUser { _id }
customPropertyTexts
`;
const qryDealFilter = `
query deals(
$search: String
$stageId: String
$pipelineId: String
$assignedUserIds: [String]
$customerIds: [String]
$companyIds: [String]
$productIds: [String]
$closeDateType: String
$mainType: String
$mainTypeId: String
$isRelated: Boolean
$isSaved: Boolean
$date: ItemDate
$labelIds: [String]
$initialStageId: String
$userIds: [String]
$assignedToMe: String
$segment: String
$startDate: String
$endDate: String
$hasStartAndCloseDate: Boolean
) {
deals(
search: $search
stageId: $stageId
pipelineId: $pipelineId
customerIds: $customerIds
assignedUserIds: $assignedUserIds
companyIds: $companyIds
productIds: $productIds
closeDateType: $closeDateType
conformityMainType: $mainType
conformityMainTypeId: $mainTypeId
conformityIsRelated: $isRelated
conformityIsSaved: $isSaved
date: $date
labelIds: $labelIds
initialStageId: $initialStageId
userIds: $userIds
assignedToMe: $assignedToMe
segment: $segment
startDate: $startDate
endDate: $endDate
hasStartAndCloseDate: $hasStartAndCloseDate
) {
_id
}
}
`;
afterEach(async () => {
// Clearing test data
await Boards.deleteMany({});
await Pipelines.deleteMany({});
await Stages.deleteMany({});
await Deals.deleteMany({});
});
test('Filter by initialStageId', async () => {
const deal = await dealFactory();
const response = await graphqlRequest(qryDealFilter, 'deals', {
initialStageId: deal.stageId
});
expect(response.length).toBe(1);
});
test('Filter by search', async () => {
await dealFactory({ searchText: 'name' });
const response = await graphqlRequest(qryDealFilter, 'deals', {
search: 'name'
});
expect(response.length).toBe(1);
});
test('Filter by next day', async () => {
const tomorrow = moment()
.add(1, 'day')
.endOf('day')
.format('YYYY-MM-DD');
await dealFactory({ closeDate: new Date(tomorrow) });
const response = await graphqlRequest(qryDealFilter, 'deals', {
closeDateType: 'nextDay'
});
expect(response.length).toBe(1);
});
test('Deal filter by next week', async () => {
const nextWeek = moment()
.day(8)
.format('YYYY-MM-DD');
await dealFactory({ closeDate: new Date(nextWeek) });
const response = await graphqlRequest(qryDealFilter, 'deals', {
closeDateType: 'nextWeek'
});
expect(response.length).toBe(1);
});
test('Deal filter by next month', async () => {
const nextMonth = moment()
.add(1, 'months')
.format('YYYY-MM-01');
await dealFactory({ closeDate: new Date(nextMonth) });
const response = await graphqlRequest(qryDealFilter, 'deals', {
closeDateType: 'nextMonth'
});
expect(response.length).toBe(1);
});
test('Deal filter by has no close date', async () => {
await dealFactory({ noCloseDate: true });
const response = await graphqlRequest(qryDealFilter, 'deals', {
closeDateType: 'noCloseDate'
});
expect(response.length).toBe(1);
});
test('Deal filter by overdue', async () => {
const yesterday = moment()
.utc()
.subtract(1, 'days')
.toDate();
await dealFactory({ closeDate: yesterday });
const response = await graphqlRequest(qryDealFilter, 'deals', {
closeDateType: 'overdue'
});
expect(response.length).toBe(1);
});
test('Deal filter by products', async () => {
const { productsData, productId } = await generateProductsData();
await dealFactory({ productsData });
const response = await graphqlRequest(qryDealFilter, 'deals', {
productIds: [productId]
});
expect(response.length).toBe(1);
});
test('Deal filter by hasStartAndCloseDate', async () => {
await dealFactory({ closeDate: new Date() });
await dealFactory({ closeDate: new Date(), startDate: new Date() });
const response = await graphqlRequest(qryDealFilter, 'deals', {
hasStartAndCloseDate: true
});
expect(response.length).toBe(1);
});
test('Deal filter by team members', async () => {
const { _id } = await userFactory();
await dealFactory({ assignedUserIds: [_id] });
let response = await graphqlRequest(qryDealFilter, 'deals', {
assignedUserIds: [_id]
});
expect(response.length).toBe(1);
await dealFactory();
// Filter by assigned to no one
response = await graphqlRequest(qryDealFilter, 'deals', {
assignedUserIds: ['']
});
expect(response.length).toBe(0);
});
test('Deal filter by customers', async () => {
process.env.ELK_SYNCER = 'false';
const customer1 = await customerFactory();
const customer2 = await customerFactory();
const user = await userFactory();
const deal = await dealFactory();
await notificationFactory({
contentTypeId: deal._id,
contentType: 'deal',
receiver: user
});
await conformityFactory({
mainType: 'deal',
mainTypeId: deal._id,
relType: 'customer',
relTypeId: customer1._id
});
await conformityFactory({
mainType: 'deal',
mainTypeId: deal._id,
relType: 'customer',
relTypeId: customer2._id
});
await conformityFactory({
mainType: 'customer',
mainTypeId: customer1._id,
relType: 'deal',
relTypeId: deal._id
});
await conformityFactory({
mainType: 'customer',
mainTypeId: customer2._id,
relType: 'deal',
relTypeId: deal._id
});
let response = await graphqlRequest(
qryDealFilter,
'deals',
{
customerIds: [customer1._id, customer2._id]
},
{ user }
);
expect(response.length).toBe(1);
const customer3 = await customerFactory();
response = await graphqlRequest(qryDealFilter, 'deals', {
customerIds: [customer3._id]
});
expect(response.length).toBe(0);
});
test('Deal filter by companies', async () => {
const { _id } = await companyFactory();
const deal = await dealFactory();
await conformityFactory({
mainType: 'company',
mainTypeId: _id,
relType: 'deal',
relTypeId: deal._id
});
// another company choosed
await conformityFactory({
mainType: 'deal',
mainTypeId: deal._id,
relType: 'company',
relTypeId: (await companyFactory())._id
});
let response = await graphqlRequest(qryDealFilter, 'deals', {
companyIds: [_id]
});
expect(response.length).toBe(1);
const company1 = await companyFactory();
response = await graphqlRequest(qryDealFilter, 'deals', {
companyIds: [company1._id]
});
expect(response.length).toBe(0);
});
test('Deal filter by label', async () => {
const { _id } = await pipelineLabelFactory();
await dealFactory({ labelIds: [_id] });
let response = await graphqlRequest(qryDealFilter, 'deals', {
labelIds: [_id]
});
expect(response.length).toBe(1);
// filtering nolabelled deals
await dealFactory();
response = await graphqlRequest(qryDealFilter, 'deals', { labelIds: [''] });
expect(response.length).toBe(1);
});
test('Deal filter by assignedToMe', async () => {
const user = await userFactory({});
await dealFactory({ assignedUserIds: [user._id] });
await dealFactory({});
const response = await graphqlRequest(
qryDealFilter,
'deals',
{ assignedToMe: 'true' },
{ user }
);
expect(response.length).toBe(1);
});
test('Deal filter by segment', async () => {
const segment = await segmentFactory({
contentType: 'deal'
});
const deal = await dealFactory({});
await dealFactory({});
const mock = sinon.stub(elk, 'fetchElk').callsFake(() => {
return Promise.resolve({ hits: { hits: [{ _id: deal._id }] } });
});
const response = await graphqlRequest(qryDealFilter, 'deals', {
segment: segment._id
});
expect(response.length).toBe(1);
mock.restore();
});
test('Deal filter by date range', async () => {
await dealFactory({ closeDate: new Date('2020-01-06') });
await dealFactory({ closeDate: new Date('2020-01-10') });
let response = await graphqlRequest(qryDealFilter, 'deals', {
startDate: '2020-01-09',
endDate: '2020-01-11'
});
expect(response.length).toBe(1);
response = await graphqlRequest(qryDealFilter, 'deals', {
endDate: '2020-01-11'
});
expect(response.length).toBe(2);
});
test('Deal filter by date', async () => {
const board = await boardFactory();
const pipeline = await pipelineFactory({ boardId: board._id });
const stage = await stageFactory({ pipelineId: pipeline._id });
const date = new Date();
await dealFactory({ closeDate: date, stageId: stage._id });
const args = {
date: { year: date.getUTCFullYear(), month: date.getUTCMonth() },
pipelineId: pipeline._id
};
const response = await graphqlRequest(qryDealFilter, 'deals', args);
expect(response.length).toBe(1);
});
test('Deals filtered by created user', async () => {
const board = await boardFactory();
const pipeline = await pipelineFactory({ boardId: board._id });
const stage = await stageFactory({ pipelineId: pipeline._id });
const user = await userFactory();
const dealParams = { userId: user._id, stageId: stage._id };
await dealFactory(dealParams);
await dealFactory(dealParams);
await dealFactory(dealParams);
const response = await graphqlRequest(qryDealFilter, 'deals', {
userIds: [user._id]
});
expect(response.length).toBe(3);
});
test('Deals filtered by pipeline', async () => {
const board = await boardFactory();
const pipeline = await pipelineFactory({ boardId: board._id });
const stage = await stageFactory({ pipelineId: pipeline._id });
const user = await userFactory();
const dealParams = { userId: user._id, stageId: stage._id };
await dealFactory(dealParams);
await dealFactory(dealParams);
await dealFactory({});
const response = await graphqlRequest(qryDealFilter, 'deals', {
pipelineId: pipeline._id
});
expect(response.length).toBe(2);
});
test('Deals', async () => {
const board = await boardFactory();
const pipeline = await pipelineFactory({ boardId: board._id });
const stage = await stageFactory({ pipelineId: pipeline._id });
const currentUser = await userFactory({});
const field = await fieldFactory({
showInCard: true,
contentType: 'deal'
});
const args = { stageId: stage._id };
const deal = await dealFactory({ ...args, name: 'b' });
await dealFactory({ ...args, name: 'c' });
await dealFactory({ ...args, name: 'a' });
await dealFactory({
...args,
name: 'd',
customFieldsData: [{ field: field._id, value: 'test' }]
});
Object.assign(args, { pipelineId: stage.pipelineId });
const qry = `
query deals($stageId: String!, $pipelineId: String, $sortField: String, $sortDirection: Int) {
deals(stageId: $stageId, pipelineId: $pipelineId, sortField: $sortField, sortDirection: $sortDirection) {
_id
name
customPropertyTexts
}
}
`;
let response = await graphqlRequest(qry, 'deals', args, {
user: currentUser
});
expect(response.length).toBe(4);
response = await graphqlRequest(qry, 'deals', {
...args,
sortField: 'name',
sortDirection: 1
});
expect(response[0].name).toBe('a');
expect(response[1].name).toBe('b');
expect(response[2].name).toBe('c');
await Pipelines.updateOne(
{ _id: pipeline._id },
{ $set: { isCheckUser: true } }
);
response = await graphqlRequest(qry, 'deals', args, { user: currentUser });
expect(response.length).toBe(0);
await Deals.updateOne(
{ _id: deal._id },
{ $set: { assignedUserIds: [currentUser._id] } }
);
response = await graphqlRequest(qry, 'deals', args, { user: currentUser });
expect(response.length).toBe(1);
});
test('Deals total count', async () => {
const stage = await stageFactory({});
const currentUser = await userFactory({});
const args = { stageId: stage._id };
await dealFactory(args);
await dealFactory(args);
const qry = `
query dealsTotalCount($stageId: String!) {
dealsTotalCount(stageId: $stageId)
}
`;
const response = await graphqlRequest(qry, 'dealsTotalCount', args, {
user: currentUser
});
expect(response).toBe(2);
});
test('Deal detail', async () => {
const currentUser = await userFactory({});
const board = await boardFactory();
const pipeline = await pipelineFactory({ boardId: board._id });
const stage = await stageFactory({ pipelineId: pipeline._id });
const { productsData } = await generateProductsData();
const field1 = await fieldFactory({
showInCard: true,
contentType: 'deal'
});
const field2 = await fieldFactory({
showInCard: false,
contentType: 'deal'
});
const deal = await dealFactory({
stageId: stage._id,
watchedUserIds: [currentUser._id],
productsData,
customFieldsData: [
{ field: field1._id, value: 'test1' },
{ field: field2._id, value: 'test2' }
]
});
const args = { _id: deal._id };
const qry = `
query dealDetail($_id: String!) {
dealDetail(_id: $_id) {
${commonDealFields}
}
}
`;
let response = await graphqlRequest(qry, 'dealDetail', args, {
user: currentUser
});
expect(response._id).toBe(deal._id);
expect(response.customPropertyTexts.length).toBe(1);
await Pipelines.updateOne(
{ _id: pipeline._id },
{ $set: { visibility: 'private' } }
);
try {
response = await graphqlRequest(qry, 'dealDetail', args, {
user: currentUser
});
} catch (e) {
expect(e[0].message).toEqual('You do not have permission to view.');
}
await Pipelines.updateOne(
{ _id: pipeline._id },
{ $set: { memberIds: [currentUser._id] } }
);
response = await graphqlRequest(qry, 'dealDetail', args, {
user: currentUser
});
expect(response._id).toBe(deal._id);
await Pipelines.updateOne(
{ _id: pipeline._id },
{ $set: { visibility: 'public', isCheckUser: true } }
);
try {
response = await graphqlRequest(qry, 'dealDetail', args, {
user: currentUser
});
} catch (e) {
expect(e[0].message).toEqual('You do not have permission to view.');
}
await Pipelines.updateOne(
{ _id: pipeline._id },
{ $set: { excludeCheckUserIds: [currentUser._id] } }
);
response = await graphqlRequest(qry, 'dealDetail', args, {
user: currentUser
});
expect(response._id).toBe(deal._id);
await Pipelines.updateOne(
{ _id: pipeline._id },
{ $set: { excludeCheckUserIds: [], isCheckUser: true } }
);
await Deals.updateOne(
{ _id: deal._id },
{ $set: { assignedUserIds: [currentUser._id] } }
);
response = await graphqlRequest(qry, 'dealDetail', args, {
user: currentUser
});
expect(response._id).toBe(deal._id);
expect(response.isWatched).toBe(true);
});
test('Deal total amount', async () => {
const board = await boardFactory();
const pipeline = await pipelineFactory({ boardId: board._id });
const stage = await stageFactory({ pipelineId: pipeline._id });
const product = await productFactory();
const productsData = [
{
productId: product._id,
currency: 'USD',
amount: 200,
tickUsed: true
}
];
const args = {
stageId: stage._id,
productsData
};
await dealFactory(args);
await dealFactory(args);
await dealFactory(args);
const filter = { pipelineId: pipeline._id };
const qry = `
query dealsTotalAmounts($pipelineId: String) {
dealsTotalAmounts(pipelineId: $pipelineId) {
_id
name
currencies {
name
amount
}
}
}
`;
const response = await graphqlRequest(qry, 'dealsTotalAmounts', filter);
expect(response[0].currencies[0].name).toBe('USD');
expect(response[0].currencies[0].amount).toBe(600);
});
test('Deal (=ticket, task) filter by conformity saved and related', async () => {
const { _id } = await companyFactory();
const deal = await dealFactory();
await dealFactory();
await customerFactory({});
await companyFactory({});
let response = await graphqlRequest(qryDealFilter, 'deals', {
mainType: 'company',
mainTypeId: _id,
isSaved: true
});
expect(response.length).toBe(0);
response = await graphqlRequest(qryDealFilter, 'deals', {
mainType: 'company',
mainTypeId: _id,
isRelated: true
});
expect(response.length).toBe(0);
await conformityFactory({
mainType: 'company',
mainTypeId: _id,
relType: 'deal',
relTypeId: deal._id
});
const customer = await customerFactory({});
await conformityFactory({
mainType: 'company',
mainTypeId: _id,
relType: 'customer',
relTypeId: customer._id
});
response = await graphqlRequest(qryDealFilter, 'deals', {
mainType: 'company',
mainTypeId: _id,
isSaved: true
});
expect(response.length).toBe(1);
response = await graphqlRequest(qryDealFilter, 'deals', {
mainType: 'company',
mainTypeId: _id,
isRelated: true
});
expect(response.length).toBe(0);
response = await graphqlRequest(qryDealFilter, 'deals', {
mainType: 'customer',
mainTypeId: customer._id,
isSaved: true
});
expect(response.length).toBe(0);
response = await graphqlRequest(qryDealFilter, 'deals', {
mainType: 'customer',
mainTypeId: customer._id,
isRelated: true
});
expect(response.length).toBe(1);
});
test('Deal filter by customers and companies', async () => {
const customer = await customerFactory();
const company = await companyFactory();
const deal = await dealFactory();
const deal1 = await dealFactory();
const deal2 = await dealFactory();
await conformityFactory({
mainType: 'deal',
mainTypeId: deal._id,
relType: 'customer',
relTypeId: customer._id
});
await conformityFactory({
mainType: 'company',
mainTypeId: company._id,
relType: 'deal',
relTypeId: deal._id
});
await conformityFactory({
mainType: 'deal',
mainTypeId: deal1._id,
relType: 'customer',
relTypeId: customer._id
});
await conformityFactory({
mainType: 'company',
mainTypeId: company._id,
relType: 'deal',
relTypeId: deal2._id
});
const response = await graphqlRequest(qryDealFilter, 'deals', {
customerIds: [customer._id],
companyIds: [company._id]
});
expect(response.length).toBe(1);
});
test('Get archived deals', async () => {
const pipeline = await pipelineFactory();
const stage = await stageFactory({ pipelineId: pipeline._id });
const user = await userFactory();
const label = await pipelineLabelFactory();
const product = await productFactory();
const args = {
stageId: stage._id,
status: BOARD_STATUSES.ARCHIVED,
userId: user._id,
priority: 'High',
assignedUserIds: [user._id],
labelIds: [label._id],
productsData: [{ productId: product._id }]
};
await dealFactory({
...args,
name: 'james',
closeDate: new Date('2000-01-02')
});
await dealFactory({
...args,
name: 'jone',
closeDate: new Date('2000-01-03')
});
await dealFactory({
...args,
name: 'gerrad',
closeDate: new Date('2000-01-04')
});
const qry = `
query archivedDeals(
$pipelineId: String!,
$search: String,
$page: Int,
$perPage: Int,
$userIds: [String],
$priorities: [String],
$assignedUserIds: [String],
$labelIds: [String],
$productIds: [String],
$startDate: String,
$endDate: String
) {
archivedDeals(
pipelineId: $pipelineId
search: $search
page: $page
perPage: $perPage
userIds: $userIds
priorities: $priorities
assignedUserIds: $assignedUserIds
labelIds: $labelIds
productIds: $productIds
startDate: $startDate
endDate: $endDate
) {
_id
}
}
`;
let response = await graphqlRequest(qry, 'archivedDeals', {
pipelineId: pipeline._id,
userIds: [user._id],
priorities: ['High'],
assignedUserIds: [user._id],
labelIds: [label._id],
productIds: [product._id]
});
expect(response.length).toBe(3);
response = await graphqlRequest(qry, 'archivedDeals', {
pipelineId: pipeline._id,
search: 'james'
});
expect(response.length).toBe(1);
response = await graphqlRequest(qry, 'archivedDeals', {
pipelineId: 'fakeId'
});
expect(response.length).toBe(0);
response = await graphqlRequest(qry, 'archivedDeals', {
pipelineId: pipeline._id,
startDate: '2000-01-03',
endDate: '2000-01-03'
});
expect(response.length).toBe(1);
response = await graphqlRequest(qry, 'archivedDeals', {
pipelineId: pipeline._id,
endDate: '2000-01-03'
});
expect(response.length).toBe(2);
await Users.deleteMany({});
await PipelineLabels.deleteMany({});
await Products.deleteMany({});
});
test('Get archived deals count', async () => {
const pipeline = await pipelineFactory();
const stage = await stageFactory({ pipelineId: pipeline._id });
const args = {
stageId: stage._id,
status: BOARD_STATUSES.ARCHIVED
};
await dealFactory({ ...args, name: 'james' });
await dealFactory({ ...args, name: 'jone' });
await dealFactory({ ...args, name: 'gerrad' });
const qry = `
query archivedDealsCount(
$pipelineId: String!,
$search: String
) {
archivedDealsCount(
pipelineId: $pipelineId
search: $search
)
}
`;
let response = await graphqlRequest(qry, 'archivedDealsCount', {
pipelineId: pipeline._id
});
expect(response).toBe(3);
response = await graphqlRequest(qry, 'archivedDealsCount', {
pipelineId: pipeline._id,
search: 'james'
});
expect(response).toBe(1);
response = await graphqlRequest(qry, 'archivedDealsCount', {
pipelineId: 'fakeId'
});
expect(response).toBe(0);
});
});