@ackplus/nest-dynamic-templates 1.1.0 → 1.1.2

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.
Files changed (113) hide show
  1. package/package.json +2 -2
  2. package/src/{index.ts → index.d.ts} +2 -14
  3. package/src/index.d.ts.map +1 -0
  4. package/src/lib/constant.d.ts +3 -0
  5. package/src/lib/constant.d.ts.map +1 -0
  6. package/src/lib/dto/create-template-layout.dto.d.ts +16 -0
  7. package/src/lib/dto/create-template-layout.dto.d.ts.map +1 -0
  8. package/src/lib/dto/create-template.dto.d.ts +18 -0
  9. package/src/lib/dto/create-template.dto.d.ts.map +1 -0
  10. package/src/lib/dto/render-content-template-layout.dto.d.ts +8 -0
  11. package/src/lib/dto/render-content-template-layout.dto.d.ts.map +1 -0
  12. package/src/lib/dto/render-content-template.dto.d.ts +9 -0
  13. package/src/lib/dto/render-content-template.dto.d.ts.map +1 -0
  14. package/src/lib/dto/render-template-layout.dto.d.ts +11 -0
  15. package/src/lib/dto/render-template-layout.dto.d.ts.map +1 -0
  16. package/src/lib/dto/render-template.dto.d.ts +15 -0
  17. package/src/lib/dto/render-template.dto.d.ts.map +1 -0
  18. package/src/lib/dto/template-filter.dto.d.ts +9 -0
  19. package/src/lib/dto/template-filter.dto.d.ts.map +1 -0
  20. package/src/lib/dto/template-layout-filter.dto.d.ts +8 -0
  21. package/src/lib/dto/template-layout-filter.dto.d.ts.map +1 -0
  22. package/src/lib/engines/language/html.engine.d.ts +10 -0
  23. package/src/lib/engines/language/html.engine.d.ts.map +1 -0
  24. package/src/lib/engines/language/{index.ts → index.d.ts} +1 -0
  25. package/src/lib/engines/language/index.d.ts.map +1 -0
  26. package/src/lib/engines/language/markdown.engine.d.ts +10 -0
  27. package/src/lib/engines/language/markdown.engine.d.ts.map +1 -0
  28. package/src/lib/engines/language/mjml.engine.d.ts +10 -0
  29. package/src/lib/engines/language/mjml.engine.d.ts.map +1 -0
  30. package/src/lib/engines/language/text.engine.d.ts +8 -0
  31. package/src/lib/engines/language/text.engine.d.ts.map +1 -0
  32. package/src/lib/engines/{language-engine.ts → language-engine.d.ts} +2 -7
  33. package/src/lib/engines/language-engine.d.ts.map +1 -0
  34. package/src/lib/engines/template/ejs.engine.d.ts +11 -0
  35. package/src/lib/engines/template/ejs.engine.d.ts.map +1 -0
  36. package/src/lib/engines/template/handlebars.engine.d.ts +11 -0
  37. package/src/lib/engines/template/handlebars.engine.d.ts.map +1 -0
  38. package/src/lib/engines/template/{index.ts → index.d.ts} +1 -0
  39. package/src/lib/engines/template/index.d.ts.map +1 -0
  40. package/src/lib/engines/template/nunjucks.engine.d.ts +17 -0
  41. package/src/lib/engines/template/nunjucks.engine.d.ts.map +1 -0
  42. package/src/lib/engines/template/pug.engine.d.ts +13 -0
  43. package/src/lib/engines/template/pug.engine.d.ts.map +1 -0
  44. package/src/lib/engines/{template-engine.ts → template-engine.d.ts} +2 -6
  45. package/src/lib/engines/template-engine.d.ts.map +1 -0
  46. package/src/lib/entities/template-layout.entity.d.ts +21 -0
  47. package/src/lib/entities/template-layout.entity.d.ts.map +1 -0
  48. package/src/lib/entities/template.entity.d.ts +22 -0
  49. package/src/lib/entities/template.entity.d.ts.map +1 -0
  50. package/src/lib/errors/template.errors.d.ts +20 -0
  51. package/src/lib/errors/template.errors.d.ts.map +1 -0
  52. package/src/lib/interfaces/{module-config.interface.ts → module-config.interface.d.ts} +2 -10
  53. package/src/lib/interfaces/module-config.interface.d.ts.map +1 -0
  54. package/src/lib/interfaces/template.types.d.ts +23 -0
  55. package/src/lib/interfaces/template.types.d.ts.map +1 -0
  56. package/src/lib/nest-dynamic-templates.module.d.ts +11 -0
  57. package/src/lib/nest-dynamic-templates.module.d.ts.map +1 -0
  58. package/src/lib/services/template-config.service.d.ts +55 -0
  59. package/src/lib/services/template-config.service.d.ts.map +1 -0
  60. package/src/lib/services/template-engine.registry.d.ts +22 -0
  61. package/src/lib/services/template-engine.registry.d.ts.map +1 -0
  62. package/src/lib/services/template-layout.service.d.ts +37 -0
  63. package/src/lib/services/template-layout.service.d.ts.map +1 -0
  64. package/src/lib/services/template.service.d.ts +39 -0
  65. package/src/lib/services/template.service.d.ts.map +1 -0
  66. package/src/test/helpers.d.ts +5 -0
  67. package/src/test/helpers.d.ts.map +1 -0
  68. package/src/test/test-database.config.d.ts +5 -0
  69. package/src/test/test-database.config.d.ts.map +1 -0
  70. package/src/test/test.setup.d.ts +4 -0
  71. package/src/test/test.setup.d.ts.map +1 -0
  72. package/eslint.config.mjs +0 -22
  73. package/jest.config.ts +0 -10
  74. package/project.json +0 -38
  75. package/src/lib/constant.ts +0 -2
  76. package/src/lib/dto/create-template-layout.dto.ts +0 -65
  77. package/src/lib/dto/create-template.dto.ts +0 -80
  78. package/src/lib/dto/render-content-template-layout.dto.ts +0 -32
  79. package/src/lib/dto/render-content-template.dto.ts +0 -37
  80. package/src/lib/dto/render-template-layout.dto.ts +0 -55
  81. package/src/lib/dto/render-template.dto.ts +0 -74
  82. package/src/lib/dto/template-filter.dto.ts +0 -52
  83. package/src/lib/dto/template-layout-filter.dto.ts +0 -51
  84. package/src/lib/engines/language/html.engine.ts +0 -49
  85. package/src/lib/engines/language/markdown.engine.ts +0 -37
  86. package/src/lib/engines/language/mjml.engine.ts +0 -44
  87. package/src/lib/engines/language/text.engine.ts +0 -15
  88. package/src/lib/engines/template/ejs.engine.ts +0 -33
  89. package/src/lib/engines/template/handlebars.engine.ts +0 -35
  90. package/src/lib/engines/template/nunjucks.engine.ts +0 -70
  91. package/src/lib/engines/template/pug.engine.ts +0 -43
  92. package/src/lib/entities/template-layout.entity.ts +0 -99
  93. package/src/lib/entities/template.entity.ts +0 -105
  94. package/src/lib/errors/template.errors.ts +0 -73
  95. package/src/lib/interfaces/template.types.ts +0 -25
  96. package/src/lib/nest-dynamic-templates.module.ts +0 -143
  97. package/src/lib/services/template-config.service.ts +0 -112
  98. package/src/lib/services/template-engine.registry.ts +0 -109
  99. package/src/lib/services/template-layout.service.ts +0 -407
  100. package/src/lib/services/template.service.ts +0 -476
  101. package/src/test/helpers.ts +0 -31
  102. package/src/test/nunjucks.service.spec.ts +0 -157
  103. package/src/test/pug.service.spec-temp +0 -254
  104. package/src/test/template-layout.service.spec.ts +0 -422
  105. package/src/test/template.service.spec.ts +0 -862
  106. package/src/test/test-database.config.ts +0 -24
  107. package/src/test/test-database.d.ts +0 -6
  108. package/src/test/test.setup.ts +0 -34
  109. package/src/types/ioredis.d.ts +0 -6
  110. package/src/types/mjml.d.ts +0 -5
  111. package/tsconfig.json +0 -17
  112. package/tsconfig.lib.json +0 -14
  113. package/tsconfig.spec.json +0 -15
