@tomei/media 0.10.0 → 0.10.1-test.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.commitlintrc.json +22 -22
- package/.gitlab-ci.yml +234 -16
- package/.husky/commit-msg +15 -15
- package/.husky/pre-commit +7 -7
- package/.prettierrc +4 -4
- package/.vscode/settings.json +3 -0
- package/README.md +93 -93
- package/dist/__tests__/common.service.spec.d.ts +1 -0
- package/dist/__tests__/common.service.spec.js +160 -0
- package/dist/__tests__/common.service.spec.js.map +1 -0
- package/dist/__tests__/medias.repository.spec.d.ts +1 -0
- package/dist/__tests__/medias.repository.spec.js +140 -0
- package/dist/__tests__/medias.repository.spec.js.map +1 -0
- package/dist/__tests__/medias.spec.d.ts +1 -0
- package/dist/__tests__/medias.spec.js +347 -0
- package/dist/__tests__/medias.spec.js.map +1 -0
- package/dist/__tests__/pipes.spec.d.ts +1 -0
- package/dist/__tests__/pipes.spec.js +130 -0
- package/dist/__tests__/pipes.spec.js.map +1 -0
- package/dist/medias.d.ts +2 -2
- package/dist/medias.js +7 -1
- package/dist/medias.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/eslint.config.mjs +58 -58
- package/jest.config.js +26 -0
- package/migration/0001-add-defaultyn-hiddenyn-to-media-table.js +36 -36
- package/migration/media-migration.js +82 -82
- package/nest-cli.json +18 -18
- package/package.json +83 -78
- package/sonar-project.properties +12 -12
- package/src/__tests__/common.service.spec.ts +203 -0
- package/src/__tests__/medias.repository.spec.ts +158 -0
- package/src/__tests__/medias.spec.ts +468 -0
- package/src/__tests__/pipes.spec.ts +154 -0
- package/src/medias.ts +11 -3
- package/tsconfig.build.json +4 -4
- package/tsconfig.json +30 -30
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
jest.mock('@nestjs/config', () => ({
|
|
2
|
+
ConfigService: jest.fn().mockImplementation(() => ({
|
|
3
|
+
get: jest.fn().mockReturnValue('http://localhost:3000'),
|
|
4
|
+
})),
|
|
5
|
+
}));
|
|
6
|
+
|
|
7
|
+
jest.mock('@nestjs/common', () => ({
|
|
8
|
+
Injectable: () => (target: any) => target,
|
|
9
|
+
HttpException: class HttpException extends Error {
|
|
10
|
+
constructor(
|
|
11
|
+
public response: any,
|
|
12
|
+
public status: number,
|
|
13
|
+
) {
|
|
14
|
+
super(typeof response === 'string' ? response : JSON.stringify(response));
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
InternalServerErrorException: class InternalServerErrorException extends Error {
|
|
18
|
+
constructor(message: string) {
|
|
19
|
+
super(message);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
jest.mock('axios');
|
|
25
|
+
jest.mock('lodash', () => ({
|
|
26
|
+
omit: jest.fn((obj, keys) => {
|
|
27
|
+
const result = { ...obj };
|
|
28
|
+
keys.forEach((k: string) => delete result[k]);
|
|
29
|
+
return result;
|
|
30
|
+
}),
|
|
31
|
+
omitBy: jest.fn((obj, fn) => obj),
|
|
32
|
+
keys: jest.fn((obj) => Object.keys(obj)),
|
|
33
|
+
pick: jest.fn((obj, keys) => {
|
|
34
|
+
const result: any = {};
|
|
35
|
+
keys.forEach((k: string) => {
|
|
36
|
+
if (k in obj) result[k] = obj[k];
|
|
37
|
+
});
|
|
38
|
+
return result;
|
|
39
|
+
}),
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
jest.mock('@paralleldrive/cuid2', () => ({
|
|
43
|
+
createId: jest.fn().mockReturnValue('new-cuid'),
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
import axios from 'axios';
|
|
47
|
+
import { CommonService } from '../common/common.service';
|
|
48
|
+
|
|
49
|
+
const mockAxios = axios as jest.Mocked<typeof axios>;
|
|
50
|
+
|
|
51
|
+
const mockConfigService = {
|
|
52
|
+
get: jest.fn().mockReturnValue('http://localhost:3000'),
|
|
53
|
+
} as any;
|
|
54
|
+
|
|
55
|
+
describe('CommonService', () => {
|
|
56
|
+
let service: CommonService;
|
|
57
|
+
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
jest.clearAllMocks();
|
|
60
|
+
service = new CommonService(mockConfigService);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('handleAxiosError', () => {
|
|
64
|
+
it('throws HttpException when error has a response', () => {
|
|
65
|
+
const err = { response: { data: 'Bad Request', status: 400 } };
|
|
66
|
+
expect(() => service.handleAxiosError(err)).toThrow();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('throws HttpException when error has a request but no response', () => {
|
|
70
|
+
const err = { request: 'timeout' };
|
|
71
|
+
expect(() => service.handleAxiosError(err)).toThrow();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('throws InternalServerErrorException for generic errors', () => {
|
|
75
|
+
const err = { message: 'Something went wrong' };
|
|
76
|
+
expect(() => service.handleAxiosError(err)).toThrow();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('addActivityHistory', () => {
|
|
81
|
+
it('posts activity and returns EntityId', async () => {
|
|
82
|
+
mockAxios.post = jest
|
|
83
|
+
.fn()
|
|
84
|
+
.mockResolvedValue({ data: { EntityId: 'entity-123' } });
|
|
85
|
+
|
|
86
|
+
const record = {
|
|
87
|
+
Action: 'Insert',
|
|
88
|
+
EntityValueBefore: {},
|
|
89
|
+
EntityValueAfter: {
|
|
90
|
+
Title: 'Test',
|
|
91
|
+
CreatedById: 'u1',
|
|
92
|
+
CreatedAt: new Date(),
|
|
93
|
+
},
|
|
94
|
+
PerformedById: 'user-001',
|
|
95
|
+
EntityId: 'entity-001',
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const result = await service.addActivityHistory(
|
|
99
|
+
record,
|
|
100
|
+
'Media',
|
|
101
|
+
'create',
|
|
102
|
+
);
|
|
103
|
+
expect(result).toBe('entity-123');
|
|
104
|
+
expect(mockAxios.post).toHaveBeenCalledWith(
|
|
105
|
+
'http://localhost:3000/activity-histories',
|
|
106
|
+
expect.objectContaining({ EntityId: 'entity-001' }),
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('uses update activity label for update method', async () => {
|
|
111
|
+
mockAxios.post = jest
|
|
112
|
+
.fn()
|
|
113
|
+
.mockResolvedValue({ data: { EntityId: 'e2' } });
|
|
114
|
+
|
|
115
|
+
const record = {
|
|
116
|
+
EntityValueBefore: { Title: 'Old' },
|
|
117
|
+
EntityValueAfter: { Title: 'New' },
|
|
118
|
+
PerformedById: 'user-001',
|
|
119
|
+
EntityId: 'entity-002',
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
await service.addActivityHistory(record, 'Media', 'update');
|
|
123
|
+
expect(mockAxios.post).toHaveBeenCalledWith(
|
|
124
|
+
expect.any(String),
|
|
125
|
+
expect.objectContaining({ Action: 'Update' }),
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('calls handleAxiosError when axios throws', async () => {
|
|
130
|
+
const axiosError = { response: { data: 'Error', status: 500 } };
|
|
131
|
+
mockAxios.post = jest.fn().mockRejectedValue(axiosError);
|
|
132
|
+
|
|
133
|
+
const record = {
|
|
134
|
+
EntityValueBefore: {},
|
|
135
|
+
EntityValueAfter: {},
|
|
136
|
+
PerformedById: 'u1',
|
|
137
|
+
EntityId: 'e1',
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
await expect(
|
|
141
|
+
service.addActivityHistory(record, 'Media', 'create'),
|
|
142
|
+
).rejects.toThrow();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('getList', () => {
|
|
147
|
+
it('returns rows from the response', async () => {
|
|
148
|
+
mockAxios.get = jest
|
|
149
|
+
.fn()
|
|
150
|
+
.mockResolvedValue({ data: { rows: ['item1', 'item2'] } });
|
|
151
|
+
|
|
152
|
+
const result = await service.getList('MediaTypes');
|
|
153
|
+
expect(result).toEqual(['item1', 'item2']);
|
|
154
|
+
expect(mockAxios.get).toHaveBeenCalledWith(
|
|
155
|
+
'http://localhost:3000/lists/items',
|
|
156
|
+
expect.objectContaining({ params: { ListName: 'MediaTypes' } }),
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('calls handleAxiosError when axios throws', async () => {
|
|
161
|
+
mockAxios.get = jest
|
|
162
|
+
.fn()
|
|
163
|
+
.mockRejectedValue({ response: { data: 'err', status: 500 } });
|
|
164
|
+
await expect(service.getList('Any')).rejects.toThrow();
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('addFieldTranslation', () => {
|
|
169
|
+
it('posts field translation', async () => {
|
|
170
|
+
mockAxios.post = jest.fn().mockResolvedValue({});
|
|
171
|
+
const payload = { field: 'Title', value: 'Tajuk' } as any;
|
|
172
|
+
|
|
173
|
+
await service.addFieldTranslation(payload);
|
|
174
|
+
expect(mockAxios.post).toHaveBeenCalledWith(
|
|
175
|
+
'http://localhost:3000/field-translations',
|
|
176
|
+
payload,
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('calls handleAxiosError when axios throws', async () => {
|
|
181
|
+
mockAxios.post = jest.fn().mockRejectedValue({ message: 'fail' });
|
|
182
|
+
await expect(service.addFieldTranslation({} as any)).rejects.toThrow();
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('getMedia', () => {
|
|
187
|
+
it('returns rows from the response', async () => {
|
|
188
|
+
mockAxios.get = jest
|
|
189
|
+
.fn()
|
|
190
|
+
.mockResolvedValue({ data: { rows: [{ MediaId: 'm1' }] } });
|
|
191
|
+
const result = await service.getMedia({
|
|
192
|
+
ObjectId: 'obj1',
|
|
193
|
+
ObjectType: 'Rental',
|
|
194
|
+
} as any);
|
|
195
|
+
expect(result).toEqual([{ MediaId: 'm1' }]);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('calls handleAxiosError when axios throws', async () => {
|
|
199
|
+
mockAxios.get = jest.fn().mockRejectedValue({ message: 'fail' });
|
|
200
|
+
await expect(service.getMedia({} as any)).rejects.toThrow();
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
jest.mock('@nestjs/swagger', () => ({
|
|
2
|
+
ApiProperty: () => () => {},
|
|
3
|
+
ApiPropertyOptional: () => () => {},
|
|
4
|
+
}));
|
|
5
|
+
|
|
6
|
+
jest.mock('sequelize-typescript', () => ({
|
|
7
|
+
Table: () => () => {},
|
|
8
|
+
Column: () => () => {},
|
|
9
|
+
Model: class Model {
|
|
10
|
+
static findByPk = jest.fn();
|
|
11
|
+
static findOne = jest.fn();
|
|
12
|
+
static findAll = jest.fn();
|
|
13
|
+
static findAndCountAll = jest.fn();
|
|
14
|
+
static create = jest.fn();
|
|
15
|
+
get = jest.fn();
|
|
16
|
+
update = jest.fn();
|
|
17
|
+
destroy = jest.fn();
|
|
18
|
+
},
|
|
19
|
+
DataType: {
|
|
20
|
+
STRING: 'STRING',
|
|
21
|
+
TEXT: 'TEXT',
|
|
22
|
+
DATE: 'DATE',
|
|
23
|
+
BOOLEAN: 'BOOLEAN',
|
|
24
|
+
ENUM: () => 'ENUM',
|
|
25
|
+
},
|
|
26
|
+
PrimaryKey: () => () => {},
|
|
27
|
+
ForeignKey: () => () => {},
|
|
28
|
+
BelongsTo: () => () => {},
|
|
29
|
+
HasMany: () => () => {},
|
|
30
|
+
CreatedAt: () => () => {},
|
|
31
|
+
UpdatedAt: () => () => {},
|
|
32
|
+
Default: () => () => {},
|
|
33
|
+
AllowNull: () => () => {},
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
jest.mock('sequelize', () => ({
|
|
37
|
+
Op: { substring: Symbol('Op.substring') },
|
|
38
|
+
DataTypes: {},
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
jest.mock('@tomei/general', () => ({
|
|
42
|
+
RepositoryBase: class RepositoryBase {
|
|
43
|
+
constructor(_model: any) {}
|
|
44
|
+
},
|
|
45
|
+
IRepositoryBase: {},
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
import { MediasRepository } from '../medias.repository';
|
|
49
|
+
import { MediasModel } from '../entities/medias.entity';
|
|
50
|
+
|
|
51
|
+
const mockModel = {
|
|
52
|
+
MediaId: 'media-001',
|
|
53
|
+
get: jest.fn().mockReturnValue({}),
|
|
54
|
+
update: jest.fn(),
|
|
55
|
+
destroy: jest.fn(),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
describe('MediasRepository', () => {
|
|
59
|
+
let repo: MediasRepository;
|
|
60
|
+
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
jest.clearAllMocks();
|
|
63
|
+
repo = new MediasRepository();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('findByPk', () => {
|
|
67
|
+
it('returns a MediasModel when found', async () => {
|
|
68
|
+
(MediasModel.findOne as jest.Mock).mockResolvedValue(mockModel);
|
|
69
|
+
const result = await repo.findByPk('media-001', undefined);
|
|
70
|
+
expect(result).toBe(mockModel);
|
|
71
|
+
expect(MediasModel.findOne).toHaveBeenCalledWith({
|
|
72
|
+
where: { MediaId: 'media-001' },
|
|
73
|
+
transaction: undefined,
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('passes the transaction option', async () => {
|
|
78
|
+
const tx = { id: 'tx-1' };
|
|
79
|
+
(MediasModel.findOne as jest.Mock).mockResolvedValue(mockModel);
|
|
80
|
+
await repo.findByPk('media-001', tx);
|
|
81
|
+
expect(MediasModel.findOne).toHaveBeenCalledWith({
|
|
82
|
+
where: { MediaId: 'media-001' },
|
|
83
|
+
transaction: tx,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('returns null when record is not found', async () => {
|
|
88
|
+
(MediasModel.findOne as jest.Mock).mockResolvedValue(null);
|
|
89
|
+
const result = await repo.findByPk('missing-id', undefined);
|
|
90
|
+
expect(result).toBeNull();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('throws when the database call fails', async () => {
|
|
94
|
+
(MediasModel.findOne as jest.Mock).mockRejectedValue(
|
|
95
|
+
new Error('DB error'),
|
|
96
|
+
);
|
|
97
|
+
await expect(repo.findByPk('media-001', undefined)).rejects.toThrow(
|
|
98
|
+
'DB error',
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('delete', () => {
|
|
104
|
+
it('destroys the record by MediaId', async () => {
|
|
105
|
+
(MediasModel as any).destroy = jest.fn().mockResolvedValue(1);
|
|
106
|
+
await repo.delete('media-001');
|
|
107
|
+
expect((MediasModel as any).destroy).toHaveBeenCalledWith(
|
|
108
|
+
expect.objectContaining({
|
|
109
|
+
where: expect.objectContaining({ MediaId: 'media-001' }),
|
|
110
|
+
}),
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('passes the transaction option', async () => {
|
|
115
|
+
const tx = { id: 'tx-2' };
|
|
116
|
+
(MediasModel as any).destroy = jest.fn().mockResolvedValue(1);
|
|
117
|
+
await repo.delete('media-001', tx);
|
|
118
|
+
expect((MediasModel as any).destroy).toHaveBeenCalledWith(
|
|
119
|
+
expect.objectContaining({ transaction: tx }),
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('throws when the database call fails', async () => {
|
|
124
|
+
(MediasModel as any).destroy = jest
|
|
125
|
+
.fn()
|
|
126
|
+
.mockRejectedValue(new Error('Delete failed'));
|
|
127
|
+
await expect(repo.delete('media-001')).rejects.toThrow('Delete failed');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('findAndCountAll', () => {
|
|
132
|
+
it('returns count and rows with options', async () => {
|
|
133
|
+
const mockResult = { count: 2, rows: [mockModel, mockModel] };
|
|
134
|
+
(MediasModel.findAndCountAll as jest.Mock).mockResolvedValue(mockResult);
|
|
135
|
+
const result = await repo.findAndCountAll({ limit: 10, offset: 0 });
|
|
136
|
+
expect(result).toEqual(mockResult);
|
|
137
|
+
expect(MediasModel.findAndCountAll).toHaveBeenCalledWith({
|
|
138
|
+
limit: 10,
|
|
139
|
+
offset: 0,
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('returns all records when no options are given', async () => {
|
|
144
|
+
const mockResult = { count: 1, rows: [mockModel] };
|
|
145
|
+
(MediasModel.findAndCountAll as jest.Mock).mockResolvedValue(mockResult);
|
|
146
|
+
const result = await repo.findAndCountAll(undefined);
|
|
147
|
+
expect(result).toEqual(mockResult);
|
|
148
|
+
expect(MediasModel.findAndCountAll).toHaveBeenCalledWith();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('throws when the database call fails', async () => {
|
|
152
|
+
(MediasModel.findAndCountAll as jest.Mock).mockRejectedValue(
|
|
153
|
+
new Error('Query failed'),
|
|
154
|
+
);
|
|
155
|
+
await expect(repo.findAndCountAll({ limit: 5 })).rejects.toThrow();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|