@strapi/strapi 4.10.0 → 4.10.1-experimental.0
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/coverage/clover.xml +1613 -0
- package/coverage/coverage-final.json +48 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/commands/__tests__/data-transfer/shared/index.html +116 -0
- package/coverage/lcov-report/commands/__tests__/data-transfer/shared/transfer.test.utils.js.html +133 -0
- package/coverage/lcov-report/commands/admin-create.js.html +424 -0
- package/coverage/lcov-report/commands/admin-reset.js.html +241 -0
- package/coverage/lcov-report/commands/generate-template.js.html +373 -0
- package/coverage/lcov-report/commands/index.html +146 -0
- package/coverage/lcov-report/commands/transfer/export.js.html +619 -0
- package/coverage/lcov-report/commands/transfer/import.js.html +562 -0
- package/coverage/lcov-report/commands/transfer/index.html +146 -0
- package/coverage/lcov-report/commands/transfer/transfer.js.html +532 -0
- package/coverage/lcov-report/commands/utils/helpers.js.html +430 -0
- package/coverage/lcov-report/commands/utils/index.html +116 -0
- package/coverage/lcov-report/core/registries/custom-fields.js.html +301 -0
- package/coverage/lcov-report/core/registries/index.html +116 -0
- package/coverage/lcov-report/core-api/controller/collection-type.js.html +418 -0
- package/coverage/lcov-report/core-api/controller/index.html +161 -0
- package/coverage/lcov-report/core-api/controller/index.js.html +220 -0
- package/coverage/lcov-report/core-api/controller/single-type.js.html +274 -0
- package/coverage/lcov-report/core-api/controller/transform.js.html +376 -0
- package/coverage/lcov-report/core-api/service/collection-type.js.html +325 -0
- package/coverage/lcov-report/core-api/service/index.html +161 -0
- package/coverage/lcov-report/core-api/service/index.js.html +220 -0
- package/coverage/lcov-report/core-api/service/pagination.js.html +460 -0
- package/coverage/lcov-report/core-api/service/single-type.js.html +301 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +386 -0
- package/coverage/lcov-report/load/filepath-to-prop-path.js.html +151 -0
- package/coverage/lcov-report/load/index.html +116 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/services/content-api/index.html +116 -0
- package/coverage/lcov-report/services/content-api/index.js.html +307 -0
- package/coverage/lcov-report/services/content-api/permissions/engine.js.html +100 -0
- package/coverage/lcov-report/services/content-api/permissions/index.html +131 -0
- package/coverage/lcov-report/services/content-api/permissions/index.js.html +529 -0
- package/coverage/lcov-report/services/content-api/permissions/providers/action.js.html +142 -0
- package/coverage/lcov-report/services/content-api/permissions/providers/condition.js.html +142 -0
- package/coverage/lcov-report/services/content-api/permissions/providers/index.html +146 -0
- package/coverage/lcov-report/services/content-api/permissions/providers/index.js.html +112 -0
- package/coverage/lcov-report/services/core-store.js.html +520 -0
- package/coverage/lcov-report/services/entity-service/attributes/index.html +131 -0
- package/coverage/lcov-report/services/entity-service/attributes/index.js.html +178 -0
- package/coverage/lcov-report/services/entity-service/attributes/transforms.js.html +145 -0
- package/coverage/lcov-report/services/entity-service/components.js.html +1246 -0
- package/coverage/lcov-report/services/entity-service/index.html +146 -0
- package/coverage/lcov-report/services/entity-service/index.js.html +1120 -0
- package/coverage/lcov-report/services/entity-service/params.js.html +112 -0
- package/coverage/lcov-report/services/entity-validator/__tests__/relations/utils/index.html +116 -0
- package/coverage/lcov-report/services/entity-validator/__tests__/relations/utils/relations.testdata.js.html +544 -0
- package/coverage/lcov-report/services/entity-validator/index.html +131 -0
- package/coverage/lcov-report/services/entity-validator/index.js.html +1231 -0
- package/coverage/lcov-report/services/entity-validator/validators.js.html +733 -0
- package/coverage/lcov-report/services/event-hub.js.html +319 -0
- package/coverage/lcov-report/services/fs.js.html +259 -0
- package/coverage/lcov-report/services/index.html +161 -0
- package/coverage/lcov-report/services/metrics/admin-user-hash.js.html +148 -0
- package/coverage/lcov-report/services/metrics/index.html +206 -0
- package/coverage/lcov-report/services/metrics/index.js.html +265 -0
- package/coverage/lcov-report/services/metrics/is-truthy.js.html +112 -0
- package/coverage/lcov-report/services/metrics/middleware.js.html +184 -0
- package/coverage/lcov-report/services/metrics/rate-limiter.js.html +166 -0
- package/coverage/lcov-report/services/metrics/sender.js.html +394 -0
- package/coverage/lcov-report/services/metrics/stringify-deep.js.html +151 -0
- package/coverage/lcov-report/services/utils/index.html +116 -0
- package/coverage/lcov-report/services/utils/upload-files.js.html +322 -0
- package/coverage/lcov-report/services/worker-queue.js.html +262 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov-report/utils/convert-custom-field-type.js.html +151 -0
- package/coverage/lcov-report/utils/index.html +146 -0
- package/coverage/lcov-report/utils/machine-id.js.html +127 -0
- package/coverage/lcov-report/utils/url-from-segments.js.html +121 -0
- package/lib/commands/__tests__/commands.test.js +20 -0
- package/lib/commands/__tests__/commands.test.utils.js +16 -0
- package/lib/commands/actions/admin/create-user/__tests__/admin.create-user.test.js +450 -0
- package/lib/commands/actions/admin/reset-user-password/__tests__/admin.reset-user-password.test.js +145 -0
- package/lib/commands/actions/build/action.js +18 -0
- package/lib/commands/actions/build/command.js +15 -0
- package/lib/commands/actions/export/__tests__/export.test.js +175 -0
- package/lib/commands/actions/import/__tests__/import.test.js +143 -0
- package/lib/commands/actions/templates/generate/__tests__/templates.generate.js +118 -0
- package/lib/commands/actions/transfer/__tests__/transfer.test.js +178 -0
- package/lib/core/registries/__tests__/custom-fields.test.js +152 -0
- package/lib/core-api/__tests__/controller.test.js +39 -0
- package/lib/core-api/controller/__tests__/transform.test.js +226 -0
- package/lib/core-api/service/__tests__/index.test.js +127 -0
- package/lib/core-api/service/__tests__/pagination.test.js +275 -0
- package/lib/load/__tests__/filepath-to-prop-path.test.js +30 -0
- package/lib/middlewares/__tests__/errors.test.js +21 -0
- package/lib/services/__tests__/content-api-permissions.test.js +291 -0
- package/lib/services/__tests__/core-store.test.js +148 -0
- package/lib/services/__tests__/event-hub.test.js +126 -0
- package/lib/services/__tests__/fs.test.js +78 -0
- package/lib/services/__tests__/worker-queue.test.js +47 -0
- package/lib/services/entity-service/__tests__/entity-service-events.test.js +117 -0
- package/lib/services/entity-service/__tests__/entity-service.test.js +587 -0
- package/lib/services/entity-validator/__tests__/biginteger-validators.test.js +220 -0
- package/lib/services/entity-validator/__tests__/date-validators.test.js +183 -0
- package/lib/services/entity-validator/__tests__/datetime-validators.test.js +183 -0
- package/lib/services/entity-validator/__tests__/email-validators.test.js +56 -0
- package/lib/services/entity-validator/__tests__/enumeration-validators.test.js +43 -0
- package/lib/services/entity-validator/__tests__/float-validators.test.js +278 -0
- package/lib/services/entity-validator/__tests__/index.test.js +609 -0
- package/lib/services/entity-validator/__tests__/integer-validators.test.js +278 -0
- package/lib/services/entity-validator/__tests__/relations/attribute-level.test.js +123 -0
- package/lib/services/entity-validator/__tests__/relations/component-level.test.js +275 -0
- package/lib/services/entity-validator/__tests__/relations/dynamic-zone-level.test.js +159 -0
- package/lib/services/entity-validator/__tests__/relations/media-level.test.js +74 -0
- package/lib/services/entity-validator/__tests__/relations/utils/relations.testdata.js +153 -0
- package/lib/services/entity-validator/__tests__/string-validators.test.js +374 -0
- package/lib/services/entity-validator/__tests__/time-validators.test.js +183 -0
- package/lib/services/entity-validator/__tests__/timestamp-validators.test.js +204 -0
- package/lib/services/entity-validator/__tests__/uid-validators.test.js +229 -0
- package/lib/services/metrics/__tests__/admin-user-hash.test.js +41 -0
- package/lib/services/metrics/__tests__/index.test.js +157 -0
- package/lib/services/metrics/__tests__/is-truthy.js +33 -0
- package/lib/services/metrics/__tests__/middleware.test.js +60 -0
- package/lib/services/metrics/__tests__/rate-limiter.test.js +50 -0
- package/lib/services/metrics/__tests__/stringify-deep.test.js +27 -0
- package/lib/utils/__tests__/convert-custom-field-type.test.js +69 -0
- package/lib/utils/__tests__/url-from-segments.test.js +40 -0
- package/package.json +15 -15
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const roleId = 1;
|
|
4
|
+
const load = jest.fn(() => mock);
|
|
5
|
+
|
|
6
|
+
const create = jest.fn();
|
|
7
|
+
const getSuperAdmin = jest.fn(() => Promise.resolve({ id: roleId }));
|
|
8
|
+
const exists = jest.fn();
|
|
9
|
+
|
|
10
|
+
const admin = {
|
|
11
|
+
services: {
|
|
12
|
+
user: {
|
|
13
|
+
create,
|
|
14
|
+
exists,
|
|
15
|
+
},
|
|
16
|
+
role: {
|
|
17
|
+
getSuperAdmin,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const mock = {
|
|
23
|
+
load,
|
|
24
|
+
admin,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
jest.mock('@strapi/strapi', () => {
|
|
28
|
+
const impl = jest.fn(() => mock);
|
|
29
|
+
|
|
30
|
+
impl.compile = jest.fn();
|
|
31
|
+
|
|
32
|
+
return impl;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const inquirer = require('inquirer');
|
|
36
|
+
const createAdminCommand = require('../action');
|
|
37
|
+
|
|
38
|
+
describe('admin:create command', () => {
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
load.mockClear();
|
|
41
|
+
create.mockClear();
|
|
42
|
+
getSuperAdmin.mockClear();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('createAdminCommand accepts direct input', async () => {
|
|
46
|
+
const email = 'email@email.fr';
|
|
47
|
+
const password = 'testPasword1234';
|
|
48
|
+
const firstname = 'John';
|
|
49
|
+
const lastname = 'Doe';
|
|
50
|
+
|
|
51
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
|
|
52
|
+
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
53
|
+
|
|
54
|
+
await createAdminCommand({ email, password, firstname, lastname });
|
|
55
|
+
|
|
56
|
+
expect(mockExit).toHaveBeenCalledWith(0);
|
|
57
|
+
expect(consoleLog).toHaveBeenCalled();
|
|
58
|
+
expect(load).toHaveBeenCalled();
|
|
59
|
+
expect(getSuperAdmin).toHaveBeenCalled();
|
|
60
|
+
expect(create).toHaveBeenCalledWith(
|
|
61
|
+
expect.objectContaining({ email, password, firstname, lastname })
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
mockExit.mockRestore();
|
|
65
|
+
consoleLog.mockRestore();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('Handles prompt input', () => {
|
|
69
|
+
test('Only prompt on TTY', async () => {
|
|
70
|
+
const tmpTTY = process.stdin.isTTY;
|
|
71
|
+
process.stdin.isTTY = false;
|
|
72
|
+
|
|
73
|
+
// throw so the code will stop executing
|
|
74
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
75
|
+
throw new Error('exit');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
79
|
+
|
|
80
|
+
await createAdminCommand().catch((err) => {
|
|
81
|
+
expect(err).toEqual(new Error('exit'));
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
expect(consoleError).toBeCalledWith('First name is required');
|
|
85
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
86
|
+
expect(load).not.toHaveBeenCalled();
|
|
87
|
+
expect(getSuperAdmin).not.toHaveBeenCalled();
|
|
88
|
+
expect(create).not.toHaveBeenCalled();
|
|
89
|
+
|
|
90
|
+
process.stdin.isTTY = tmpTTY;
|
|
91
|
+
mockExit.mockRestore();
|
|
92
|
+
consoleError.mockRestore();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('Stops if not confirmed', async () => {
|
|
96
|
+
process.stdin.isTTY = true;
|
|
97
|
+
const email = 'email@email.fr';
|
|
98
|
+
const password = 'testPasword1234';
|
|
99
|
+
const firstname = 'John';
|
|
100
|
+
const lastname = 'Doe';
|
|
101
|
+
|
|
102
|
+
const mockInquiry = jest.spyOn(inquirer, 'prompt').mockImplementationOnce(async () => ({
|
|
103
|
+
email,
|
|
104
|
+
password,
|
|
105
|
+
firstname,
|
|
106
|
+
lastname,
|
|
107
|
+
confirm: false,
|
|
108
|
+
}));
|
|
109
|
+
|
|
110
|
+
// throw so the code will stop executing
|
|
111
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
112
|
+
throw new Error('exit');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await createAdminCommand().catch((err) => {
|
|
116
|
+
expect(err).toEqual(new Error('exit'));
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(mockInquiry).toHaveBeenLastCalledWith([
|
|
120
|
+
expect.objectContaining({
|
|
121
|
+
message: expect.any(String),
|
|
122
|
+
name: 'email',
|
|
123
|
+
type: 'input',
|
|
124
|
+
}),
|
|
125
|
+
expect.objectContaining({
|
|
126
|
+
message: expect.any(String),
|
|
127
|
+
name: 'password',
|
|
128
|
+
type: 'password',
|
|
129
|
+
}),
|
|
130
|
+
expect.objectContaining({
|
|
131
|
+
message: expect.any(String),
|
|
132
|
+
name: 'firstname',
|
|
133
|
+
type: 'input',
|
|
134
|
+
}),
|
|
135
|
+
expect.objectContaining({
|
|
136
|
+
message: expect.any(String),
|
|
137
|
+
name: 'lastname',
|
|
138
|
+
type: 'input',
|
|
139
|
+
}),
|
|
140
|
+
expect.objectContaining({
|
|
141
|
+
message: expect.any(String),
|
|
142
|
+
name: 'confirm',
|
|
143
|
+
type: 'confirm',
|
|
144
|
+
}),
|
|
145
|
+
]);
|
|
146
|
+
expect(mockExit).toHaveBeenCalledWith(0);
|
|
147
|
+
expect(load).not.toHaveBeenCalled();
|
|
148
|
+
expect(getSuperAdmin).not.toHaveBeenCalled();
|
|
149
|
+
expect(create).not.toHaveBeenCalled();
|
|
150
|
+
|
|
151
|
+
mockExit.mockRestore();
|
|
152
|
+
mockInquiry.mockRestore();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('Calls the create method with user input', async () => {
|
|
156
|
+
const email = 'email@email.fr';
|
|
157
|
+
const password = 'testPasword1234';
|
|
158
|
+
const firstname = 'John';
|
|
159
|
+
const lastname = 'Doe';
|
|
160
|
+
|
|
161
|
+
const mockInquiry = jest.spyOn(inquirer, 'prompt').mockImplementationOnce(async () => ({
|
|
162
|
+
email,
|
|
163
|
+
password,
|
|
164
|
+
firstname,
|
|
165
|
+
lastname,
|
|
166
|
+
confirm: true,
|
|
167
|
+
}));
|
|
168
|
+
|
|
169
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
|
|
170
|
+
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
171
|
+
|
|
172
|
+
await createAdminCommand();
|
|
173
|
+
|
|
174
|
+
expect(mockExit).toHaveBeenCalledWith(0);
|
|
175
|
+
expect(consoleLog).toHaveBeenCalled();
|
|
176
|
+
expect(load).toHaveBeenCalled();
|
|
177
|
+
expect(getSuperAdmin).toHaveBeenCalled();
|
|
178
|
+
expect(create).toHaveBeenCalledWith(
|
|
179
|
+
expect.objectContaining({ email, password, firstname, lastname })
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
mockInquiry.mockRestore();
|
|
183
|
+
mockExit.mockRestore();
|
|
184
|
+
consoleLog.mockRestore();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test('Creates registration token if password is not passed', async () => {
|
|
188
|
+
const email = 'email@email.fr';
|
|
189
|
+
const firstname = 'John';
|
|
190
|
+
const lastname = 'Doe';
|
|
191
|
+
|
|
192
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
|
|
193
|
+
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
194
|
+
const mockInquiry = jest.spyOn(inquirer, 'prompt').mockImplementationOnce(async () => ({
|
|
195
|
+
email,
|
|
196
|
+
firstname,
|
|
197
|
+
lastname,
|
|
198
|
+
confirm: true,
|
|
199
|
+
}));
|
|
200
|
+
|
|
201
|
+
await createAdminCommand();
|
|
202
|
+
|
|
203
|
+
expect(getSuperAdmin).toHaveBeenCalled();
|
|
204
|
+
expect(create).toHaveBeenCalledWith(
|
|
205
|
+
expect.objectContaining({
|
|
206
|
+
email,
|
|
207
|
+
firstname,
|
|
208
|
+
lastname,
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
expect.not.objectContaining({ password: expect.any(String), registrationToken: null });
|
|
212
|
+
|
|
213
|
+
mockInquiry.mockRestore();
|
|
214
|
+
mockExit.mockRestore();
|
|
215
|
+
consoleLog.mockRestore();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test('Sets registration token to null if password is passed', async () => {
|
|
219
|
+
const email = 'email@email.fr';
|
|
220
|
+
const password = 'testPasword1234';
|
|
221
|
+
const firstname = 'John';
|
|
222
|
+
const lastname = 'Doe';
|
|
223
|
+
|
|
224
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
|
|
225
|
+
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
226
|
+
const mockInquiry = jest.spyOn(inquirer, 'prompt').mockImplementationOnce(async () => ({
|
|
227
|
+
email,
|
|
228
|
+
password,
|
|
229
|
+
firstname,
|
|
230
|
+
lastname,
|
|
231
|
+
confirm: true,
|
|
232
|
+
}));
|
|
233
|
+
|
|
234
|
+
await createAdminCommand();
|
|
235
|
+
|
|
236
|
+
expect(getSuperAdmin).toHaveBeenCalled();
|
|
237
|
+
expect(create).toHaveBeenCalledWith(
|
|
238
|
+
expect.objectContaining({ email, password, firstname, lastname, registrationToken: null })
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
mockInquiry.mockRestore();
|
|
242
|
+
mockExit.mockRestore();
|
|
243
|
+
consoleLog.mockRestore();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test('Stops if the user already exists', async () => {
|
|
247
|
+
exists.mockImplementation(() => Promise.resolve(true));
|
|
248
|
+
|
|
249
|
+
const email = 'email@email.fr';
|
|
250
|
+
const password = 'testPasword1234';
|
|
251
|
+
const firstname = 'John';
|
|
252
|
+
const lastname = 'Doe';
|
|
253
|
+
|
|
254
|
+
const mockInquiry = jest.spyOn(inquirer, 'prompt').mockImplementationOnce(async () => ({
|
|
255
|
+
email,
|
|
256
|
+
password,
|
|
257
|
+
firstname,
|
|
258
|
+
lastname,
|
|
259
|
+
confirm: true,
|
|
260
|
+
}));
|
|
261
|
+
|
|
262
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
263
|
+
throw new Error('exit');
|
|
264
|
+
});
|
|
265
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
266
|
+
|
|
267
|
+
await createAdminCommand().catch((err) => {
|
|
268
|
+
expect(err).toEqual(new Error('exit'));
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
expect(consoleError).toBeCalledWith('User with email "email@email.fr" already exists');
|
|
272
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
273
|
+
expect(exists).toHaveBeenCalledWith(expect.objectContaining({ email }));
|
|
274
|
+
expect(getSuperAdmin).not.toHaveBeenCalled();
|
|
275
|
+
expect(create).not.toHaveBeenCalled();
|
|
276
|
+
|
|
277
|
+
exists.mockRestore();
|
|
278
|
+
mockExit.mockRestore();
|
|
279
|
+
mockInquiry.mockRestore();
|
|
280
|
+
consoleError.mockRestore();
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe('Validation', () => {
|
|
285
|
+
test('Handles invalid email', async () => {
|
|
286
|
+
const email = 'email.@email.fr';
|
|
287
|
+
const password = 'testPasword1234';
|
|
288
|
+
const firstname = 'John';
|
|
289
|
+
const lastname = 'Doe';
|
|
290
|
+
|
|
291
|
+
const mockInquiry = jest.spyOn(inquirer, 'prompt').mockImplementationOnce(async () => ({
|
|
292
|
+
email,
|
|
293
|
+
password,
|
|
294
|
+
firstname,
|
|
295
|
+
lastname,
|
|
296
|
+
confirm: true,
|
|
297
|
+
}));
|
|
298
|
+
|
|
299
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
300
|
+
throw new Error('exit');
|
|
301
|
+
});
|
|
302
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
303
|
+
|
|
304
|
+
await createAdminCommand().catch((err) => {
|
|
305
|
+
expect(err).toEqual(new Error('exit'));
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
expect(consoleError).toBeCalledWith('Invalid email address');
|
|
309
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
310
|
+
expect(load).not.toHaveBeenCalled();
|
|
311
|
+
|
|
312
|
+
exists.mockRestore();
|
|
313
|
+
mockExit.mockRestore();
|
|
314
|
+
mockInquiry.mockRestore();
|
|
315
|
+
consoleError.mockRestore();
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test('Handles short passwords', async () => {
|
|
319
|
+
const email = 'email.@email.fr';
|
|
320
|
+
const password = '123';
|
|
321
|
+
const firstname = 'John';
|
|
322
|
+
const lastname = 'Doe';
|
|
323
|
+
|
|
324
|
+
const mockInquiry = jest.spyOn(inquirer, 'prompt').mockImplementationOnce(async () => ({
|
|
325
|
+
email,
|
|
326
|
+
password,
|
|
327
|
+
firstname,
|
|
328
|
+
lastname,
|
|
329
|
+
confirm: true,
|
|
330
|
+
}));
|
|
331
|
+
|
|
332
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
333
|
+
throw new Error('exit');
|
|
334
|
+
});
|
|
335
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
336
|
+
|
|
337
|
+
await createAdminCommand().catch((err) => {
|
|
338
|
+
expect(err).toEqual(new Error('exit'));
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
expect(consoleError).toBeCalledWith('Password must be at least 8 characters long');
|
|
342
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
343
|
+
expect(load).not.toHaveBeenCalled();
|
|
344
|
+
|
|
345
|
+
exists.mockRestore();
|
|
346
|
+
mockExit.mockRestore();
|
|
347
|
+
mockInquiry.mockRestore();
|
|
348
|
+
consoleError.mockRestore();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
test('Handles passwords without lowercase characters', async () => {
|
|
352
|
+
const email = 'email.@email.fr';
|
|
353
|
+
const password = '12345678';
|
|
354
|
+
const firstname = 'John';
|
|
355
|
+
const lastname = 'Doe';
|
|
356
|
+
|
|
357
|
+
const mockInquiry = jest.spyOn(inquirer, 'prompt').mockImplementationOnce(async () => ({
|
|
358
|
+
email,
|
|
359
|
+
password,
|
|
360
|
+
firstname,
|
|
361
|
+
lastname,
|
|
362
|
+
confirm: true,
|
|
363
|
+
}));
|
|
364
|
+
|
|
365
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
366
|
+
throw new Error('exit');
|
|
367
|
+
});
|
|
368
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
369
|
+
|
|
370
|
+
await createAdminCommand().catch((err) => {
|
|
371
|
+
expect(err).toEqual(new Error('exit'));
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
expect(consoleError).toBeCalledWith('Password must contain at least one lowercase character');
|
|
375
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
376
|
+
expect(load).not.toHaveBeenCalled();
|
|
377
|
+
|
|
378
|
+
exists.mockRestore();
|
|
379
|
+
mockExit.mockRestore();
|
|
380
|
+
mockInquiry.mockRestore();
|
|
381
|
+
consoleError.mockRestore();
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test('Handles passwords without uppercase characters', async () => {
|
|
385
|
+
const email = 'email.@email.fr';
|
|
386
|
+
const password = '1234567a';
|
|
387
|
+
const firstname = 'John';
|
|
388
|
+
const lastname = 'Doe';
|
|
389
|
+
|
|
390
|
+
const mockInquiry = jest.spyOn(inquirer, 'prompt').mockImplementationOnce(async () => ({
|
|
391
|
+
email,
|
|
392
|
+
password,
|
|
393
|
+
firstname,
|
|
394
|
+
lastname,
|
|
395
|
+
confirm: true,
|
|
396
|
+
}));
|
|
397
|
+
|
|
398
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
399
|
+
throw new Error('exit');
|
|
400
|
+
});
|
|
401
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
402
|
+
|
|
403
|
+
await createAdminCommand().catch((err) => {
|
|
404
|
+
expect(err).toEqual(new Error('exit'));
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
expect(consoleError).toBeCalledWith('Password must contain at least one uppercase character');
|
|
408
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
409
|
+
expect(load).not.toHaveBeenCalled();
|
|
410
|
+
|
|
411
|
+
exists.mockRestore();
|
|
412
|
+
mockExit.mockRestore();
|
|
413
|
+
mockInquiry.mockRestore();
|
|
414
|
+
consoleError.mockRestore();
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
test('Handles passwords without number', async () => {
|
|
418
|
+
const email = 'email.@email.fr';
|
|
419
|
+
const password = 'abcdefgH';
|
|
420
|
+
const firstname = 'John';
|
|
421
|
+
const lastname = 'Doe';
|
|
422
|
+
|
|
423
|
+
const mockInquiry = jest.spyOn(inquirer, 'prompt').mockImplementationOnce(async () => ({
|
|
424
|
+
email,
|
|
425
|
+
password,
|
|
426
|
+
firstname,
|
|
427
|
+
lastname,
|
|
428
|
+
confirm: true,
|
|
429
|
+
}));
|
|
430
|
+
|
|
431
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
432
|
+
throw new Error('exit');
|
|
433
|
+
});
|
|
434
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
435
|
+
|
|
436
|
+
await createAdminCommand().catch((err) => {
|
|
437
|
+
expect(err).toEqual(new Error('exit'));
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
expect(consoleError).toBeCalledWith('Password must contain at least one number');
|
|
441
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
442
|
+
expect(load).not.toHaveBeenCalled();
|
|
443
|
+
|
|
444
|
+
exists.mockRestore();
|
|
445
|
+
mockExit.mockRestore();
|
|
446
|
+
mockInquiry.mockRestore();
|
|
447
|
+
consoleError.mockRestore();
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
});
|
package/lib/commands/actions/admin/reset-user-password/__tests__/admin.reset-user-password.test.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const load = jest.fn(() => mock);
|
|
4
|
+
const resetPasswordByEmail = jest.fn();
|
|
5
|
+
const admin = {
|
|
6
|
+
services: {
|
|
7
|
+
user: {
|
|
8
|
+
resetPasswordByEmail,
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const mock = {
|
|
14
|
+
load,
|
|
15
|
+
admin,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
jest.mock('@strapi/strapi', () => {
|
|
19
|
+
const impl = jest.fn(() => mock);
|
|
20
|
+
|
|
21
|
+
impl.compile = jest.fn();
|
|
22
|
+
|
|
23
|
+
return impl;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const inquirer = require('inquirer');
|
|
27
|
+
const resetAdminPasswordCommand = require('../action');
|
|
28
|
+
|
|
29
|
+
describe('admin:reset-password command', () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
load.mockClear();
|
|
32
|
+
resetPasswordByEmail.mockClear();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('resetAdminPasswordCommand accepts direct input', async () => {
|
|
36
|
+
const email = 'email@email.fr';
|
|
37
|
+
const password = 'testPasword1234';
|
|
38
|
+
|
|
39
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
|
|
40
|
+
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
41
|
+
|
|
42
|
+
await resetAdminPasswordCommand({ email, password });
|
|
43
|
+
|
|
44
|
+
expect(mockExit).toHaveBeenCalledWith(0);
|
|
45
|
+
expect(consoleLog).toHaveBeenCalled();
|
|
46
|
+
expect(load).toHaveBeenCalled();
|
|
47
|
+
expect(resetPasswordByEmail).toHaveBeenCalledWith(email, password);
|
|
48
|
+
|
|
49
|
+
mockExit.mockRestore();
|
|
50
|
+
consoleLog.mockRestore();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('Handles prompt input', () => {
|
|
54
|
+
test('Only prompt on TTY', async () => {
|
|
55
|
+
const tmpTTY = process.stdin.isTTY;
|
|
56
|
+
process.stdin.isTTY = false;
|
|
57
|
+
|
|
58
|
+
// throw so the code will stop executing
|
|
59
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
60
|
+
throw new Error('exit');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
64
|
+
|
|
65
|
+
await resetAdminPasswordCommand().catch((err) => {
|
|
66
|
+
expect(err).toEqual(new Error('exit'));
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(consoleError).toBeCalledWith('Missing required options `email` or `password`');
|
|
70
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
71
|
+
expect(load).not.toHaveBeenCalled();
|
|
72
|
+
expect(resetPasswordByEmail).not.toHaveBeenCalled();
|
|
73
|
+
|
|
74
|
+
process.stdin.isTTY = tmpTTY;
|
|
75
|
+
mockExit.mockRestore();
|
|
76
|
+
consoleError.mockRestore();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('Stops if not confirmed', async () => {
|
|
80
|
+
process.stdin.isTTY = true;
|
|
81
|
+
const email = 'email@email.fr';
|
|
82
|
+
const password = 'testPasword1234';
|
|
83
|
+
|
|
84
|
+
const mockInquiry = jest
|
|
85
|
+
.spyOn(inquirer, 'prompt')
|
|
86
|
+
.mockImplementationOnce(async () => ({ email, password, confirm: false }));
|
|
87
|
+
|
|
88
|
+
// throw so the code will stop executing
|
|
89
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
|
90
|
+
throw new Error('exit');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
await resetAdminPasswordCommand().catch((err) => {
|
|
94
|
+
expect(err).toEqual(new Error('exit'));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(mockInquiry).toHaveBeenLastCalledWith([
|
|
98
|
+
expect.objectContaining({
|
|
99
|
+
message: expect.any(String),
|
|
100
|
+
name: 'email',
|
|
101
|
+
type: 'input',
|
|
102
|
+
}),
|
|
103
|
+
expect.objectContaining({
|
|
104
|
+
message: expect.any(String),
|
|
105
|
+
name: 'password',
|
|
106
|
+
type: 'password',
|
|
107
|
+
}),
|
|
108
|
+
expect.objectContaining({
|
|
109
|
+
message: expect.any(String),
|
|
110
|
+
name: 'confirm',
|
|
111
|
+
type: 'confirm',
|
|
112
|
+
}),
|
|
113
|
+
]);
|
|
114
|
+
expect(mockExit).toHaveBeenCalledWith(0);
|
|
115
|
+
expect(load).not.toHaveBeenCalled();
|
|
116
|
+
expect(resetPasswordByEmail).not.toHaveBeenCalled();
|
|
117
|
+
|
|
118
|
+
mockExit.mockRestore();
|
|
119
|
+
mockInquiry.mockRestore();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('Calls the reset method with user input', async () => {
|
|
123
|
+
const email = 'email@email.fr';
|
|
124
|
+
const password = 'testPasword1234';
|
|
125
|
+
|
|
126
|
+
const mockInquiry = jest
|
|
127
|
+
.spyOn(inquirer, 'prompt')
|
|
128
|
+
.mockImplementationOnce(async () => ({ email, password, confirm: true }));
|
|
129
|
+
|
|
130
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
|
|
131
|
+
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
132
|
+
|
|
133
|
+
await resetAdminPasswordCommand();
|
|
134
|
+
|
|
135
|
+
expect(mockExit).toHaveBeenCalledWith(0);
|
|
136
|
+
expect(consoleLog).toHaveBeenCalled();
|
|
137
|
+
expect(load).toHaveBeenCalled();
|
|
138
|
+
expect(resetPasswordByEmail).toHaveBeenCalledWith(email, password);
|
|
139
|
+
|
|
140
|
+
mockInquiry.mockRestore();
|
|
141
|
+
mockExit.mockRestore();
|
|
142
|
+
consoleLog.mockRestore();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const strapi = require('../../..');
|
|
4
|
+
const { buildAdmin } = require('../../builders');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `$ strapi build`
|
|
8
|
+
*/
|
|
9
|
+
module.exports = async ({ optimization, forceBuild = true }) => {
|
|
10
|
+
const { appDir, distDir } = await strapi.compile();
|
|
11
|
+
|
|
12
|
+
await buildAdmin({
|
|
13
|
+
forceBuild,
|
|
14
|
+
optimization,
|
|
15
|
+
buildDestDir: distDir,
|
|
16
|
+
srcDir: appDir,
|
|
17
|
+
});
|
|
18
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { getLocalScript } = require('../../utils/helpers');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `$ strapi build`
|
|
7
|
+
* @param {import('../../../types/core/commands').AddCommandOptions} options
|
|
8
|
+
*/
|
|
9
|
+
module.exports = ({ command }) => {
|
|
10
|
+
command
|
|
11
|
+
.command('build')
|
|
12
|
+
.option('--no-optimization', 'Build the admin app without optimizing assets')
|
|
13
|
+
.description('Build the strapi admin app')
|
|
14
|
+
.action(getLocalScript('build'));
|
|
15
|
+
};
|