@squiz/dxp-cli-next 5.28.0 → 5.29.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/lib/migration/create/create.js +1 -3
- package/lib/migration/create/create.spec.js +0 -1
- package/lib/migration/next/next.js +15 -0
- package/lib/migration/next/next.spec.js +44 -0
- package/lib/migration/types/createMigration.types.d.ts +0 -1
- package/lib/migration/utils/common.d.ts +0 -1
- package/lib/migration/utils/common.js +1 -14
- package/lib/migration/utils/common.spec.js +0 -31
- package/lib/migration/utils/createMigration.js +1 -5
- package/lib/migration/utils/createMigration.spec.js +0 -17
- package/lib/migration/utils/index.d.ts +1 -0
- package/lib/migration/utils/index.js +1 -0
- package/lib/migration/utils/promptForMorphConfirmation.d.ts +5 -0
- package/lib/migration/utils/promptForMorphConfirmation.js +55 -0
- package/lib/migration/utils/promptForMorphConfirmation.spec.d.ts +1 -0
- package/lib/migration/utils/promptForMorphConfirmation.spec.js +101 -0
- package/package.json +1 -1
|
@@ -31,7 +31,7 @@ const createMigrationCommand = () => {
|
|
|
31
31
|
})
|
|
32
32
|
.action((options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
33
33
|
yield (0, utils_1.throwErrorIfNotLoggedIn)(createCommand);
|
|
34
|
-
|
|
34
|
+
const spinner = (0, ora_1.default)('Creating migration').start();
|
|
35
35
|
try {
|
|
36
36
|
// Create migration
|
|
37
37
|
const response = yield (0, utils_1.createMigration)(options);
|
|
@@ -39,8 +39,6 @@ const createMigrationCommand = () => {
|
|
|
39
39
|
throw new Error('Migration creation failed');
|
|
40
40
|
}
|
|
41
41
|
spinner.succeed('Migration created successfully');
|
|
42
|
-
// Upload file to S3
|
|
43
|
-
spinner = (0, ora_1.default)('Uploading file to S3').start();
|
|
44
42
|
spinner.succeed(`Successfully created migration: ${JSON.stringify({
|
|
45
43
|
migrationId: response.assetMigration.migrationId,
|
|
46
44
|
assetId: response.assetMigration.assetId,
|
|
@@ -65,7 +65,6 @@ describe('createMigrationCommand', () => {
|
|
|
65
65
|
updated: 1234567890,
|
|
66
66
|
migrationIdAssetId: 'migration-123-asset-456',
|
|
67
67
|
},
|
|
68
|
-
uploadUrl: 'https://upload.s3.amazonaws.com',
|
|
69
68
|
};
|
|
70
69
|
mockCreateMigration.createMigration.mockResolvedValue(mockCreateMigrationResponse);
|
|
71
70
|
});
|
|
@@ -45,6 +45,21 @@ const nextStageCommand = () => {
|
|
|
45
45
|
const spinner = (0, ora_1.default)('Starting next stage').start();
|
|
46
46
|
try {
|
|
47
47
|
const { stageOptions: stageOptionsPath } = options, otherOptions = __rest(options, ["stageOptions"]);
|
|
48
|
+
const migration = yield (0, utils_1.getMigration)(otherOptions);
|
|
49
|
+
if (!migration) {
|
|
50
|
+
throw new Error('Migration not found');
|
|
51
|
+
}
|
|
52
|
+
const { stage, status, assetId } = migration;
|
|
53
|
+
const needsConfirmation = (stage === 'preview' && status === 'complete') ||
|
|
54
|
+
(stage === 'morph' && status === 'awaiting-confirmation');
|
|
55
|
+
if (needsConfirmation) {
|
|
56
|
+
spinner.stop();
|
|
57
|
+
const shouldProceed = yield (0, utils_1.promptForMorphConfirmation)(stage, status, assetId);
|
|
58
|
+
if (!shouldProceed) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
spinner.start('Starting next stage');
|
|
62
|
+
}
|
|
48
63
|
const stageOptions = (0, utils_1.loadStageOptionsFromFile)(stageOptionsPath);
|
|
49
64
|
const response = yield (0, utils_1.nextStage)(Object.assign(Object.assign({}, otherOptions), (stageOptions && { stageOptions })));
|
|
50
65
|
spinner.succeed(response.message);
|
|
@@ -40,11 +40,14 @@ const next_1 = __importDefault(require("./next"));
|
|
|
40
40
|
const utils = __importStar(require("../utils/common"));
|
|
41
41
|
const ApplicationStore = __importStar(require("../../ApplicationStore"));
|
|
42
42
|
const nextStageModule = __importStar(require("../utils/nextStage"));
|
|
43
|
+
const getMigrationModule = __importStar(require("../utils/getMigration"));
|
|
43
44
|
jest.mock('../utils/common');
|
|
44
45
|
jest.mock('../utils/nextStage');
|
|
46
|
+
jest.mock('../utils/getMigration');
|
|
45
47
|
jest.mock('../../ApplicationStore');
|
|
46
48
|
const mockUtils = utils;
|
|
47
49
|
const mockNextStage = nextStageModule;
|
|
50
|
+
const mockGetMigration = getMigrationModule;
|
|
48
51
|
const mockApplicationStore = ApplicationStore;
|
|
49
52
|
describe('nextStageCommand', () => {
|
|
50
53
|
let logSpy;
|
|
@@ -60,6 +63,18 @@ describe('nextStageCommand', () => {
|
|
|
60
63
|
message: 'Successfully started next stage',
|
|
61
64
|
};
|
|
62
65
|
mockNextStage.nextStage.mockResolvedValue(mockNextStageResponse);
|
|
66
|
+
mockGetMigration.getMigration.mockResolvedValue({
|
|
67
|
+
migrationId: 'migration-123',
|
|
68
|
+
assetId: 'asset-456',
|
|
69
|
+
stage: 'validation',
|
|
70
|
+
status: 'completed',
|
|
71
|
+
xmlFilePath: 'test.xml',
|
|
72
|
+
matrixUrl: 'http://test.com',
|
|
73
|
+
previewAssetId: 'preview-123',
|
|
74
|
+
created: 1234567890,
|
|
75
|
+
updated: 1234567890,
|
|
76
|
+
migrationIdAssetId: 'migration-123-asset-456',
|
|
77
|
+
});
|
|
63
78
|
});
|
|
64
79
|
afterEach(() => {
|
|
65
80
|
logSpy.mockRestore();
|
|
@@ -77,6 +92,10 @@ describe('nextStageCommand', () => {
|
|
|
77
92
|
'asset-456',
|
|
78
93
|
]);
|
|
79
94
|
expect(mockUtils.throwErrorIfNotLoggedIn).toHaveBeenCalledWith(program);
|
|
95
|
+
expect(mockGetMigration.getMigration).toHaveBeenCalledWith({
|
|
96
|
+
migrationId: 'migration-123',
|
|
97
|
+
assetId: 'asset-456',
|
|
98
|
+
});
|
|
80
99
|
expect(mockNextStage.nextStage).toHaveBeenCalledWith({
|
|
81
100
|
migrationId: 'migration-123',
|
|
82
101
|
assetId: 'asset-456',
|
|
@@ -97,6 +116,11 @@ describe('nextStageCommand', () => {
|
|
|
97
116
|
'--tenant',
|
|
98
117
|
'test-tenant',
|
|
99
118
|
]);
|
|
119
|
+
expect(mockGetMigration.getMigration).toHaveBeenCalledWith({
|
|
120
|
+
migrationId: 'migration-123',
|
|
121
|
+
assetId: 'asset-456',
|
|
122
|
+
tenant: 'test-tenant',
|
|
123
|
+
});
|
|
100
124
|
expect(mockNextStage.nextStage).toHaveBeenCalledWith({
|
|
101
125
|
migrationId: 'migration-123',
|
|
102
126
|
assetId: 'asset-456',
|
|
@@ -116,6 +140,10 @@ describe('nextStageCommand', () => {
|
|
|
116
140
|
'--stage-options',
|
|
117
141
|
'./src/__tests__/migration/stageOptionsInput.json',
|
|
118
142
|
]);
|
|
143
|
+
expect(mockGetMigration.getMigration).toHaveBeenCalledWith({
|
|
144
|
+
migrationId: 'migration-123',
|
|
145
|
+
assetId: 'asset-456',
|
|
146
|
+
});
|
|
119
147
|
expect(mockNextStage.nextStage).toHaveBeenCalledWith({
|
|
120
148
|
migrationId: 'migration-123',
|
|
121
149
|
assetId: 'asset-456',
|
|
@@ -128,6 +156,22 @@ describe('nextStageCommand', () => {
|
|
|
128
156
|
}));
|
|
129
157
|
});
|
|
130
158
|
describe('error scenarios', () => {
|
|
159
|
+
it('should handle getMigration error', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
160
|
+
const migrationError = new Error('Failed to get migration: TypeError: Invalid URL');
|
|
161
|
+
mockGetMigration.getMigration.mockRejectedValue(migrationError);
|
|
162
|
+
mockUtils.handleCommandError.mockImplementation(() => { });
|
|
163
|
+
const program = (0, next_1.default)();
|
|
164
|
+
yield program.parseAsync([
|
|
165
|
+
'node',
|
|
166
|
+
'dxp-cli',
|
|
167
|
+
'next',
|
|
168
|
+
'--migration-id',
|
|
169
|
+
'migration-123',
|
|
170
|
+
'--asset-id',
|
|
171
|
+
'asset-456',
|
|
172
|
+
]);
|
|
173
|
+
expect(mockUtils.handleCommandError).toHaveBeenCalledWith(program, migrationError);
|
|
174
|
+
}));
|
|
131
175
|
it('should handle nextStage API error', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
132
176
|
const apiError = new Error('Failed to start next stage');
|
|
133
177
|
mockNextStage.nextStage.mockRejectedValue(apiError);
|
|
@@ -28,5 +28,4 @@ export declare function buildMigrationUrl(tenantID?: string, overrideUrl?: strin
|
|
|
28
28
|
*/
|
|
29
29
|
export declare function validateAxiosStatus(status: number): boolean;
|
|
30
30
|
export declare function getMigrationHeaders(tenantID?: string, isJson?: boolean): Promise<Record<string, string>>;
|
|
31
|
-
export declare function uploadFileToS3(uploadUrl: string, filePath: string, tenantID?: string): Promise<string>;
|
|
32
31
|
export declare function redactKey(key: string, visibleChars?: number): string;
|
|
@@ -12,8 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.redactKey = exports.
|
|
16
|
-
const fs_1 = __importDefault(require("fs"));
|
|
15
|
+
exports.redactKey = exports.getMigrationHeaders = exports.validateAxiosStatus = exports.buildMigrationUrl = exports.throwErrorIfNotLoggedIn = exports.handleCommandError = void 0;
|
|
17
16
|
const chalk_1 = __importDefault(require("chalk"));
|
|
18
17
|
const ApplicationConfig_1 = require("../../ApplicationConfig");
|
|
19
18
|
const axios_1 = __importDefault(require("axios"));
|
|
@@ -105,18 +104,6 @@ function getMigrationHeaders(tenantID, isJson = true) {
|
|
|
105
104
|
});
|
|
106
105
|
}
|
|
107
106
|
exports.getMigrationHeaders = getMigrationHeaders;
|
|
108
|
-
function uploadFileToS3(uploadUrl, filePath, tenantID) {
|
|
109
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
110
|
-
const fileBuffer = fs_1.default.readFileSync(filePath);
|
|
111
|
-
const response = yield fetch(uploadUrl, {
|
|
112
|
-
method: 'PUT',
|
|
113
|
-
body: fileBuffer,
|
|
114
|
-
headers: yield getMigrationHeaders(tenantID, false),
|
|
115
|
-
});
|
|
116
|
-
return response.url;
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
exports.uploadFileToS3 = uploadFileToS3;
|
|
120
107
|
function redactKey(key, visibleChars = 3) {
|
|
121
108
|
if (!key)
|
|
122
109
|
return '';
|
|
@@ -155,37 +155,6 @@ describe('Migration Utils', () => {
|
|
|
155
155
|
expect(mockFetchApplicationConfig).toHaveBeenCalledWith('tenant-id');
|
|
156
156
|
}));
|
|
157
157
|
});
|
|
158
|
-
describe('uploadFileToS3', () => {
|
|
159
|
-
beforeEach(() => {
|
|
160
|
-
mockFs.readFileSync.mockReturnValue(Buffer.from('file content'));
|
|
161
|
-
mockFetchApplicationConfig.mockResolvedValue({
|
|
162
|
-
tenant: 'test-tenant',
|
|
163
|
-
baseUrl: 'https://example.com',
|
|
164
|
-
region: 'au',
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
it('uploads file successfully', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
168
|
-
const mockResponse = {
|
|
169
|
-
url: 'https://s3.amazonaws.com/uploaded-file',
|
|
170
|
-
};
|
|
171
|
-
mockFetch.mockResolvedValue(mockResponse);
|
|
172
|
-
const result = yield (0, _1.uploadFileToS3)('https://upload.url', '/path/to/file.tar.gz', 'tenant-id');
|
|
173
|
-
expect(result).toBe('https://s3.amazonaws.com/uploaded-file');
|
|
174
|
-
expect(mockFetch).toHaveBeenCalledWith('https://upload.url', {
|
|
175
|
-
method: 'PUT',
|
|
176
|
-
body: Buffer.from('file content'),
|
|
177
|
-
headers: {
|
|
178
|
-
'x-dxp-tenant': 'test-tenant',
|
|
179
|
-
},
|
|
180
|
-
});
|
|
181
|
-
}));
|
|
182
|
-
it('handles file read error', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
183
|
-
mockFs.readFileSync.mockImplementation(() => {
|
|
184
|
-
throw new Error('File not found');
|
|
185
|
-
});
|
|
186
|
-
yield expect((0, _1.uploadFileToS3)('https://upload.url', '/nonexistent/file.tar.gz')).rejects.toThrow('File not found');
|
|
187
|
-
}));
|
|
188
|
-
});
|
|
189
158
|
describe('redactKey', () => {
|
|
190
159
|
it('redacts key correctly', () => {
|
|
191
160
|
expect((0, _1.redactKey)('1234567890', 3)).toBe('*******890');
|
|
@@ -37,19 +37,15 @@ function createMigration(options) {
|
|
|
37
37
|
throw new Error(`Migration creation failed with status: ${response.status}`);
|
|
38
38
|
}
|
|
39
39
|
// Validate response structure
|
|
40
|
-
const { assetMigration
|
|
40
|
+
const { assetMigration } = response.data || {};
|
|
41
41
|
if (!(assetMigration === null || assetMigration === void 0 ? void 0 : assetMigration.migrationId) ||
|
|
42
42
|
!(assetMigration === null || assetMigration === void 0 ? void 0 : assetMigration.assetId) ||
|
|
43
43
|
!(assetMigration === null || assetMigration === void 0 ? void 0 : assetMigration.stage) ||
|
|
44
44
|
!(assetMigration === null || assetMigration === void 0 ? void 0 : assetMigration.status)) {
|
|
45
45
|
throw new Error('Invalid response format from migration service');
|
|
46
46
|
}
|
|
47
|
-
if (!uploadUrl) {
|
|
48
|
-
throw new Error('Upload URL not found in response');
|
|
49
|
-
}
|
|
50
47
|
return {
|
|
51
48
|
assetMigration,
|
|
52
|
-
uploadUrl,
|
|
53
49
|
};
|
|
54
50
|
}
|
|
55
51
|
catch (error) {
|
|
@@ -161,7 +161,6 @@ describe('createMigration', () => {
|
|
|
161
161
|
updated: 1234567890,
|
|
162
162
|
migrationIdAssetId: 'migration-123-asset-123',
|
|
163
163
|
},
|
|
164
|
-
uploadUrl: 'https://upload.s3.amazonaws.com',
|
|
165
164
|
},
|
|
166
165
|
};
|
|
167
166
|
mockApiServiceInstance.client.post.mockResolvedValue(mockResponse);
|
|
@@ -195,27 +194,11 @@ describe('createMigration', () => {
|
|
|
195
194
|
stage: 'pending',
|
|
196
195
|
status: 'created',
|
|
197
196
|
},
|
|
198
|
-
uploadUrl: 'https://upload.s3.amazonaws.com',
|
|
199
197
|
},
|
|
200
198
|
};
|
|
201
199
|
mockApiServiceInstance.client.post.mockResolvedValue(mockResponse);
|
|
202
200
|
yield expect((0, _1.createMigration)(mockOptions)).rejects.toThrow('Invalid response format from migration service');
|
|
203
201
|
}));
|
|
204
|
-
it('handles missing upload URL', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
205
|
-
const mockResponse = {
|
|
206
|
-
status: 200,
|
|
207
|
-
data: {
|
|
208
|
-
assetMigration: {
|
|
209
|
-
migrationId: 'migration-123',
|
|
210
|
-
assetId: 'asset-123',
|
|
211
|
-
stage: 'pending',
|
|
212
|
-
status: 'created',
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
};
|
|
216
|
-
mockApiServiceInstance.client.post.mockResolvedValue(mockResponse);
|
|
217
|
-
yield expect((0, _1.createMigration)(mockOptions)).rejects.toThrow('Upload URL not found in response');
|
|
218
|
-
}));
|
|
219
202
|
it('handles API service errors', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
220
203
|
const error = new Error('Network error');
|
|
221
204
|
mockApiServiceInstance.client.post.mockRejectedValue(error);
|
|
@@ -22,3 +22,4 @@ __exportStar(require("./nextStage"), exports);
|
|
|
22
22
|
__exportStar(require("./setMigrationSettings"), exports);
|
|
23
23
|
__exportStar(require("./revertMigration"), exports);
|
|
24
24
|
__exportStar(require("./loadStageOptionsFromFile"), exports);
|
|
25
|
+
__exportStar(require("./promptForMorphConfirmation"), exports);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.promptForMorphConfirmation = void 0;
|
|
16
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
17
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
18
|
+
/**
|
|
19
|
+
* Prompts the user for confirmation when about to trigger morph stages.
|
|
20
|
+
* Returns true if user has chosen to confirm.
|
|
21
|
+
*/
|
|
22
|
+
function promptForMorphConfirmation(stage, status, assetId) {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
let message;
|
|
25
|
+
let abortMessage;
|
|
26
|
+
if (stage === 'preview' && status === 'complete') {
|
|
27
|
+
message = `You are about to morph the live asset (${assetId}). Do you wish to continue? [y/N]`;
|
|
28
|
+
abortMessage = 'Morph stage not run';
|
|
29
|
+
}
|
|
30
|
+
else if (stage === 'morph' && status === 'awaiting-confirmation') {
|
|
31
|
+
message = `You are about to permanently delete the standard page bodycopies for asset ${assetId}, please ensure that the client has confirmed the live asset is functioning as expected. This can NOT be undone. Do you wish to continue? [y/N]`;
|
|
32
|
+
abortMessage = 'Morph cleanup not run';
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
const choice = yield inquirer_1.default.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: 'list',
|
|
40
|
+
name: 'confirm',
|
|
41
|
+
message,
|
|
42
|
+
choices: [
|
|
43
|
+
{ name: 'No', value: false },
|
|
44
|
+
{ name: 'Yes', value: true },
|
|
45
|
+
],
|
|
46
|
+
default: false, // Default answer is No
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
if (!choice.confirm) {
|
|
50
|
+
console.log(chalk_1.default.yellow(abortMessage));
|
|
51
|
+
}
|
|
52
|
+
return choice.confirm;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
exports.promptForMorphConfirmation = promptForMorphConfirmation;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const promptForMorphConfirmation_1 = require("./promptForMorphConfirmation");
|
|
16
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
17
|
+
jest.mock('inquirer', () => ({
|
|
18
|
+
prompt: jest.fn(),
|
|
19
|
+
}));
|
|
20
|
+
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation();
|
|
21
|
+
const mockPrompt = require('inquirer').prompt;
|
|
22
|
+
describe('promptForMorphConfirmation', () => {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
jest.clearAllMocks();
|
|
25
|
+
});
|
|
26
|
+
afterAll(() => {
|
|
27
|
+
mockConsoleLog.mockRestore();
|
|
28
|
+
});
|
|
29
|
+
describe('Preview to Morph stage', () => {
|
|
30
|
+
it('should prompt for confirmation when stage is preview and status is complete', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
|
+
mockPrompt.mockResolvedValue({ confirm: true });
|
|
32
|
+
const result = yield (0, promptForMorphConfirmation_1.promptForMorphConfirmation)('preview', 'complete', 'asset123');
|
|
33
|
+
expect(mockPrompt).toHaveBeenCalledWith([
|
|
34
|
+
{
|
|
35
|
+
type: 'list',
|
|
36
|
+
name: 'confirm',
|
|
37
|
+
message: 'You are about to morph the live asset (asset123). Do you wish to continue? [y/N]',
|
|
38
|
+
choices: [
|
|
39
|
+
{ name: 'No', value: false },
|
|
40
|
+
{ name: 'Yes', value: true },
|
|
41
|
+
],
|
|
42
|
+
default: false,
|
|
43
|
+
},
|
|
44
|
+
]);
|
|
45
|
+
expect(result).toBe(true);
|
|
46
|
+
expect(mockConsoleLog).not.toHaveBeenCalled();
|
|
47
|
+
}));
|
|
48
|
+
it('should return false and show abort message when user selects No for preview stage', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
49
|
+
mockPrompt.mockResolvedValue({ confirm: false });
|
|
50
|
+
const result = yield (0, promptForMorphConfirmation_1.promptForMorphConfirmation)('preview', 'complete', 'asset456');
|
|
51
|
+
expect(result).toBe(false);
|
|
52
|
+
expect(mockConsoleLog).toHaveBeenCalledWith(chalk_1.default.yellow('Morph stage not run'));
|
|
53
|
+
}));
|
|
54
|
+
});
|
|
55
|
+
describe('Morph Cleanup stage', () => {
|
|
56
|
+
it('should prompt for confirmation when stage is morph and status is awaiting-confirmation', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
57
|
+
mockPrompt.mockResolvedValue({ confirm: true });
|
|
58
|
+
const result = yield (0, promptForMorphConfirmation_1.promptForMorphConfirmation)('morph', 'awaiting-confirmation', 'asset789');
|
|
59
|
+
expect(mockPrompt).toHaveBeenCalledWith([
|
|
60
|
+
{
|
|
61
|
+
type: 'list',
|
|
62
|
+
name: 'confirm',
|
|
63
|
+
message: 'You are about to permanently delete the standard page bodycopies for asset asset789, please ensure that the client has confirmed the live asset is functioning as expected. This can NOT be undone. Do you wish to continue? [y/N]',
|
|
64
|
+
choices: [
|
|
65
|
+
{ name: 'No', value: false },
|
|
66
|
+
{ name: 'Yes', value: true },
|
|
67
|
+
],
|
|
68
|
+
default: false,
|
|
69
|
+
},
|
|
70
|
+
]);
|
|
71
|
+
expect(result).toBe(true);
|
|
72
|
+
expect(mockConsoleLog).not.toHaveBeenCalled();
|
|
73
|
+
}));
|
|
74
|
+
it('should return false and show abort message when user selects No for morph cleanup stage', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
75
|
+
mockPrompt.mockResolvedValue({ confirm: false });
|
|
76
|
+
const result = yield (0, promptForMorphConfirmation_1.promptForMorphConfirmation)('morph', 'awaiting-confirmation', 'asset999');
|
|
77
|
+
expect(result).toBe(false);
|
|
78
|
+
expect(mockConsoleLog).toHaveBeenCalledWith(chalk_1.default.yellow('Morph cleanup not run'));
|
|
79
|
+
}));
|
|
80
|
+
});
|
|
81
|
+
describe('Other stages', () => {
|
|
82
|
+
it('should return true without prompting for preview stage with non-complete status', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
const result = yield (0, promptForMorphConfirmation_1.promptForMorphConfirmation)('preview', 'running', 'asset123');
|
|
84
|
+
expect(result).toBe(true);
|
|
85
|
+
expect(mockPrompt).not.toHaveBeenCalled();
|
|
86
|
+
expect(mockConsoleLog).not.toHaveBeenCalled();
|
|
87
|
+
}));
|
|
88
|
+
it('should return true without prompting for other stages', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
89
|
+
const result = yield (0, promptForMorphConfirmation_1.promptForMorphConfirmation)('export-to-json', 'complete', 'asset123');
|
|
90
|
+
expect(result).toBe(true);
|
|
91
|
+
expect(mockPrompt).not.toHaveBeenCalled();
|
|
92
|
+
expect(mockConsoleLog).not.toHaveBeenCalled();
|
|
93
|
+
}));
|
|
94
|
+
it('should return true without prompting for unknown stage and status combinations', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
95
|
+
const result = yield (0, promptForMorphConfirmation_1.promptForMorphConfirmation)('unknown', 'unknown-status', 'asset123');
|
|
96
|
+
expect(result).toBe(true);
|
|
97
|
+
expect(mockPrompt).not.toHaveBeenCalled();
|
|
98
|
+
expect(mockConsoleLog).not.toHaveBeenCalled();
|
|
99
|
+
}));
|
|
100
|
+
});
|
|
101
|
+
});
|