Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_server
1 result
Show changes
Showing
with 1538 additions and 96 deletions
import { HttpModule, HttpStatus } from '@nestjs/common';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { INewsletterSubscription } from './interface/newsletter-subscription.interface';
import { NewsletterSubscription } from './newsletter-subscription.schema';
import { NewsletterService } from './newsletter.service';
describe('NewsletterService', () => {
let service: NewsletterService;
const mockNewsletterModel = {
create: jest.fn(),
deleteOne: jest.fn(),
countDocuments: jest.fn(),
findOne: jest.fn(),
exec: jest.fn(),
find: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule],
providers: [
NewsletterService,
{
provide: getModelToken(NewsletterSubscription.name),
useValue: mockNewsletterModel,
},
],
}).compile();
service = module.get<NewsletterService>(NewsletterService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('newsletterSubscribe', () => {
it('it should not add subscription for email test2@test.com : already exist', async () => {
const result = { email: 'test2@test.com' } as INewsletterSubscription;
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
try {
await service.newsletterSubscribe('test2@test.com');
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('Email already exists');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
}
});
it('it should add a subscription for email test2@test.com', async () => {
const result: INewsletterSubscription = { email: 'test2@test.com' } as INewsletterSubscription;
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => undefined)
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
mockNewsletterModel.create.mockResolvedValueOnce(_doc);
const subscription = await service.newsletterSubscribe('test2@test.com');
expect(subscription).toEqual({ email: 'test2@test.com' });
});
});
describe('newsletterUnsubscribe', () => {
it('it should not remove subscription for email test@test.com : does not exist', async () => {
const result: INewsletterSubscription = undefined;
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
try {
await service.newsletterUnsubscribe('test@test.com');
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('Invalid email');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
}
});
it('it should remove a subscription for email test2@test.com', async () => {
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' };
const result = {
email: 'test2@test.com',
deleteOne: async () => _doc,
} as INewsletterSubscription;
jest
.spyOn(service, 'findOne')
.mockImplementationOnce(async (): Promise<INewsletterSubscription | undefined> => result);
const subscription = await service.newsletterUnsubscribe('test2@test.com');
expect(subscription).toEqual(_doc);
});
});
describe('countNewsletterSubscriptions', () => {
it('it should count subscriptions', async () => {
mockNewsletterModel.countDocuments.mockResolvedValueOnce(69);
const count = await service.countNewsletterSubscriptions();
expect(count).toEqual(69);
});
});
describe('findOne', () => {
it('it should not find a subscription with email test@test.com', async () => {
mockNewsletterModel.findOne.mockResolvedValueOnce(undefined);
const findOneEmail = await service.findOne('test@test.com');
expect(findOneEmail).toEqual(undefined);
});
it('it should find a subscription with email test2@test.com', async () => {
const _doc = { _id: 'a1aaaaa1a1', email: 'test2@test.com' } as INewsletterSubscription;
mockNewsletterModel.findOne.mockResolvedValueOnce(_doc);
const findOneEmail = await service.findOne('test2@test.com');
expect(findOneEmail).toEqual(_doc);
});
});
describe('findAll', () => {
it('it should find all', async () => {
const _docs = [{ _id: 'a1aaaaa1a1', email: 'test2@test.com' } as INewsletterSubscription];
mockNewsletterModel.find.mockResolvedValueOnce(_docs);
const findOneEmail = await service.findAll();
expect(findOneEmail).toEqual(_docs);
});
});
describe('searchNewsletterSubscription', () => {
it('it should find 2 search result', async () => {
const _docs = [
{ _id: 'a1aaaaa1a1', email: 'test2@test.com' } as INewsletterSubscription,
{ _id: 'bbbbb', email: 'test@test.com' } as INewsletterSubscription,
];
mockNewsletterModel.find.mockResolvedValueOnce(_docs);
const findOneEmail = await service.searchNewsletterSubscription('test');
expect(findOneEmail.length).toBe(2);
});
});
});
......@@ -15,40 +15,31 @@ export class NewsletterService {
if (existingEmail) {
throw new HttpException('Email already exists', HttpStatus.BAD_REQUEST);
}
const createSubscription = new this.newsletterSubscriptionModel({ email: email });
createSubscription.save();
return await this.findOne(email);
await this.newsletterSubscriptionModel.create({ email: email });
return this.findOne(email);
}
public async newsletterUnsubscribe(email: string): Promise<NewsletterSubscription> {
const subscription = await this.newsletterSubscriptionModel.findOne({ email: email }).exec();
const subscription = await this.findOne(email);
if (!subscription) {
throw new HttpException('Invalid email', HttpStatus.BAD_REQUEST);
}
return subscription.deleteOne();
}
public async findOne(mail: string): Promise<NewsletterSubscription | undefined> {
return this.newsletterSubscriptionModel.findOne({ email: mail }).exec();
public async findOne(mail: string): Promise<INewsletterSubscription | undefined> {
return this.newsletterSubscriptionModel.findOne({ email: mail });
}
public async searchNewsletterSubscription(searchString: string): Promise<NewsletterSubscriptionDocument[]> {
return this.newsletterSubscriptionModel.find({ email: new RegExp(searchString, 'i') }).exec();
return this.newsletterSubscriptionModel.find({ email: new RegExp(searchString, 'i') });
}
public async countNewsletterSubscriptions(): Promise<number> {
return this.newsletterSubscriptionModel.countDocuments({}).exec();
}
public async deleteOneEmail(mail: string): Promise<NewsletterSubscription | undefined> {
const subscription = await this.newsletterSubscriptionModel.findOne({ email: mail }).exec();
if (!subscription) {
throw new HttpException('Invalid email', HttpStatus.BAD_REQUEST);
}
return subscription.deleteOne();
return this.newsletterSubscriptionModel.countDocuments({});
}
public async findAll(): Promise<NewsletterSubscription[]> {
return await this.newsletterSubscriptionModel.find().exec();
return this.newsletterSubscriptionModel.find();
}
}
import { HttpModule } from '@nestjs/common';
import { HttpModule, HttpService } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { of } from 'rxjs';
import { ConfigurationModule } from '../configuration/configuration.module';
import { PostsController } from './posts.controller';
import { PostsService } from './posts.service';
import { PostWithMeta } from './schemas/postWithMeta.schema';
import { AxiosResponse } from 'axios';
describe('PostsController', () => {
let controller: PostsController;
const httpServiceMock = {
get: jest.fn(),
};
const postServiceMock = {
getLocationTags: jest.fn(),
getPublicTags: jest.fn(),
getRegularTags: jest.fn(),
formatPosts: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [ConfigurationModule, HttpModule],
providers: [PostsService],
providers: [
{
provide: PostsService,
useValue: postServiceMock,
},
{
provide: HttpService,
useValue: httpServiceMock,
},
],
controllers: [PostsController],
}).compile();
......@@ -22,23 +43,383 @@ describe('PostsController', () => {
expect(controller).toBeDefined();
});
it('should get pending attachments', async () => {
const result:PostWithMeta = {posts:[], meta:{pagination: null}};
const query = "";
jest.spyOn(controller, 'findAll').mockImplementation(async (): Promise<any> => result);
expect(await controller.findAll(query)).toBe(result);
describe('findAll', () => {
it('should get all posts', async () => {
const query = '';
const result: AxiosResponse = {
data: {
posts: [
{
id: '61c4847b0ff4550001505090',
uuid: 'f4ee5a37-a343-4cad-8a32-3f6cf87f9569',
title: 'Only feature image',
slug: 'only-feature-image',
html: '<p>Test</p>',
comment_id: '61c4847b0ff4550001505090',
feature_image: 'http://localhost:2368/content/images/2021/12/dacc-4.png',
featured: false,
visibility: 'public',
email_recipient_filter: 'none',
created_at: '2021-12-23T14:15:23.000+00:00',
updated_at: '2021-12-23T14:15:45.000+00:00',
published_at: '2021-12-23T14:15:45.000+00:00',
custom_excerpt: null,
codeinjection_head: null,
codeinjection_foot: null,
custom_template: null,
canonical_url: null,
tags: [Array],
authors: [Array],
primary_author: [Object],
primary_tag: [Object],
url: 'http://localhost:2368/only-feature-image/',
excerpt:
'« Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus.\n' +
'Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed,\n' +
'dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper\n' +
'congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est\n' +
'eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu\n' +
'massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut\n' +
'in risus volutpat libero pharetra tem',
reading_time: 2,
access: true,
send_email_when_published: false,
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
email_subject: null,
frontmatter: null,
},
{
id: '61c4847b0ff4550001505090',
uuid: 'f4ee5a37-a343-4cad-8a32-3f6cf87f9569',
title: 'Only test image',
slug: 'only-test-image',
html: '<p>Test 2</p>',
comment_id: '61c4847b0ff4550001505090',
feature_image: 'http://localhost:2368/content/images/2021/12/test.png',
featured: false,
visibility: 'public',
email_recipient_filter: 'none',
created_at: '2021-12-23T14:15:23.000+00:00',
updated_at: '2021-12-23T14:15:45.000+00:00',
published_at: '2021-12-23T14:15:45.000+00:00',
custom_excerpt: null,
codeinjection_head: null,
codeinjection_foot: null,
custom_template: null,
canonical_url: null,
tags: [Array],
authors: [Array],
primary_author: [Object],
primary_tag: [Object],
url: 'http://localhost:2368/only-feature-image/',
excerpt:
'« Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus.\n' +
'Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed,\n' +
'dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper\n' +
'congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est\n' +
'eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu\n' +
'massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut\n' +
'in risus volutpat libero pharetra tem',
reading_time: 2,
access: true,
send_email_when_published: false,
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
email_subject: null,
frontmatter: null,
},
{
id: '61c4847b0ff4550001505090',
uuid: 'f4ee5a37-a343-4cad-8a32-3f6cf87f9569',
title: 'Only toto image',
slug: 'only-toto-image',
html: '<p>Test 3</p>',
comment_id: '61c4847b0ff4550001505090',
feature_image: 'http://localhost:2368/content/images/2021/12/dacc-4.png',
featured: false,
visibility: 'public',
email_recipient_filter: 'none',
created_at: '2021-12-23T14:15:23.000+00:00',
updated_at: '2021-12-23T14:15:45.000+00:00',
published_at: '2021-12-23T14:15:45.000+00:00',
custom_excerpt: null,
codeinjection_head: null,
codeinjection_foot: null,
custom_template: null,
canonical_url: null,
tags: [Array],
authors: [Array],
primary_author: [Object],
primary_tag: [Object],
url: 'http://localhost:2368/only-feature-image/',
excerpt:
'« Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus.\n' +
'Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed,\n' +
'dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper\n' +
'congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est\n' +
'eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu\n' +
'massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut\n' +
'in risus volutpat libero pharetra tem',
reading_time: 2,
access: true,
send_email_when_published: false,
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
email_subject: null,
frontmatter: null,
},
],
meta: { pagination: { page: 1, limit: 15, pages: 1, total: 2, next: null, prev: null } },
},
status: 200,
statusText: 'OK',
headers: {},
config: {},
};
jest.spyOn(httpServiceMock, 'get').mockImplementationOnce(() => of(result));
const response = await controller.findAll(query);
expect(response.posts.length).toEqual(3);
expect(response.meta.pagination.limit).toEqual(15);
expect(response.meta.pagination.page).toEqual(1);
expect(response.meta.pagination.total).toEqual(2);
});
});
it('should get pending attachments', async () => {
const result = { posts:[] };
jest.spyOn(controller, 'findAllTags').mockImplementation(async (): Promise<any> => result);
expect(await controller.findAllTags()).toBe(result);
describe('findAllTags', () => {
it('should get all tags', async () => {
postServiceMock.getLocationTags.mockImplementationOnce(() => [
{
id: '61b74b2c0d3b9800018ca3df',
name: 'oullins',
slug: 'oullins',
description: 'commune',
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:24.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/tag/oullins/',
},
{
id: '61b74b2c0d3b9800018ca3df',
name: 'oullins',
slug: 'oullins',
description: 'commune',
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:24.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/tag/oullins/',
},
{
id: '61b74b2c0d3b9800018ca3e0',
name: 'Bron',
slug: 'bron',
description: 'commune',
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:24.000Z',
updated_at: '2021-12-13T13:31:24.000Z',
url: 'http://localhost:2368/404/',
},
]);
postServiceMock.getPublicTags.mockImplementationOnce(() => [
{
id: '61b74b2d0d3b9800018ca3f6',
name: 'Séniors (+ de 65ans)',
slug: 'seniors-de-65ans',
description: 'public',
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:25.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/404/',
},
{
id: '61b74b2d0d3b9800018ca3f7',
name: 'Allophones',
slug: 'allophones',
description: 'public',
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:25.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/404/',
},
]);
postServiceMock.getRegularTags.mockImplementationOnce(() => [
{
id: '61b74b2d0d3b9800018ca3fa',
name: 'Études',
slug: 'etudes',
description: null,
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:25.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/tag/etudes/',
},
]);
const result = await controller.findAllTags();
expect(result.commune.length).toBe(3);
expect(result.others.length).toBe(1);
expect(result.public.length).toBe(2);
});
});
it('should get pending attachments', async () => {
const result = { public:[], comune:[], others:[] };
const id = "78945945"
jest.spyOn(controller, 'getPostbyId').mockImplementation(async (): Promise<any> => result);
expect(await controller.getPostbyId(id)).toBe(result);
describe('getPostbyId', () => {
it('should get post Hello by id 61c4847b0ff4550001505090', async () => {
const data = [
{
id: '61c4847b0ff4550001505090',
uuid: 'f4ee5a37-a343-4cad-8a32-3f6cf87f9569',
title: 'Hello',
slug: 'hello',
html: '<p>Test</p>',
comment_id: '61c4847b0ff4550001505090',
feature_image: 'http://localhost:2368/content/images/2021/12/dacc-4.png',
featured: false,
visibility: 'public',
email_recipient_filter: 'none',
created_at: '2021-12-23T14:15:23.000+00:00',
updated_at: '2021-12-23T14:15:45.000+00:00',
published_at: '2021-12-23T14:15:45.000+00:00',
custom_excerpt: null,
codeinjection_head: null,
codeinjection_foot: null,
custom_template: null,
canonical_url: null,
tags: [Array],
authors: [Array],
primary_author: [Object],
primary_tag: [Object],
url: 'http://localhost:2368/hello/',
excerpt:
'« Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus.\n' +
'Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed,\n' +
'dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper\n' +
'congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est\n' +
'eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu\n' +
'massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut\n' +
'in risus volutpat libero pharetra tem',
reading_time: 2,
access: true,
send_email_when_published: false,
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
email_subject: null,
frontmatter: null,
},
];
const axiosResult: AxiosResponse = {
data: {
posts: data,
},
status: 200,
statusText: 'OK',
headers: {},
config: {},
};
httpServiceMock.get.mockImplementationOnce(() => of(axiosResult));
postServiceMock.formatPosts.mockImplementationOnce(() => data);
const result = await (await controller.getPostbyId('61c4847b0ff4550001505090')).toPromise();
expect(result).toStrictEqual({ posts: [data] });
});
});
});
......@@ -9,6 +9,7 @@ import { PostWithMeta } from './schemas/postWithMeta.schema';
@Controller('posts')
export class PostsController {
private readonly logger = new Logger(PostsController.name);
constructor(private readonly httpService: HttpService, private readonly postsService: PostsService) {}
@Get()
......@@ -36,7 +37,7 @@ export class PostsController {
.pipe(
map((response) => response.data),
catchError((err) => {
Logger.error(err);
this.logger.error(err);
throw new HttpException('Invalid ghost configuration', HttpStatus.BAD_REQUEST);
})
);
......
import { HttpModule } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { ConfigurationModule } from '../configuration/configuration.module';
import { TagEnum } from './enums/tag.enum';
import { PostsService } from './posts.service';
import { Tag } from './schemas/tag.schema';
import * as _ from 'lodash';
import { Post } from './schemas/post.schema';
describe('PostsService', () => {
let service: PostsService;
// let configService: ConfigurationServiceMock;
const locationtags = [
{
id: '61b74b2c0b9800018ca3df',
name: 'oullins',
slug: 'oullins',
description: 'commune',
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:24.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/tag/oullins/',
},
{
id: '61b74b2c0d9800018ca3df',
name: 'oullins',
slug: 'oullins',
description: 'commune',
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:24.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/tag/oullins/',
},
{
id: '61b74b2d3b9800018ca3e0',
name: 'Bron',
slug: 'bron',
description: 'commune',
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:24.000Z',
updated_at: '2021-12-13T13:31:24.000Z',
url: 'http://localhost:2368/404/',
},
];
const publictags = [
{
id: '61b74b2d0d3b9800018ca3f6',
name: 'Séniors (+ de 65ans)',
slug: 'seniors-de-65ans',
description: 'public',
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:25.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/404/',
},
{
id: '61b74b2d0d3b98000ca3f7',
name: 'Allophones',
slug: 'allophones',
description: 'public',
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:25.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/404/',
},
];
const otherTags = [
{
id: '61b74b2d0d3b980001a3fa',
name: 'Études',
slug: 'etudes',
description: null,
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:25.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/tag/etudes/',
},
{
id: '61b74b2d0d3b980001a3fa',
name: 'A la une',
slug: 'a-la-une',
description: null,
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:25.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/tag/a-la-une/',
},
{
id: '61b74b2d0d3b980001a3fa',
name: 'Infos',
slug: 'infos',
description: null,
feature_image: null,
visibility: 'public',
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
codeinjection_head: null,
codeinjection_foot: null,
canonical_url: null,
accent_color: null,
created_at: '2021-12-13T13:31:25.000Z',
updated_at: '2021-12-13T13:31:25.000Z',
url: 'http://localhost:2368/tag/infos/',
},
];
const tagsData = [...locationtags, ...publictags, ...otherTags];
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
......@@ -13,9 +213,114 @@ describe('PostsService', () => {
}).compile();
service = module.get<PostsService>(PostsService);
jest.spyOn(service, 'getTags').mockImplementationOnce(async (): Promise<Tag[]> => tagsData);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
it('should get tags', async () => {
expect(await service.getTags()).toEqual(tagsData);
});
it('should get location tags', async () => {
expect(await service.getLocationTags()).toEqual(locationtags);
});
it('should get public tags', async () => {
expect(await service.getPublicTags()).toEqual(publictags);
});
it('should get regular tags', async () => {
expect(await service.getRegularTags()).toEqual([otherTags[1], otherTags[2], otherTags[0]]);
});
describe('arraymove', () => {
it('should order tags for display: A La Une tag should be set to first index', () => {
const dataCopy = [...otherTags];
service.arraymove(dataCopy, _.findIndex(dataCopy, { slug: TagEnum.aLaUne }), 0);
expect(dataCopy).toEqual([otherTags[1], otherTags[0], otherTags[2]]);
});
it('should order tags for display: Info tag should be set to second index', () => {
const dataCopy = [...otherTags];
expect(service.arraymove(dataCopy, _.findIndex(dataCopy, { slug: TagEnum.infos }), 1)).toEqual([
otherTags[0],
otherTags[2],
otherTags[1],
]);
});
it('should order tags for display: A La Une tag should be set to first index and Info to second', () => {
const dataCopy = [...otherTags];
service.arraymove(dataCopy, _.findIndex(dataCopy, { slug: TagEnum.aLaUne }), 0);
expect(service.arraymove(dataCopy, _.findIndex(dataCopy, { slug: TagEnum.infos }), 1)).toEqual([
otherTags[1],
otherTags[2],
otherTags[0],
]);
});
});
describe('formatPosts', () => {
const postToFormat: Post = {
id: '61c4847b0ff4550001505090',
uuid: 'f4ee5a37-a343-4cad-8a32-3f6cf87f9569',
title: 'Only feature image',
slug: 'only-feature-image',
html: '<p>Test</p>',
comment_id: '61c4847b0ff4550001505090',
feature_image: 'http://localhost:2368/content/images/2021/12/dacc-4.png',
featured: false,
visibility: 'public',
email_recipient_filter: 'none',
created_at: '2021-12-23T14:15:23.000+00:00',
updated_at: '2021-12-23T14:15:45.000+00:00',
published_at: '2021-12-23T14:15:45.000+00:00',
custom_excerpt: null,
codeinjection_head: null,
codeinjection_foot: null,
custom_template: null,
canonical_url: null,
tags: [],
authors: [],
primary_author: [],
primary_tag: [],
url: 'http://localhost:2368/only-feature-image/',
excerpt:
'« Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus.\n' +
'Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed,\n' +
'dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper\n' +
'congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est\n' +
'eleifend mi, non fermentum diam nisl sit amet erat. Duis semper. Duis arcu\n' +
'massa, scelerisque vitae, consequat in, pretium a, enim. Pellentesque congue. Ut\n' +
'in risus volutpat libero pharetra tem',
reading_time: '2',
access: true,
send_email_when_published: false,
og_image: null,
og_title: null,
og_description: null,
twitter_image: null,
twitter_title: null,
twitter_description: null,
meta_title: null,
meta_description: null,
email_subject: null,
frontmatter: null,
};
it('should format post with no custom expert', () => {
const objCp = { ...postToFormat };
let result = { ...postToFormat };
result.excerpt = 'Inconnu';
result.feature_image = 'https://localhost/blog/content/images/2021/12/dacc-4.png';
expect(service.formatPosts(objCp)).toEqual(result);
});
it('should format post with custom expert', () => {
let objCp = { ...postToFormat };
objCp.custom_excerpt = 'Toto';
let result = { ...postToFormat };
result.custom_excerpt = 'Toto';
result.feature_image = 'https://localhost/blog/content/images/2021/12/dacc-4.png';
expect(service.formatPosts(objCp)).toEqual(result);
});
});
});
......@@ -72,13 +72,17 @@ export class PostsService {
if (!postData.custom_excerpt) {
postData.excerpt = 'Inconnu';
}
// Handle image display. Rewrite image URL to fit ghost infra issue.
if (postData.feature_image && !this.configService.isLocalConf()) {
postData.feature_image = `https://${this.configService.config.host}/blog/content${
postData.feature_image.split('/content')[1]
}`;
if (!this.configService.isLocalConf()) {
if (postData.feature_image) {
console.log('NOT LOCAL');
postData.feature_image = `https://${this.configService.config.host}/blog/content${
postData.feature_image.split('/content')[1]
}`;
}
const regex = /(https?:\/\/ghost):(\d*)?/g;
postData.html = postData.html.replace(regex, `https://${this.configService.config.host}`);
postData.html = postData.html.replace(regex, `https://${this.configService.config.host}/blog`);
}
return postData;
}
......
......@@ -27,4 +27,13 @@ export class Post {
meta_title: string;
meta_description: string;
email_subject: string;
codeinjection_head: string;
codeinjection_foot: string;
custom_template: string;
canonical_url: string;
tags: [];
authors: [];
primary_author: [];
primary_tag: [];
frontmatter: [];
}
......@@ -17,6 +17,7 @@ import { StructuresSearchService } from './structures-search.service';
@Injectable()
export class ApticStructuresService {
private readonly logger = new Logger(ApticStructuresService.name);
constructor(
private readonly httpService: HttpService,
private readonly userService: UsersService,
......@@ -46,13 +47,15 @@ export class ApticStructuresService {
this.createApticStructures(structure);
},
(err) => {
Logger.log(err);
this.logger.log(err);
}
);
});
},
(err) => {
Logger.log(`getApticStructures error on postal code: ${postalCode}. Code: ${err}`);
this.logger.log(
`formatApticStructures | getApticStructures error on postal code: ${postalCode}. Code: ${err}`
);
}
);
});
......@@ -65,7 +68,7 @@ export class ApticStructuresService {
private async createApticStructures(structure: ApticStructure): Promise<any> {
this.structureAlreadyExist(structure).then(async (exist) => {
if (!exist) {
Logger.log(`Create structure : ${structure.name}`, 'ApticStructuresService - createApticStructures');
this.logger.log(`createApticStructures | Create structure : ${structure.name}`);
const createdStructure = new this.structureModel();
// Known fields
createdStructure.structureName = structure.name;
......@@ -97,6 +100,7 @@ export class ApticStructuresService {
createdStructure.save();
this.structuresSearchService.indexStructure(createdStructure);
// Send admin weird structure mail
this.userService.sendAdminApticNewStructureMail(createdStructure);
this.verifyDuplication(createdStructure);
}
});
......@@ -182,7 +186,7 @@ export class ApticStructuresService {
public getMetopoleMunicipality(): void {
const req =
'https://download.data.grandlyon.com/ws/grandlyon/adr_voie_lieu.adrcomgl/all.json?maxfeatures=-1&start=1';
Logger.log(`Request : ${req}`, 'ApticStructuresService - getMetopoleMunicipality');
this.logger.log(`getMetopoleMunicipality | Request : ${req}`, '');
this.httpService.get(encodeURI(req)).subscribe(
(data) => {
const inseeArray = data.data.values.map((municipality) => {
......@@ -195,19 +199,19 @@ export class ApticStructuresService {
this.formatApticStructures(postalCodeArray);
});
},
(err) => Logger.error(err)
(err) => this.logger.error(err)
);
}
public getPostalCodeWithINSEE(inseeCode: string): Observable<AxiosResponse<any>> {
const req = `https://geo.api.gouv.fr/communes/${inseeCode}?fields=codesPostaux&format=json`;
Logger.log(`Request : ${req}`, 'ApticStructuresService - getMetopoleMunicipality');
this.logger.debug(`getMetopoleMunicipality | Request : ${req}`);
return this.httpService.get(encodeURI(req));
}
public getApticStructures(postalCodeData: string): Observable<AxiosResponse<{ presencePoints: ApticStructure[] }>> {
const req = `https://aptisearch-api.aptic.fr/v1/postal-code/${postalCodeData}`;
Logger.log(`Request : ${req}`, 'ApticStructuresService');
this.logger.debug(`getApticStructures | Request : ${req}`);
return this.httpService.get(req, {
headers: {
api_key: process.env.APTIC_TOKEN,
......@@ -220,7 +224,7 @@ export class ApticStructuresService {
rejectUnauthorized: false,
});
const req = `https://aptisearch-api.aptic.fr/v1/catalog/${catalogId}/services`;
Logger.log(`Request : ${req}`, 'ApticStructuresService');
this.logger.log(`getApticStructureOffer | Request : ${req}`);
return this.httpService.get(req, {
httpsAgent: agent,
headers: {
......
import { HttpModule, HttpStatus } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ElasticsearchService } from '@nestjs/elasticsearch';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { UsersServiceMock } from '../../../test/mock/services/user.mock.service';
import { ConfigurationService } from '../../configuration/configuration.service';
import { MailerModule } from '../../mailer/mailer.module';
import { MailerService } from '../../mailer/mailer.service';
import { SearchModule } from '../../search/search.module';
import { UsersService } from '../../users/users.service';
import { structureDto } from '../dto/structure.dto';
import { Structure } from '../schemas/structure.schema';
import { StructuresSearchService } from './structures-search.service';
import { StructuresService } from './structures.service';
describe('StructuresService', () => {
let service: StructuresService;
const mockStructureModel = {
create: jest.fn(),
deleteOne: jest.fn(),
countDocuments: jest.fn(),
findOne: jest.fn(),
exec: jest.fn(),
find: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule, MailerModule, SearchModule, ConfigModule],
providers: [
StructuresService,
ConfigurationService,
StructuresSearchService,
{
provide: getModelToken(Structure.name),
useValue: mockStructureModel,
},
{
provide: UsersService,
useClass: UsersServiceMock,
},
],
}).compile();
service = module.get<StructuresService>(StructuresService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
it('should Initiate structure', () => {
const res = service.initiateStructureIndex();
expect(res).toBeTruthy();
});
it('should searchForStructures', () => {
let res = service.searchForStructures('a', [{ nbPrinters: '1' }]);
expect(res).toBeTruthy();
res = service.searchForStructures('a');
expect(res).toBeTruthy();
});
it('should create structure', () => {
const structure = new structureDto();
let res = service.create(null, structure);
expect(res).toBeTruthy();
res = service.create('tsfsf6296', structure);
expect(res).toBeTruthy();
});
it('should search structure', () => {
const filters = [{ nbPrinters: '1' }];
let res = service.search('', filters);
expect(res).toBeTruthy();
res = service.search(null, filters);
expect(res).toBeTruthy();
res = service.search(null);
expect(res).toBeTruthy();
});
it('should find all structures', () => {
const res = service.findAll();
expect(res).toBeTruthy();
});
it('should find all unclaimed structures', () => {
const res = service.findAllUnclaimed();
expect(res).toBeTruthy();
});
it('should find all formated structures', () => {
const res = service.findAllFormated(null, null, null);
expect(res).toBeTruthy();
});
it('should populate ES', () => {
const res = service.populateES();
expect(res).toBeTruthy();
});
it('should report structure Error', () => {
let res = service.reportStructureError('6093ba0e2ab5775cfc01ed3e', '');
expect(res).toBeTruthy();
res = service.reportStructureError(null, '');
expect(res).toBeTruthy();
});
});
......@@ -430,7 +430,8 @@ export class StructuresService {
public async sendAdminStructureNotification(
structure: StructureDocument,
templateLocation: any,
jsonConfigLocation: any
jsonConfigLocation: any,
user: any = null
) {
const uniqueAdminEmails = [...new Set((await this.userService.getAdmins()).map((admin) => admin.email))].map(
(item) => {
......@@ -438,14 +439,21 @@ export class StructuresService {
}
);
//ici récupérer le user Actuel avec le service afin de remplir le mail.
const config = this.mailerService.config;
const ejsPath = this.mailerService.getTemplateLocation(templateLocation);
const jsonConfig = this.mailerService.loadJsonConfig(jsonConfigLocation);
const html = await ejs.renderFile(ejsPath, {
config,
id: structure ? structure._id : 0,
structureName: structure ? structure.structureName : '',
structureAdress: structure
? structure.address.numero
? `${structure.address.numero} ${structure.address.street} ${structure.address.commune}`
: `${structure.address.street} ${structure.address.commune}`
: '',
structureDescription: structure ? structure.otherDescription : '',
user: user,
});
this.mailerService.send(uniqueAdminEmails, jsonConfig.subject, html);
}
......
......@@ -12,6 +12,7 @@ import { CategoriesFormationsService } from '../categories/services/categories-f
import { CategoriesOthersService } from '../categories/services/categories-others.service';
import { TempUserService } from '../temp-user/temp-user.service';
import { UsersService } from '../users/users.service';
import { CreateStructureDto } from './dto/create-structure.dto';
import { StructuresService } from './services/structures.service';
import { StructuresController } from './structures.controller';
describe('AuthController', () => {
......@@ -60,8 +61,178 @@ describe('AuthController', () => {
expect(controller).toBeDefined();
});
it('should get structure coordinates', async () => {
const coords = controller.getCoordinates('Lyon');
expect(coords).toBeTruthy();
});
it('should create structure', async () => {
const structure: CreateStructureDto = {
idUser: '1',
structure: null,
};
const res = controller.create(structure);
expect(res).toBeTruthy();
});
it('should update structure after ownerVerify', async () => {
const structureId = '1';
const res = controller.updateAfterOwnerVerify(structureId);
expect(res).toBeTruthy();
});
it('should update structure', async () => {
const structureService = new StructuresServiceMock();
const structure = structureService.findOne('6093ba0e2ab5775cfc01ed3e');
const structureId = '1';
const res = await controller.update(structureId, {
numero: null,
deletedAt: null,
remoteAccompaniment: null,
...structure,
});
expect(res.structureName).toBe('a');
});
it('should get all structure', async () => {
const res = await controller.findAll();
expect(res.length).toBe(2);
});
it('should get all Formated structure', async () => {
const res = await controller.findAllFormated();
expect(res.length).toBe(2);
});
it('should search structure', async () => {
const res = controller.search(null, null);
expect(res).toBeTruthy();
});
it('should reset Search Index', async () => {
const res = controller.resetES();
expect(res).toBeTruthy();
});
it('should see if structure is claimed', async () => {
const res = controller.isClaimed('1');
expect(res).toBeTruthy();
});
it('should claim structure', async () => {
const userMock = new UsersServiceMock();
const user = userMock.findOne('pauline.dupont@mii.com');
const res = controller.claim('1', {
phone: null,
resetPasswordToken: null,
changeEmailToken: null,
newEmail: null,
pendingStructuresLink: null,
structuresLink: null,
structureOutdatedMailSent: null,
email: user.email,
name: user.name,
surname: user.surname,
emailVerified: true,
password: user.password,
validationToken: null,
role: null,
});
expect(res).toBeTruthy();
});
it('should count', async () => {
const res = controller.countCategories([{ id: 'equipmentsAndServices', text: 'wifiEnAccesLibre' }]);
expect(res).toBeTruthy();
});
it('should search an address', async () => {
const res = controller.searchAddress({ searchQuery: 'Rue Alphonse Daudet' });
expect(res).toBeTruthy();
});
it('should find struct', async () => {
let res = controller.find('6093ba0e2ab5775cfc01ed3e');
expect(res).toBeTruthy();
res = controller.find('');
expect(res).toBeTruthy();
});
it('should find struct with owners', async () => {
const res = controller.findWithOwners('6093ba0e2ab5775cfc01ed3e', { emailUser: 'pauline.dupont@mii.com' });
expect(res).toBeTruthy();
});
it('should delete struct', async () => {
const res = controller.delete('6093ba0e2ab5775cfc01ed3e');
expect(res).toBeTruthy();
});
it('should add Owner', async () => {
let res = controller.addOwner('6093ba0e2ab5775cfc01ed3e', { email: 'pauline.dupont@mii.com' });
expect(res).toBeTruthy();
res = controller.addOwner('6093ba0e2ab5775cfc01ed3e', { email: 'pauline.dupont@mii.fr' });
expect(res).toBeTruthy();
res = controller.addOwner('', { email: 'pauline.dupont@mii.fr' });
expect(res).toBeTruthy();
});
it('should remove Owner', async () => {
let res = controller.removeOwner('6093ba0e2ab5775cfc01ed3e', 'tsfsf6296');
expect(res).toBeTruthy();
res = controller.removeOwner('6093ba0e2ab5775cfc01ed3e', '1');
expect(res).toBeTruthy();
res = controller.removeOwner('', '1');
expect(res).toBeTruthy();
});
it('should join user', async () => {
const userMock = new UsersServiceMock();
const user = userMock.findOne('pauline.dupont@mii.com');
let res = controller.join('6093ba0e2ab5775cfc01ed3e', {
phone: null,
resetPasswordToken: null,
changeEmailToken: null,
newEmail: null,
pendingStructuresLink: null,
structuresLink: null,
structureOutdatedMailSent: null,
email: user.email,
name: user.name,
surname: user.surname,
emailVerified: true,
password: user.password,
validationToken: null,
role: null,
});
expect(res).toBeTruthy();
res = controller.join('', null);
expect(res).toBeTruthy();
res = controller.join('6093ba0e2ab5775cfc01ed3e', null);
expect(res).toBeTruthy();
});
it('should join in struct', async () => {
let res = controller.joinValidation('6093ba0e2ab5775cfc01ed3e', 'true', 'tsfsf6296');
expect(res).toBeTruthy();
res = controller.joinValidation('6093ba0e2ab5775cfc01ed3e', 'true', '');
expect(res).toBeTruthy();
res = controller.joinValidation('', 'true', '');
expect(res).toBeTruthy();
});
it('should remove user from struct', async () => {
const res = controller.joinValidation('6093ba0e2ab5775cfc01ed3e', 'false', 'tsfsf6296');
expect(res).toBeTruthy();
});
it('should report any structure error', async () => {
const res = controller.reportStructureError({ structureId: '6093ba0e2ab5775cfc01ed3e', content: null });
expect(res).toBeTruthy();
});
//TODO: test structure controler endpoint
//create, search, updateAccountVerified, update, findAll, findAllFormated, isClaimed
//updateStructureLinkedClaim, countCategories, searchAddress, find, findWithOwners
//delete, addOwner, join, joinValidation, removeOwner, reportStructureError
//updateAccountVerified,
//updateStructureLinkedClaim
});
......@@ -108,7 +108,8 @@ export class StructuresController {
@Post(':id/claim')
public async claim(@Param('id') idStructure: string, @Body() user: User): Promise<Types.ObjectId[]> {
return this.userService.updateStructureLinkedClaim(user.email, idStructure);
const structure = await this.structureService.findOne(idStructure);
return this.userService.updateStructureLinkedClaim(user.email, idStructure, structure);
}
@Post('count')
......
import { HttpModule } from '@nestjs/common';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { TclStopPoint } from './tclStopPoint.schema';
import { TclStopPointService } from './tclStopPoint.service';
describe('TclService', () => {
let service: TclStopPointService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule],
providers: [
TclStopPointService,
{
provide: getModelToken('TclStopPoint'),
useValue: TclStopPoint,
},
],
}).compile();
service = module.get<TclStopPointService>(TclStopPointService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
import { HttpModule, HttpStatus } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { MailerModule } from '../mailer/mailer.module';
import { TempUserController } from './temp-user.controller';
import { TempUserService } from './temp-user.service';
describe('TempUserService', () => {
let controller: TempUserController;
const mockTempUserService = {
findById: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule, MailerModule],
providers: [{ provide: TempUserService, useValue: mockTempUserService }],
controllers: [TempUserController],
}).compile();
controller = module.get<TempUserController>(TempUserController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
describe('getTempUser', () => {
it('should get temporary users', async () => {
const tmpUser = { email: 'test@test.com', pendingStructuresLink: [] };
mockTempUserService.findById.mockReturnValueOnce(tmpUser);
expect(await controller.getTempUser('addq651')).toEqual(tmpUser);
});
it('should throw error in cas of no users', async () => {
const tmpUser = null;
mockTempUserService.findById.mockReturnValueOnce(tmpUser);
try {
await controller.getTempUser('addq651');
// Fail test if above expression doesn't throw anything.
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('User does not exists');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
}
});
});
});
import { Document, Types } from 'mongoose';
export interface ITempUser extends Document {
readonly _id: string;
email: string;
pendingStructuresLink: Types.ObjectId[];
pendingStructuresLink?: Types.ObjectId[];
}
......@@ -9,7 +9,7 @@ export class TempUser {
email: string;
@Prop({ default: null })
pendingStructuresLink: Types.ObjectId[];
pendingStructuresLink?: Types.ObjectId[];
}
export const TempUserSchema = SchemaFactory.createForClass(TempUser);
import { HttpModule, HttpStatus } from '@nestjs/common';
import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { MailerModule } from '../mailer/mailer.module';
import { TempUserService } from './temp-user.service';
describe('TempUserService', () => {
let service: TempUserService;
const tempUserModelMock = {
create: jest.fn(),
findOne: jest.fn(),
findById: jest.fn(),
deleteOne: jest.fn(),
find: jest.fn(),
exec: jest.fn(),
updateOne: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule, MailerModule],
providers: [
TempUserService,
{
provide: getModelToken('TempUser'),
useValue: tempUserModelMock,
},
],
}).compile();
service = module.get<TempUserService>(TempUserService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('create', () => {
const tmpUser = { email: 'test@test.com', pendingStructuresLink: [] };
it('should not create temporary user: already exist', async () => {
tempUserModelMock.findOne.mockResolvedValueOnce(tmpUser);
try {
await service.create(tmpUser, 'PIMMS Framboise');
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('User already exists');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
}
});
it('should create temporary user', async () => {
tempUserModelMock.findOne.mockResolvedValueOnce(null).mockResolvedValueOnce(tmpUser);
tempUserModelMock.create.mockResolvedValueOnce(tmpUser);
expect(await service.create(tmpUser, 'PIMMS Framboise')).toEqual(tmpUser);
});
});
it('should find one', async () => {
const tmpUser = { email: 'test2@test.com', pendingStructuresLink: [] };
tempUserModelMock.findOne.mockResolvedValueOnce(tmpUser);
expect(await service.findOne('test2@test.com')).toEqual(tmpUser);
});
it('should find one by id', async () => {
const tmpUser = { email: 'test2@test.com', pendingStructuresLink: [] };
tempUserModelMock.findById.mockResolvedValueOnce(tmpUser);
expect(await service.findById('5fbb92e480a5c257dc0161f0')).toEqual(tmpUser);
});
describe('delete', () => {
it('should delete a temp user', async () => {
const tmpUser = { email: 'test2@test.com', pendingStructuresLink: [] };
tempUserModelMock.findOne.mockResolvedValueOnce(tmpUser);
tempUserModelMock.deleteOne.mockImplementationOnce(() => {});
expect(await service.delete('toto@test.com')).toEqual(tmpUser);
});
it('should return an error : user does not exist', async () => {
tempUserModelMock.findOne.mockResolvedValueOnce(null);
try {
await service.delete('toto@test.com');
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('User does not exists');
expect(e.status).toEqual(HttpStatus.BAD_REQUEST);
}
});
});
describe('updateStructureLinked', () => {
it('should update structure linked', async () => {
const tmpUser = { email: 'test2@test.com', pendingStructuresLink: [] };
tempUserModelMock.find.mockReturnThis();
tempUserModelMock.exec.mockResolvedValueOnce([]).mockResolvedValueOnce(tmpUser);
tempUserModelMock.updateOne.mockReturnThis();
expect(await service.updateStructureLinked(tmpUser)).toEqual(tmpUser);
});
it('should not update structure linked: User already linked', async () => {
const tmpUser = { email: 'test2@test.com', pendingStructuresLink: [] };
tempUserModelMock.find.mockReturnThis();
tempUserModelMock.exec.mockResolvedValueOnce([tmpUser]);
try {
await service.updateStructureLinked(tmpUser);
} catch (e) {
expect(e.message).toEqual('User already linked');
expect(e.status).toEqual(HttpStatus.UNPROCESSABLE_ENTITY);
}
});
});
});
import { HttpException, HttpService, HttpStatus, Injectable } from '@nestjs/common';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model, Types } from 'mongoose';
import { MailerService } from '../mailer/mailer.service';
......@@ -10,7 +10,6 @@ import { ITempUser } from './temp-user.interface';
@Injectable()
export class TempUserService {
constructor(
private readonly httpService: HttpService,
private readonly mailerService: MailerService,
@InjectModel(TempUser.name) private tempUserModel: Model<ITempUser>
) {}
......@@ -20,27 +19,26 @@ export class TempUserService {
if (userInDb) {
throw new HttpException('User already exists', HttpStatus.BAD_REQUEST);
}
const createUser = new this.tempUserModel(createTempUser);
const createUser = await this.tempUserModel.create(createTempUser);
// Send email
this.sendUserMail(createUser, structureName);
createUser.save();
return await this.findOne(createTempUser.email);
return this.findOne(createTempUser.email);
}
public async findOne(mail: string): Promise<TempUser | undefined> {
return this.tempUserModel.findOne({ email: mail }).exec();
public async findOne(mail: string): Promise<TempUser> {
return this.tempUserModel.findOne({ email: mail });
}
public async findById(id: string): Promise<TempUser | undefined> {
return this.tempUserModel.findById(Types.ObjectId(id)).exec();
public async findById(id: string): Promise<TempUser> {
return this.tempUserModel.findById(Types.ObjectId(id));
}
public async delete(mail: string): Promise<TempUser> {
const userInDb = await this.findOne(mail);
if (!userInDb) {
throw new HttpException('User already exists', HttpStatus.BAD_REQUEST);
throw new HttpException('User does not exists', HttpStatus.BAD_REQUEST);
}
this.tempUserModel.deleteOne({ email: mail }).exec();
this.tempUserModel.deleteOne({ email: mail });
return userInDb;
}
......
import { Reflector } from '@nestjs/core';
import { createMock } from '@golevelup/ts-jest';
import { Test, TestingModule } from '@nestjs/testing';
import { ExecutionContext } from '@nestjs/common';
import { UserRole } from '../enum/user-role.enum';
import { IsStructureOwnerGuard } from './isStructureOwner.guard';
import { Types } from 'mongoose';
describe('isStrructureOwner', () => {
let guard: IsStructureOwnerGuard;
let reflector: Reflector;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [],
providers: [
IsStructureOwnerGuard,
{
provide: Reflector,
useValue: {
constructor: jest.fn(),
get: jest.fn(),
},
},
],
}).compile();
guard = module.get<IsStructureOwnerGuard>(IsStructureOwnerGuard);
reflector = module.get<Reflector>(Reflector);
});
afterEach(async () => {
jest.clearAllMocks();
});
it('should be defined', () => {
expect(guard).toBeDefined();
});
it('should return true if structure is in user linked structures', async () => {
const context = createMock<ExecutionContext>({
getHandler: jest.fn(),
switchToHttp: jest.fn().mockReturnValueOnce({
getRequest: jest.fn().mockReturnValueOnce({
user: {
structuresLink: ['6001a38516b08100062e4161'],
structureOutdatedMailSent: [],
pendingStructuresLink: [],
newEmail: null,
changeEmailToken: null,
role: 0,
resetPasswordToken: null,
validationToken: null,
emailVerified: true,
email: 'jp@test.com',
name: 'Jean-Paul',
surname: 'DESCHAMPS',
phone: '06 11 11 11 11',
},
params: {
id: '6001a38516b08100062e4161',
},
}),
}),
});
const result = await guard.canActivate(context);
expect(result).toBeTruthy();
});
it('should return false if structure is not user linked structures', async () => {
jest.spyOn(reflector, 'get').mockImplementation((a: any, b: any) => []);
const context = createMock<ExecutionContext>({
getHandler: jest.fn(),
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn().mockReturnValue({
user: {
structuresLink: ['unIdQuiExistePasTropTrop'],
structureOutdatedMailSent: [],
pendingStructuresLink: [],
newEmail: null,
changeEmailToken: null,
role: UserRole.user,
resetPasswordToken: null,
validationToken: null,
emailVerified: true,
email: 'jp@test.com',
name: 'Jean-Paul',
surname: 'DESCHAMPS',
phone: '06 11 11 11 11',
},
params: {
id: '6001a38516b08100062e4161',
},
}),
}),
});
const result = await guard.canActivate(context);
expect(result).toBeFalsy();
expect(reflector.get).toBeCalled();
});
});
import { Reflector } from '@nestjs/core';
import { createMock } from '@golevelup/ts-jest';
import { Test, TestingModule } from '@nestjs/testing';
import { RolesGuard } from './roles.guard';
import { ExecutionContext } from '@nestjs/common';
import { UserRole } from '../enum/user-role.enum';
describe('RolesGuard', () => {
let guard: RolesGuard;
let reflector: Reflector;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [],
providers: [
RolesGuard,
{
provide: Reflector,
useValue: {
constructor: jest.fn(),
get: jest.fn(),
},
},
],
}).compile();
guard = module.get<RolesGuard>(RolesGuard);
reflector = module.get<Reflector>(Reflector);
});
afterEach(async () => {
jest.clearAllMocks();
});
it('should be defined', () => {
expect(guard).toBeDefined();
});
it('should skip(return true) if the `HasRoles` decorator is not set', async () => {
jest.spyOn(reflector, 'get').mockImplementation((a: any, b: any) => null);
const context = createMock<ExecutionContext>();
const result = await guard.canActivate(context);
expect(result).toBeTruthy();
expect(reflector.get).toBeCalled();
});
it('should return true if the `HasRoles` decorator and role is admin', async () => {
jest.spyOn(reflector, 'get').mockImplementation((a: any, b: any) => ['admin']);
const context = createMock<ExecutionContext>({
getHandler: jest.fn(),
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn().mockReturnValue({
user: { role: UserRole.admin },
}),
}),
});
const result = await guard.canActivate(context);
expect(result).toBeTruthy();
expect(reflector.get).toBeCalled();
});
it('should return false if the `HasRoles` decorator is set but role is not allowed', async () => {
jest.spyOn(reflector, 'get').mockImplementation((a: any, b: any) => ['admin']);
const context = createMock<ExecutionContext>({
getHandler: jest.fn(),
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn().mockReturnValue({
user: { role: null },
}),
}),
});
const result = await guard.canActivate(context);
expect(result).toBeFalsy();
expect(reflector.get).toBeCalled();
});
it('should return true if the `HasRoles` decorator is and role is not allowed', async () => {
jest.spyOn(reflector, 'get').mockImplementation((a: any, b: any) => ['user']);
const context = createMock<ExecutionContext>({
getHandler: jest.fn(),
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn().mockReturnValue({
user: { role: UserRole.user },
}),
}),
});
const result = await guard.canActivate(context);
expect(result).toBeTruthy();
expect(reflector.get).toBeCalled();
});
});