@@ -1,254 +0,0 @@
1
- import { DataSource, Repository } from 'typeorm';
2
- import { createTestModule } from './test.setup';
3
- import { TemplateService } from '../lib/services/template.service';
4
- import { NestDynamicTemplate } from '../lib/entities/template.entity';
5
- import { TemplateTypeEnum, TemplateEngineEnum, TemplateLanguageEnum } from '../lib/interfaces/template.types';
6
- import { CreateTemplateDto } from '../lib/dto/create-template.dto';
7
- import { engineFilters } from './helpers';
8
-
9
- describe('Pug Engine', () => {
10
- let service: TemplateService;
11
- let dataSource: DataSource;
12
- let templateRepository: Repository<NestDynamicTemplate>;
13
-
14
- const testTemplate: CreateTemplateDto = {
15
- name: 'test-template',
16
- displayName: 'Test Template',
17
- content: 'p Hello #{name}!',
18
- type: TemplateTypeEnum.EMAIL,
19
- engine: TemplateEngineEnum.PUG,
20
- language: TemplateLanguageEnum.HTML,
21
- scope: 'system',
22
- scopeId: null,
23
- locale: 'en',
24
- isActive: true
25
- };
26
-
27
- beforeEach(async () => {
28
- const moduleRef = await createTestModule({
29
- engines: {
30
- template: [TemplateEngineEnum.PUG],
31
- },
32
- enginesOptions: {
33
- filters: engineFilters,
34
- template: {
35
- [TemplateEngineEnum.PUG]: {
36
- pretty: true,
37
- compileDebug: true
38
- }
39
- }
40
- }
41
- });
42
-
43
- service = moduleRef.get<TemplateService>(TemplateService);
44
- dataSource = moduleRef.get<DataSource>(DataSource);
45
- templateRepository = dataSource.getRepository(NestDynamicTemplate);
46
- });
47
-
48
- afterEach(async () => {
49
- // Clean up templates
50
- await templateRepository.delete('1 = 1');
51
-
52
- // Clean up database after each test
53
- await dataSource.synchronize(true);
54
- });
55
-
56
- afterAll(async () => {
57
- // Close the connection after all tests
58
- await dataSource.destroy();
59
- });
60
-
61
- describe('Pug Custom Filters', () => {
62
- it('should format date using custom date filter', async () => {
63
- const template = await service.createTemplate({
64
- ...testTemplate,
65
- name: 'date-template',
66
- content: 'p Today is #{formatDate(date, "YYYY-MM-DD")}',
67
- });
68
-
69
- const today = new Date();
70
- const expectedDate = today.toISOString().split('T')[0];
71
-
72
- const result = await service.render({
73
- type: TemplateTypeEnum.EMAIL,
74
- name: 'date-template',
75
- scope: 'system',
76
- context: {
77
- date: today
78
- }
79
- });
80
-
81
- expect(result.content).toBe(`<p>Today is ${expectedDate}</p>`);
82
- });
83
-
84
- it('should format currency using custom currency filter', async () => {
85
- const template = await service.createTemplate({
86
- ...testTemplate,
87
- name: 'currency-template',
88
- content: 'p Price: #{formatCurrency(amount, "USD")}',
89
- });
90
-
91
- const result = await service.render({
92
- type: TemplateTypeEnum.EMAIL,
93
- name: 'currency-template',
94
- scope: 'system',
95
- context: {
96
- amount: 1234.56
97
- }
98
- });
99
-
100
- expect(result.content).toBe('<p>Price: $1,234.56</p>');
101
- });
102
-
103
- it('should handle multiple filters in the same template', async () => {
104
- const template = await service.createTemplate({
105
- ...testTemplate,
106
- name: 'multi-filter-template',
107
- content: 'p Order placed on #{formatDate(date, "YYYY-MM-DD")} for #{formatCurrency(amount, "USD")}',
108
- });
109
-
110
- const today = new Date();
111
- const expectedDate = today.toISOString().split('T')[0];
112
-
113
- const result = await service.render({
114
- type: TemplateTypeEnum.EMAIL,
115
- name: 'multi-filter-template',
116
- scope: 'system',
117
- context: {
118
- date: today,
119
- amount: 1234.56
120
- }
121
- });
122
-
123
- expect(result.content).toBe(`<p>Order placed on ${expectedDate} for $1,234.56</p>`);
124
- });
125
-
126
- it('should handle different currency formats', async () => {
127
- const template = await service.createTemplate({
128
- ...testTemplate,
129
- name: 'currency-formats-template',
130
- content: 'p USD: #{formatCurrency(usd, "USD")}, EUR: #{formatCurrency(eur, "EUR")}',
131
- });
132
-
133
- const result = await service.render({
134
- type: TemplateTypeEnum.EMAIL,
135
- name: 'currency-formats-template',
136
- scope: 'system',
137
- context: {
138
- usd: 1234.56,
139
- eur: 1234.56
140
- }
141
- });
142
-
143
- expect(result.content).toBe('<p>USD: $1,234.56, EUR: €1,234.56</p>');
144
- });
145
-
146
- it('should handle different date formats', async () => {
147
- const template = await service.createTemplate({
148
- ...testTemplate,
149
- name: 'date-formats-template',
150
- content: 'p Short: #{formatDate(date, "MM/DD/YY")}, Long: #{formatDate(date, "MMMM D, YYYY")}, ISO: #{formatDate(date, "YYYY-MM-DD")}',
151
- });
152
-
153
- const date = new Date('2024-03-15');
154
- const result = await service.render({
155
- type: TemplateTypeEnum.EMAIL,
156
- name: 'date-formats-template',
157
- scope: 'system',
158
- context: {
159
- date: date
160
- }
161
- });
162
-
163
- expect(result.content).toBe('<p>Short: 03/15/24, Long: March 15, 2024, ISO: 2024-03-15</p>');
164
- });
165
- });
166
-
167
- describe('Pug HTML Features', () => {
168
- // Custom matcher to check HTML structure
169
- const expectHtmlStructure = (received: string, expected: string) => {
170
- const normalizeHtml = (html: string) => {
171
- return html
172
- .replace(/\s+/g, ' ')
173
- .replace(/>\s+</g, '><')
174
- .trim();
175
- };
176
-
177
- const receivedNormalized = normalizeHtml(received);
178
- const expectedNormalized = normalizeHtml(expected);
179
-
180
- // Extract attributes and compare them regardless of order
181
- const getAttributes = (html: string) => {
182
- const match = html.match(/<[^>]+>/);
183
- if (!match) return [];
184
- return match[0]
185
- .replace(/<[^\s>]+/, '')
186
- .replace(/>$/, '')
187
- .trim()
188
- .split(/\s+/)
189
- .sort();
190
- };
191
-
192
- const receivedAttrs = getAttributes(receivedNormalized);
193
- const expectedAttrs = getAttributes(expectedNormalized);
194
-
195
- expect(receivedAttrs).toEqual(expectedAttrs);
196
- expect(receivedNormalized.replace(/<[^>]+>/, '')).toBe(expectedNormalized.replace(/<[^>]+>/, ''));
197
- };
198
-
199
- it('should render nested HTML tags', async () => {
200
- const template = await service.createTemplate({
201
- ...testTemplate,
202
- name: 'nested-html-template',
203
- content: 'div\n h1 Title\n p This is a paragraph.'
204
- });
205
-
206
- const result = await service.render({
207
- type: TemplateTypeEnum.EMAIL,
208
- name: 'nested-html-template',
209
- scope: 'system',
210
- context: {}
211
- });
212
-
213
- expect(result.content.replace(/\n/g, ''))
214
- .toBe('<div><h1>Title</h1><p>This is a paragraph.</p></div>');
215
- });
216
-
217
- it('should render HTML with attributes', async () => {
218
- const template = await service.createTemplate({
219
- ...testTemplate,
220
- name: 'attributes-html-template',
221
- content: 'a(href="https://example.com" target="_blank") Example Link'
222
- });
223
-
224
- const result = await service.render({
225
- type: TemplateTypeEnum.EMAIL,
226
- name: 'attributes-html-template',
227
- scope: 'system',
228
- context: {}
229
- });
230
-
231
- expect(result.content).toBe('<a href="https://example.com" target="_blank">Example Link</a>');
232
- });
233
-
234
- it('should render HTML with classes and ids', async () => {
235
- const template = await service.createTemplate({
236
- ...testTemplate,
237
- name: 'class-id-html-template',
238
- content: 'div#main.container Main content'
239
- });
240
-
241
- const result = await service.render({
242
- type: TemplateTypeEnum.EMAIL,
243
- name: 'class-id-html-template',
244
- scope: 'system',
245
- context: {}
246
- });
247
-
248
- expectHtmlStructure(
249
- result.content,
250
- '<div class="container" id="main">Main content</div>'
251
- );
252
- });
253
- });
254
- });
@@ -1,422 +0,0 @@
1
- import { DataSource, Repository } from 'typeorm';
2
- import { createTestModule } from './test.setup';
3
- import { TemplateTypeEnum, TemplateEngineEnum, TemplateLanguageEnum } from '../lib/interfaces/template.types';
4
- import { CreateTemplateDto } from '../lib/dto/create-template.dto';
5
- import { ForbiddenException, NotFoundException } from '@nestjs/common';
6
- import { NestDynamicTemplateLayout } from '../lib/entities/template-layout.entity';
7
- import { TemplateLayoutService } from '../lib/services/template-layout.service';
8
-
9
- describe('Template Layout Service', () => {
10
- let service: TemplateLayoutService;
11
- let dataSource: DataSource;
12
- let templateLayoutRepository: Repository<NestDynamicTemplateLayout>;
13
-
14
- const testTemplate: CreateTemplateDto = {
15
- name: 'test-template',
16
- displayName: 'Test Template',
17
- content: 'Hello {{name}}!',
18
- type: TemplateTypeEnum.EMAIL,
19
- engine: TemplateEngineEnum.NUNJUCKS,
20
- language: TemplateLanguageEnum.HTML,
21
- scope: 'system',
22
- scopeId: null,
23
- locale: 'en',
24
- isActive: true
25
- };
26
-
27
- beforeEach(async () => {
28
- const moduleRef = await createTestModule();
29
-
30
- service = moduleRef.get<TemplateLayoutService>(TemplateLayoutService);
31
- dataSource = moduleRef.get<DataSource>(DataSource);
32
- templateLayoutRepository = dataSource.getRepository(NestDynamicTemplateLayout);
33
- });
34
-
35
- afterEach(async () => {
36
- // Clean up templates
37
- await templateLayoutRepository.delete('1 = 1');
38
-
39
- // Clean up database after each test
40
- await dataSource.synchronize(true);
41
- });
42
-
43
- afterAll(async () => {
44
- // Close the connection after all tests
45
- await dataSource.destroy();
46
- });
47
-
48
- describe('System Template Layout Management', () => {
49
- it('should create system template layout', async () => {
50
- const result = await service.createTemplateLayout(testTemplate);
51
-
52
- expect(result).toBeDefined();
53
- expect(result.name).toBe(testTemplate.name);
54
- expect(result.scope).toBe('system');
55
- expect(result.scopeId).toBeNull();
56
-
57
- // Verify template was saved in database
58
- const savedTemplate = await templateLayoutRepository.findOne({ where: { id: result.id } });
59
- expect(savedTemplate).toBeDefined();
60
- expect(savedTemplate.name).toBe(testTemplate.name);
61
- });
62
-
63
- it('should not create other then system template layout', async () => {
64
- await expect(service.createTemplateLayout({
65
- ...testTemplate,
66
- scope: 'custom',
67
- scopeId: '123',
68
- content: 'Custom content for {{name}}'
69
- })).rejects.toThrow(ForbiddenException);
70
- });
71
-
72
- it('should find system template', async () => {
73
- // First create a template
74
- const created = await service.createTemplateLayout(testTemplate);
75
-
76
- // Then find it
77
- const found = await service.findTemplateLayout(
78
- testTemplate.name,
79
- testTemplate.scope,
80
- testTemplate.scopeId,
81
- );
82
-
83
- expect(found).toBeDefined();
84
- expect(found.id).toBe(created.id);
85
- expect(found.name).toBe(testTemplate.name);
86
- expect(found.scope).toBe(testTemplate.scope);
87
- });
88
-
89
- it('should find system template layout when template layout not found with given scope', async () => {
90
- // Create system template layout
91
- const created = await service.createTemplateLayout(testTemplate);
92
-
93
- // Then find it with custom scope
94
- const found = await service.findTemplateLayout(
95
- testTemplate.name,
96
- 'custom',
97
- '123',
98
- );
99
-
100
- // Verify template was found and is the system template
101
- expect(found).toBeDefined();
102
- expect(found).not.toBeNull();
103
- expect(found.id).toBe(created.id);
104
- expect(found.name).toBe(testTemplate.name);
105
- expect(found.scope).toBe('system');
106
- expect(found.scopeId).toBeNull();
107
- });
108
-
109
- it('should not find template layout when template layout not found in any scope and system', async () => {
110
- // Try to find non-existent template layout
111
- const result = await service.findTemplateLayout(
112
- 'non-existent-template',
113
- 'custom',
114
- '123',
115
- );
116
-
117
- expect(result).toBeNull();
118
- });
119
-
120
- it('should not find template layout when template layout not found in system scope', async () => {
121
- // Try to find non-existent template layout in system scope
122
- const result = await service.findTemplateLayout(
123
- 'non-existent-template',
124
- 'system',
125
- null,
126
- );
127
-
128
- expect(result).toBeNull();
129
- });
130
-
131
- it('should update system template when canUpdateSystemTemplate is true', async () => {
132
- // First create a template
133
- const created = await service.createTemplateLayout(testTemplate);
134
-
135
- // Then update it
136
- const result = await service.updateTemplateLayout(created.id, {
137
- content: 'Updated system content for {{name}}'
138
- }, true);
139
-
140
- expect(result).toBeDefined();
141
- expect(result.content).toBe('Updated system content for {{name}}');
142
- expect(result.scope).toBe('system');
143
-
144
- // Verify update in database
145
- const updatedTemplate = await templateLayoutRepository.findOne({ where: { id: created.id } });
146
- expect(updatedTemplate.content).toBe('Updated system content for {{name}}');
147
- });
148
-
149
- it('should not update system template layout when canUpdateSystemTemplate is false, it should throw ForbiddenException', async () => {
150
- // First create a template layout
151
- const created = await service.createTemplateLayout(testTemplate);
152
-
153
- // Then update it with canUpdateSystemTemplate set to false
154
- await expect(service.updateTemplateLayout(created.id, {
155
- content: 'Updated system content for {{name}}'
156
- }, false)).rejects.toThrow(ForbiddenException);
157
-
158
-
159
- // Verify template was not updated
160
- const updatedTemplate = await templateLayoutRepository.findOne({ where: { id: created.id } });
161
- expect(updatedTemplate.content).toBe(testTemplate.content);
162
- });
163
-
164
-
165
- it('should not update system template layout when canUpdateSystemTemplate is false, but scope is not system then overwrite the template layout', async () => {
166
- // First create a template layout
167
- const created = await service.createTemplateLayout(testTemplate);
168
-
169
- // Then update it with canUpdateSystemTemplate set to false
170
- await service.updateTemplateLayout(created.id, {
171
- scope: 'custom',
172
- scopeId: '123',
173
- content: 'Updated system content for {{name}}'
174
- }, false);
175
-
176
-
177
- // Verify system template was not updated
178
- const updatedTemplate = await templateLayoutRepository.findOne({ where: { id: created.id } });
179
- expect(updatedTemplate.content).toBe(testTemplate.content);
180
-
181
- // Verify overwrite template was created
182
- const overwrittenTemplate = await service.findTemplateLayout(
183
- testTemplate.name,
184
- 'custom',
185
- '123',
186
- );
187
- expect(overwrittenTemplate.content).toBe('Updated system content for {{name}}');
188
- });
189
-
190
- it('should delete system template layout when canDeleteSystemTemplate is true', async () => {
191
- // First create a template layout
192
- const created = await service.createTemplateLayout(testTemplate);
193
-
194
- // Then delete it
195
- await service.deleteTemplateLayout(created.id, true);
196
-
197
- // Verify template was deleted
198
- const deletedTemplate = await templateLayoutRepository.findOne({ where: { id: created.id } });
199
- expect(deletedTemplate).toBeNull();
200
- });
201
-
202
- it('should not delete system template when canDeleteSystemTemplate is false, it should throw ForbiddenException', async () => {
203
- // First create a template
204
- const created = await service.createTemplateLayout(testTemplate);
205
-
206
- // Then delete it
207
- await expect(service.deleteTemplateLayout(created.id, false)).rejects.toThrow(ForbiddenException);
208
-
209
- // Verify template was not deleted
210
- const deletedTemplate = await templateLayoutRepository.findOne({ where: { id: created.id } });
211
- expect(deletedTemplate).toBeDefined();
212
- });
213
- });
214
-
215
- describe('Render System Template Layout', () => {
216
- it('should render system template layout', async () => {
217
- // Create system template layout
218
- await service.createTemplateLayout(testTemplate);
219
-
220
- // Render template
221
- const renderedResult = await service.render({
222
- name: testTemplate.name,
223
- scope: testTemplate.scope,
224
- scopeId: testTemplate.scopeId,
225
- context: { name: 'John' }
226
- });
227
-
228
- // Verify template was rendered correctly
229
- expect(renderedResult).toEqual({
230
- subject: undefined,
231
- content: 'Hello John!'
232
- });
233
- });
234
-
235
- it('should not render system template layout when not found', async () => {
236
- // Render template
237
- await expect(service.render({
238
- name: testTemplate.name,
239
- scope: testTemplate.scope,
240
- scopeId: testTemplate.scopeId,
241
- context: { name: 'John' }
242
- })).rejects.toThrow(NotFoundException);
243
- });
244
-
245
- it('should render system template layout even scope not system and template layout not found with given scope', async () => {
246
- // Create system template layout
247
- await service.createTemplateLayout(testTemplate);
248
-
249
- // Render template
250
- const renderedResult = await service.render({
251
- name: testTemplate.name,
252
- scope: 'custom',
253
- scopeId: '123',
254
- context: { name: 'John' }
255
- });
256
-
257
- expect(renderedResult).toEqual({
258
- subject: undefined,
259
- content: 'Hello John!'
260
- });
261
- });
262
- });
263
-
264
- describe('Custom Scope Template Layout Management', () => {
265
- it('should create overwrite template layout for custom scope', async () => {
266
- // Create system template layout
267
- const systemTemplateLayout = await service.createTemplateLayout(testTemplate);
268
-
269
- // Then create overwrite template layout
270
- const overwriteTemplateLayout = await service.overwriteSystemTemplateLayout(systemTemplateLayout.id, {
271
- ...testTemplate,
272
- scope: 'custom',
273
- scopeId: '123',
274
- content: 'Custom content for {{name}}'
275
- });
276
-
277
- expect(overwriteTemplateLayout).toBeDefined();
278
- expect(overwriteTemplateLayout.scope).toBe('custom');
279
- expect(overwriteTemplateLayout.scopeId).toBe('123');
280
- expect(overwriteTemplateLayout.content).toBe('Custom content for {{name}}');
281
-
282
- // Verify system template is not affected by overwrite template
283
- const oldSystemTemplate = await templateLayoutRepository.findOne({
284
- where: { name: testTemplate.name, scope: 'system' }
285
- });
286
- expect(oldSystemTemplate).toBeDefined();
287
-
288
- // Verify system template and overwrite template are different
289
- expect(systemTemplateLayout.id).not.toBe(overwriteTemplateLayout.id);
290
-
291
- // Verify system template content is not affected by overwrite template
292
- expect(oldSystemTemplate.id).toBe(systemTemplateLayout.id);
293
- expect(oldSystemTemplate.content).toBe(systemTemplateLayout.content);
294
- });
295
-
296
- it('should update overwrite template layout without affecting system template layout', async () => {
297
- // Create system template layout
298
- const systemTemplateLayout = await service.createTemplateLayout(testTemplate);
299
-
300
- // Create overwrite template layout
301
- const overwriteTemplateLayout = await service.overwriteSystemTemplateLayout(systemTemplateLayout.id, {
302
- ...testTemplate,
303
- scope: 'custom',
304
- scopeId: '123',
305
- content: 'Custom content for {{name}}'
306
- });
307
-
308
- // Update overwrite template layout
309
- const result = await service.updateTemplateLayout(overwriteTemplateLayout.id, {
310
- content: 'Updated custom content for {{name}}'
311
- });
312
-
313
- expect(result).toBeDefined();
314
- expect(result.scope).toBe('custom');
315
- expect(result.scopeId).toBe('123');
316
- expect(result.content).toBe('Updated custom content for {{name}}');
317
-
318
- // Verify system template remains unchanged
319
- const oldSystemTemplate = await templateLayoutRepository.findOne({
320
- where: { name: testTemplate.name, scope: 'system' }
321
- });
322
- expect(oldSystemTemplate.content).toBe(systemTemplateLayout.content);
323
- });
324
-
325
- it('should not overwrite already overwritten template layout, it should return the already overwritten template layout but with updated fields', async () => {
326
- // Create system template layout
327
- const systemTemplateLayout = await service.createTemplateLayout(testTemplate);
328
-
329
- // Create overwrite template layout
330
- const overwrittenTemplateLayout = await service.overwriteSystemTemplateLayout(systemTemplateLayout.id, {
331
- ...testTemplate,
332
- scope: 'custom',
333
- scopeId: '123',
334
- content: 'Custom content for {{name}}'
335
- });
336
-
337
- // Try to overwrite again
338
- const result = await service.overwriteSystemTemplateLayout(systemTemplateLayout.id, {
339
- ...testTemplate,
340
- scope: 'custom',
341
- scopeId: '123',
342
- content: 'Updated custom content for {{name}}'
343
- })
344
-
345
- // Verify the result is the same as the already overwritten template
346
- expect(result).toBeDefined();
347
- expect(result.id).toBe(overwrittenTemplateLayout.id);
348
- expect(result.content).toBe('Updated custom content for {{name}}');
349
- });
350
-
351
- it('should find overwrite template when available', async () => {
352
- // Create system template layout
353
- const systemTemplateLayout = await service.createTemplateLayout(testTemplate);
354
-
355
- // Create overwrite template layout
356
- await service.overwriteSystemTemplateLayout(systemTemplateLayout.id, {
357
- ...testTemplate,
358
- scope: 'custom',
359
- scopeId: '123',
360
- content: 'Custom content for {{name}}'
361
- });
362
-
363
- // Find overwrite template layout
364
- const found = await service.findTemplateLayout(
365
- testTemplate.name,
366
- 'custom',
367
- '123',
368
- testTemplate.language
369
- );
370
-
371
- expect(found).toBeDefined();
372
- expect(found.content).toBe('Custom content for {{name}}');
373
- expect(found.scope).toBe('custom');
374
- expect(found.scopeId).toBe('123');
375
- })
376
-
377
- it('should render overwrite template when available', async () => {
378
- // Create system template layout
379
- const systemTemplateLayout = await service.createTemplateLayout(testTemplate);
380
-
381
- // Create overwrite template layout
382
- await service.overwriteSystemTemplateLayout(systemTemplateLayout.id, {
383
- ...testTemplate,
384
- scope: 'custom',
385
- scopeId: '123',
386
- content: 'Custom content for {{name}}'
387
- });
388
-
389
- const result = await service.render({
390
- name: testTemplate.name,
391
- scope: 'custom',
392
- scopeId: '123',
393
- locale: testTemplate.language,
394
- context: { name: 'John' }
395
- });
396
-
397
- expect(result).toEqual({
398
- subject: undefined,
399
- content: 'Custom content for John'
400
- });
401
- });
402
-
403
- it('should not fail render when overwrite template layout not found', async () => {
404
- // Create only system template layout
405
- await service.createTemplateLayout(testTemplate);
406
-
407
- const result = await service.render({
408
- name: testTemplate.name,
409
- scope: 'custom',
410
- scopeId: '123',
411
- locale: testTemplate.language,
412
- context: { name: 'John' }
413
- });
414
-
415
- expect(result).toEqual({
416
- subject: undefined,
417
- content: 'Hello John!'
418
- });
419
- });
420
- });
421
-
422
- });