@squiz/dxp-cli-next 5.27.0 → 5.28.0-develop.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.
@@ -1,4 +1,4 @@
1
- import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
1
+ import { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
2
2
  export declare const COOKIE_KEY = "dxp-sessionid";
3
3
  interface ApiServiceParameters {
4
4
  validateStatus?: (status: number) => boolean;
@@ -19,7 +19,7 @@ export declare class ApiService {
19
19
  * storage and set it on any request. This ensures that post-login, all requests
20
20
  * will seamlessly have the authorization required.
21
21
  */
22
- export declare function requestInterceptor(request: AxiosRequestConfig): Promise<AxiosRequestConfig<any>>;
22
+ export declare function requestInterceptor(request: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig<any>>;
23
23
  /**
24
24
  * The API Service responseInterceptor will handle the case that a
25
25
  * "Set-Cookie" header has been returned from an API request and will
package/lib/ApiService.js CHANGED
@@ -52,16 +52,16 @@ function requestInterceptor(request) {
52
52
  }
53
53
  else {
54
54
  const maybeSessionCookie = yield (0, ApplicationStore_1.getApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie);
55
- if (maybeSessionCookie) {
56
- additionalHeaders.cookie =
57
- (_a = tough_cookie_1.Cookie.fromJSON(maybeSessionCookie)) === null || _a === void 0 ? void 0 : _a.cookieString();
55
+ const maybeSessionCookieString = maybeSessionCookie && ((_a = tough_cookie_1.Cookie.fromJSON(maybeSessionCookie)) === null || _a === void 0 ? void 0 : _a.cookieString());
56
+ if (maybeSessionCookieString) {
57
+ additionalHeaders.cookie = maybeSessionCookieString;
58
58
  }
59
59
  }
60
60
  if (process.env.DXP_JWT) {
61
61
  additionalHeaders.authorization = `Bearer ${process.env.DXP_JWT}`;
62
62
  }
63
63
  if (Object.keys(additionalHeaders).length > 0) {
64
- request.headers = Object.assign(Object.assign({}, (request.headers || {})), additionalHeaders);
64
+ request.headers = request.headers.concat(additionalHeaders);
65
65
  }
66
66
  return request;
67
67
  });
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ const axios_1 = require("axios");
12
13
  const tough_cookie_1 = require("tough-cookie");
13
14
  const ApiService_1 = require("./ApiService");
14
15
  const ApplicationStore_1 = require("./ApplicationStore");
@@ -26,36 +27,43 @@ describe('ApiService', () => {
26
27
  }));
27
28
  it('loads stored session cookie into request config', () => __awaiter(void 0, void 0, void 0, function* () {
28
29
  yield (0, ApplicationStore_1.saveApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie, JSON.stringify(VALID_COOKIE.toJSON()));
29
- const requestConfig = yield (0, ApiService_1.requestInterceptor)({});
30
+ const requestConfig = yield (0, ApiService_1.requestInterceptor)({
31
+ headers: new axios_1.AxiosHeaders(),
32
+ });
30
33
  expect(requestConfig).toHaveProperty('headers');
31
34
  expect(requestConfig.headers).toHaveProperty('cookie');
32
35
  expect(tough_cookie_1.Cookie.parse(requestConfig.headers['cookie'])).toHaveProperty('value', 'valid-cookie-value');
33
36
  }));
34
37
  it('does not use session cookie if none stored', () => __awaiter(void 0, void 0, void 0, function* () {
35
- const requestConfig = yield (0, ApiService_1.requestInterceptor)({});
36
- expect(requestConfig).toEqual({});
38
+ const requestConfig = yield (0, ApiService_1.requestInterceptor)({
39
+ headers: new axios_1.AxiosHeaders(),
40
+ });
41
+ expect(requestConfig).toEqual({
42
+ headers: new axios_1.AxiosHeaders(),
43
+ });
37
44
  }));
38
45
  it('attaches DXP JWT as authorization header if environment variable defined', () => __awaiter(void 0, void 0, void 0, function* () {
39
46
  process.env.DXP_JWT = 'xxx.yyy.zzz';
40
47
  const requestConfig = yield (0, ApiService_1.requestInterceptor)({
41
- headers: {
48
+ headers: new axios_1.AxiosHeaders({
42
49
  'x-custom-header': 'header value',
43
- },
50
+ }),
44
51
  });
45
- expect(requestConfig).toEqual({
46
- headers: {
47
- authorization: 'Bearer xxx.yyy.zzz',
52
+ expect(requestConfig).toMatchObject({
53
+ headers: new axios_1.AxiosHeaders({
48
54
  'x-custom-header': 'header value',
49
- },
55
+ authorization: 'Bearer xxx.yyy.zzz',
56
+ }),
50
57
  });
51
58
  }));
52
59
  it('uses the SQUIZ_DXP_API_TOKEN variable instead of session if provided', () => __awaiter(void 0, void 0, void 0, function* () {
53
60
  process.env.SQUIZ_DXP_API_TOKEN = '123';
54
61
  yield (0, ApplicationStore_1.saveApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie, JSON.stringify(VALID_COOKIE.toJSON()));
55
- yield expect((0, ApiService_1.requestInterceptor)({})).resolves.toMatchObject({
56
- headers: {
62
+ const headers = new axios_1.AxiosHeaders();
63
+ yield expect((0, ApiService_1.requestInterceptor)({ headers })).resolves.toMatchObject({
64
+ headers: new axios_1.AxiosHeaders({
57
65
  'x-api-key': '123',
58
- },
66
+ }),
59
67
  });
60
68
  }));
61
69
  });
@@ -66,8 +74,8 @@ describe('ApiService', () => {
66
74
  it('saves the set-cookie for a session into the store', () => __awaiter(void 0, void 0, void 0, function* () {
67
75
  const setCookie = [VALID_COOKIE.toString()];
68
76
  const response = {
77
+ config: { headers: new axios_1.AxiosHeaders() },
69
78
  data: {},
70
- config: {},
71
79
  status: 204,
72
80
  statusText: '',
73
81
  headers: { 'set-cookie': setCookie },
@@ -84,7 +92,7 @@ describe('ApiService', () => {
84
92
  it('does not error if no set-cookie', () => __awaiter(void 0, void 0, void 0, function* () {
85
93
  const response = {
86
94
  data: {},
87
- config: {},
95
+ config: { headers: new axios_1.AxiosHeaders() },
88
96
  status: 204,
89
97
  statusText: '',
90
98
  headers: {},
@@ -97,7 +105,7 @@ describe('ApiService', () => {
97
105
  yield (0, ApplicationStore_1.saveApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie, JSON.stringify(VALID_COOKIE.toJSON()));
98
106
  const response = {
99
107
  data: {},
100
- config: {},
108
+ config: { headers: new axios_1.AxiosHeaders() },
101
109
  status: 204,
102
110
  statusText: '',
103
111
  headers: {},
@@ -110,7 +118,7 @@ describe('ApiService', () => {
110
118
  yield (0, ApplicationStore_1.saveApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie, JSON.stringify(VALID_COOKIE.toJSON()));
111
119
  const response = {
112
120
  data: { nested: 'rest' },
113
- config: {},
121
+ config: { headers: new axios_1.AxiosHeaders() },
114
122
  status: 204,
115
123
  statusText: '',
116
124
  headers: {
@@ -129,7 +137,7 @@ describe('ApiService', () => {
129
137
  it('errors with InvalidSession on failed session creation if no existing file', () => __awaiter(void 0, void 0, void 0, function* () {
130
138
  const response = {
131
139
  data: { message: ApiService_1.MESSAGE_FAILED_TO_CREATE_SESSION },
132
- config: {},
140
+ config: { headers: new axios_1.AxiosHeaders() },
133
141
  status: 401,
134
142
  statusText: '',
135
143
  headers: {},
@@ -139,7 +147,7 @@ describe('ApiService', () => {
139
147
  it('errors with InvalidSession on no session provided', () => __awaiter(void 0, void 0, void 0, function* () {
140
148
  const response = {
141
149
  data: { message: ApiService_1.MESSAGE_INVALID_REQUEST_NO_SESSIONID },
142
- config: {},
150
+ config: { headers: new axios_1.AxiosHeaders() },
143
151
  status: 401,
144
152
  statusText: '',
145
153
  headers: {},
@@ -150,7 +158,7 @@ describe('ApiService', () => {
150
158
  yield (0, ApplicationStore_1.saveApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie, JSON.stringify(VALID_COOKIE.toJSON()));
151
159
  const response = {
152
160
  data: { message: ApiService_1.MESSAGE_FAILED_TO_CREATE_SESSION },
153
- config: {},
161
+ config: { headers: new axios_1.AxiosHeaders() },
154
162
  status: 401,
155
163
  statusText: '',
156
164
  headers: {},
@@ -162,7 +170,7 @@ describe('ApiService', () => {
162
170
  yield (0, ApplicationStore_1.saveApplicationFile)(ApplicationStore_1.STORE_FILES.sessionCookie, JSON.stringify(VALID_COOKIE.toJSON()));
163
171
  const response = {
164
172
  data: { message: ApiService_1.MESSAGE_FAILED_TO_CREATE_ORG_SESSION },
165
- config: {},
173
+ config: { headers: new axios_1.AxiosHeaders() },
166
174
  status: 401,
167
175
  statusText: '',
168
176
  headers: {},
@@ -9,11 +9,13 @@ const get_1 = __importDefault(require("./get/get"));
9
9
  const next_1 = __importDefault(require("./next/next"));
10
10
  const settings_1 = __importDefault(require("./settings/settings"));
11
11
  const revert_1 = __importDefault(require("./revert/revert"));
12
+ const list_1 = __importDefault(require("./list/list"));
12
13
  const migrationCommand = new commander_1.Command('migration');
13
14
  migrationCommand
14
15
  .description('AI Page Migration Service Commands')
15
16
  .addCommand((0, create_1.default)())
16
17
  .addCommand((0, get_1.default)())
18
+ .addCommand((0, list_1.default)())
17
19
  .addCommand((0, next_1.default)())
18
20
  .addCommand((0, settings_1.default)())
19
21
  .addCommand((0, revert_1.default)());
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const listMigrationsCommand: () => Command;
3
+ export default listMigrationsCommand;
@@ -0,0 +1,45 @@
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 chalk_1 = __importDefault(require("chalk"));
16
+ const commander_1 = require("commander");
17
+ const utils_1 = require("../utils");
18
+ const ora_1 = __importDefault(require("ora"));
19
+ const listMigrations_1 = require("../utils/listMigrations");
20
+ const listMigrationsCommand = () => {
21
+ const listCommand = new commander_1.Command('list')
22
+ .alias('ls')
23
+ .description('Lists all active migrations for a tenant')
24
+ .addOption((0, utils_1.getParamOption)(utils_1.OptionName.TENANT, false))
25
+ .configureOutput({
26
+ outputError(str, write) {
27
+ write(chalk_1.default.red(str));
28
+ },
29
+ })
30
+ .action((options) => __awaiter(void 0, void 0, void 0, function* () {
31
+ const spinner = (0, ora_1.default)('Listing migrations').start();
32
+ yield (0, utils_1.throwErrorIfNotLoggedIn)(listCommand);
33
+ try {
34
+ const response = yield (0, listMigrations_1.listMigrations)(options);
35
+ spinner.succeed(`Migrations: ${JSON.stringify(response, null, 2)}`);
36
+ }
37
+ catch (error) {
38
+ spinner.fail();
39
+ (0, utils_1.handleCommandError)(listCommand, error);
40
+ }
41
+ }));
42
+ (0, utils_1.addOverrideUrlOption)(listCommand);
43
+ return listCommand;
44
+ };
45
+ exports.default = listMigrationsCommand;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ const mockListMigrations = jest.fn();
39
+ const nock_1 = __importDefault(require("nock"));
40
+ const list_1 = __importDefault(require("./list"));
41
+ const utils = __importStar(require("../utils/common"));
42
+ jest.mock('../utils/common');
43
+ jest.mock('../utils/listMigrations', () => ({
44
+ listMigrations: mockListMigrations,
45
+ }));
46
+ jest.mock('../../ApplicationStore');
47
+ const mockUtils = utils;
48
+ describe('listMigrationsCommand', () => {
49
+ const program = (0, list_1.default)();
50
+ const migrationsData = [
51
+ {
52
+ migrationId: 'migration-1',
53
+ assetId: 'asset-1',
54
+ stage: 'completed',
55
+ status: 'success',
56
+ created: 100,
57
+ updated: 200,
58
+ },
59
+ {
60
+ migrationId: 'migration-2',
61
+ assetId: 'asset-2',
62
+ stage: 'completed',
63
+ status: 'success',
64
+ created: 100,
65
+ updated: 200,
66
+ },
67
+ {
68
+ migrationId: 'migration-3',
69
+ assetId: 'asset-3',
70
+ stage: 'completed',
71
+ status: 'success',
72
+ created: 100,
73
+ updated: 200,
74
+ },
75
+ ];
76
+ const listArgs = ['node', 'dxp-cli', 'ls', '--tenant', 'test-tenant'];
77
+ beforeAll(() => {
78
+ mockListMigrations.mockResolvedValue(migrationsData);
79
+ mockUtils.throwErrorIfNotLoggedIn.mockReturnThis();
80
+ });
81
+ beforeEach(() => {
82
+ nock_1.default.cleanAll();
83
+ jest.clearAllMocks();
84
+ });
85
+ it('should have correct command name and alias', () => {
86
+ expect(program.name()).toBe('list');
87
+ expect(program.aliases()).toStrictEqual(expect.arrayContaining(['ls']));
88
+ });
89
+ it('should list migrations successfully with required options', () => __awaiter(void 0, void 0, void 0, function* () {
90
+ yield program.parseAsync(listArgs);
91
+ expect(mockUtils.throwErrorIfNotLoggedIn).toHaveBeenCalledWith(program);
92
+ expect(mockListMigrations).toHaveBeenCalled();
93
+ expect(mockListMigrations).toHaveBeenCalledTimes(1);
94
+ expect(mockUtils.handleCommandError).not.toHaveBeenCalled();
95
+ }));
96
+ it('should list migrations with tenant option', () => __awaiter(void 0, void 0, void 0, function* () {
97
+ yield program.parseAsync(listArgs);
98
+ expect(mockListMigrations).toHaveBeenCalledWith({
99
+ tenant: 'test-tenant',
100
+ });
101
+ }));
102
+ it('should list migrations with override URL when environment variable is set', () => __awaiter(void 0, void 0, void 0, function* () {
103
+ const originalEnv = process.env.ENABLE_OVERRIDE_MIGRATION_URL;
104
+ process.env.ENABLE_OVERRIDE_MIGRATION_URL = 'true';
105
+ // Recreate to pick up on env var change
106
+ const program = (0, list_1.default)();
107
+ yield program.parseAsync([
108
+ ...listArgs,
109
+ '--overrideUrl',
110
+ 'https://custom.migration.url',
111
+ ]);
112
+ expect(mockListMigrations).toHaveBeenCalledWith({
113
+ tenant: 'test-tenant',
114
+ overrideUrl: 'https://custom.migration.url',
115
+ });
116
+ process.env.ENABLE_OVERRIDE_MIGRATION_URL = originalEnv;
117
+ }));
118
+ it('should not require tenant option set', () => {
119
+ const program = (0, list_1.default)().exitOverride();
120
+ expect(() => {
121
+ program.parse(['node', 'dxp-cli', 'list']);
122
+ }).not.toThrow();
123
+ });
124
+ describe('error scenarios', () => {
125
+ it('should handle listMigrations API error', () => __awaiter(void 0, void 0, void 0, function* () {
126
+ const apiError = new Error('Migration not found');
127
+ mockListMigrations.mockRejectedValue(apiError);
128
+ yield program.parseAsync(listArgs);
129
+ expect(mockUtils.handleCommandError).toHaveBeenCalledWith(program, apiError);
130
+ }));
131
+ it('should handle network error', () => __awaiter(void 0, void 0, void 0, function* () {
132
+ const networkError = new Error('Network connection failed');
133
+ mockListMigrations.mockRejectedValue(networkError);
134
+ yield program.parseAsync(listArgs);
135
+ expect(mockUtils.handleCommandError).toHaveBeenCalledWith(program, networkError);
136
+ }));
137
+ });
138
+ });
@@ -0,0 +1,2 @@
1
+ import { AssetMigration } from '.';
2
+ export declare type ListMigrationsApiElement = Pick<AssetMigration, 'migrationId' | 'assetId' | 'stage' | 'status' | 'created' | 'updated'>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ import { CommonCommandOptions } from '../types';
2
+ import { ListMigrationsApiElement } from '../types/listMigrations.types';
3
+ export declare function listMigrations(options: CommonCommandOptions): Promise<ListMigrationsApiElement[]>;
@@ -0,0 +1,41 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.listMigrations = void 0;
13
+ const ApiService_1 = require("../../ApiService");
14
+ const _1 = require(".");
15
+ function listMigrations(options) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const apiService = new ApiService_1.ApiService({
18
+ validateStatus: _1.validateAxiosStatus,
19
+ });
20
+ const migrationUrl = yield (0, _1.buildMigrationUrl)(options.tenant, options.overrideUrl);
21
+ try {
22
+ const response = yield apiService.client.get(migrationUrl, {
23
+ headers: yield (0, _1.getMigrationHeaders)(options.tenant),
24
+ });
25
+ if (response.status !== 200) {
26
+ throw new Error(`Failed to list migrations: ${response.status}`);
27
+ }
28
+ else if (!(response === null || response === void 0 ? void 0 : response.data)) {
29
+ throw new Error('No data returned from migration service');
30
+ }
31
+ return response.data;
32
+ }
33
+ catch (error) {
34
+ if (error instanceof Error) {
35
+ throw error;
36
+ }
37
+ throw new Error(`Failed to list migrations: ${error}`);
38
+ }
39
+ });
40
+ }
41
+ exports.listMigrations = listMigrations;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,108 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const mockClient = { get: jest.fn() };
13
+ const ApplicationConfig_1 = require("../../ApplicationConfig");
14
+ const listMigrations_1 = require("./listMigrations");
15
+ jest.mock('path');
16
+ jest.mock('child_process');
17
+ jest.mock('axios');
18
+ jest.mock('../../ApplicationConfig');
19
+ jest.mock('../../ApiService', () => ({
20
+ ApiService: function () {
21
+ return {
22
+ client: mockClient,
23
+ };
24
+ },
25
+ }));
26
+ describe('listMigration', () => {
27
+ const options = {
28
+ tenant: 'test-tenant',
29
+ };
30
+ const migrationsData = [
31
+ {
32
+ migrationId: 'migration-1',
33
+ assetId: 'asset-1',
34
+ stage: 'completed',
35
+ status: 'success',
36
+ created: 100,
37
+ updated: 200,
38
+ },
39
+ {
40
+ migrationId: 'migration-2',
41
+ assetId: 'asset-2',
42
+ stage: 'completed',
43
+ status: 'success',
44
+ created: 100,
45
+ updated: 200,
46
+ },
47
+ {
48
+ migrationId: 'migration-3',
49
+ assetId: 'asset-3',
50
+ stage: 'completed',
51
+ status: 'success',
52
+ created: 100,
53
+ updated: 200,
54
+ },
55
+ ];
56
+ const mockFetchApplicationConfig = ApplicationConfig_1.fetchApplicationConfig;
57
+ beforeAll(() => {
58
+ mockClient.get.mockResolvedValue({
59
+ status: 200,
60
+ data: migrationsData,
61
+ });
62
+ mockFetchApplicationConfig.mockResolvedValue({
63
+ tenant: 'test-tenant',
64
+ baseUrl: 'https://example.com',
65
+ region: 'au',
66
+ });
67
+ });
68
+ it('lists migrations successfully', () => __awaiter(void 0, void 0, void 0, function* () {
69
+ yield expect((0, listMigrations_1.listMigrations)(options)).resolves.toStrictEqual(migrationsData);
70
+ expect(mockClient.get).toHaveBeenCalledWith('https://example.com/__dxp/service/aiapps/migration/migrations', {
71
+ headers: {
72
+ 'Content-Type': 'application/json',
73
+ 'x-dxp-tenant': 'test-tenant',
74
+ },
75
+ });
76
+ }));
77
+ it('lists migrations with override URL', () => __awaiter(void 0, void 0, void 0, function* () {
78
+ const optionsWithOverride = Object.assign(Object.assign({}, options), { overrideUrl: 'https://custom.migration.url' });
79
+ mockClient.get.mockResolvedValueOnce({
80
+ status: 200,
81
+ data: migrationsData,
82
+ });
83
+ yield expect((0, listMigrations_1.listMigrations)(optionsWithOverride)).resolves.toStrictEqual(migrationsData);
84
+ expect(mockClient.get).toHaveBeenCalledWith('https://custom.migration.url/migrations', expect.any(Object));
85
+ }));
86
+ it('handles non-success status codes', () => __awaiter(void 0, void 0, void 0, function* () {
87
+ mockClient.get.mockResolvedValue({
88
+ status: 400,
89
+ data: [],
90
+ });
91
+ yield expect((0, listMigrations_1.listMigrations)(options)).rejects.toThrow('Failed to list migrations: 400');
92
+ }));
93
+ it('handles missing response data', () => __awaiter(void 0, void 0, void 0, function* () {
94
+ mockClient.get.mockResolvedValue({
95
+ status: 200,
96
+ data: null,
97
+ });
98
+ yield expect((0, listMigrations_1.listMigrations)(options)).rejects.toThrow('No data returned from migration service');
99
+ }));
100
+ it('handles API service errors', () => __awaiter(void 0, void 0, void 0, function* () {
101
+ mockClient.get.mockRejectedValue(new Error('Network error'));
102
+ yield expect((0, listMigrations_1.listMigrations)(options)).rejects.toThrow('Network error');
103
+ }));
104
+ it('handles unknown errors', () => __awaiter(void 0, void 0, void 0, function* () {
105
+ mockClient.get.mockRejectedValue('Unknown error');
106
+ yield expect((0, listMigrations_1.listMigrations)(options)).rejects.toThrow('Failed to list migrations: Unknown error');
107
+ }));
108
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squiz/dxp-cli-next",
3
- "version": "5.27.0",
3
+ "version": "5.28.0-develop.1",
4
4
  "repository": {
5
5
  "url": "https://gitlab.squiz.net/dxp/dxp-cli-next"
6
6
  },
@@ -44,9 +44,9 @@
44
44
  "@squiz/component-cli-lib": "1.72.12",
45
45
  "@squiz/dx-logger-lib": "^1.65.1",
46
46
  "@squiz/dxp-porter-shared": "0.4.0",
47
- "@squiz/job-runner-lib": "2.1.0",
47
+ "@squiz/job-runner-lib": "2.3.0",
48
48
  "@squiz/local-component-dev-ui": "0.6.20",
49
- "axios": "1.1.3",
49
+ "axios": "1.11.0",
50
50
  "cli-color": "2.0.3",
51
51
  "commander": "9.4.0",
52
52
  "dotenv": "^16.3.1",