@jgardner04/ghost-mcp-server 1.14.2 → 1.14.3
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/package.json +1 -1
- package/src/__tests__/helpers/testUtils.js +22 -0
- package/src/services/__tests__/ghostServiceImproved.members.test.js +8 -10
- package/src/services/__tests__/ghostServiceImproved.pages.test.js +13 -13
- package/src/services/__tests__/ghostServiceImproved.posts.test.js +6 -4
- package/src/services/__tests__/ghostServiceImproved.tags.test.js +8 -10
package/package.json
CHANGED
|
@@ -117,3 +117,25 @@ export async function waitFor(condition, timeout = 5000, interval = 100) {
|
|
|
117
117
|
export function delay(ms) {
|
|
118
118
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
119
119
|
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Asserts that a promise rejects with a specific error type and message.
|
|
123
|
+
* Combines the common double `.rejects` pattern into a single call.
|
|
124
|
+
*
|
|
125
|
+
* @param {Promise} promise - The promise expected to reject
|
|
126
|
+
* @param {Function} ErrorClass - The expected error constructor (e.g., NotFoundError)
|
|
127
|
+
* @param {string|RegExp} message - The expected error message (string or regex)
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* import { expectRejection } from '../helpers/testUtils.js';
|
|
131
|
+
*
|
|
132
|
+
* await expectRejection(
|
|
133
|
+
* updateMember('non-existent', { name: 'Test' }),
|
|
134
|
+
* NotFoundError,
|
|
135
|
+
* 'Member not found'
|
|
136
|
+
* );
|
|
137
|
+
*/
|
|
138
|
+
export async function expectRejection(promise, ErrorClass, message) {
|
|
139
|
+
await expect(promise).rejects.toBeInstanceOf(ErrorClass);
|
|
140
|
+
await expect(promise).rejects.toThrow(message);
|
|
141
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { createMockContextLogger } from '../../__tests__/helpers/mockLogger.js';
|
|
3
|
-
import { mockDotenv } from '../../__tests__/helpers/testUtils.js';
|
|
3
|
+
import { mockDotenv, expectRejection } from '../../__tests__/helpers/testUtils.js';
|
|
4
4
|
import { mockGhostApiModule } from '../../__tests__/helpers/mockGhostApi.js';
|
|
5
5
|
|
|
6
6
|
// Mock the Ghost Admin API using shared mock factory
|
|
@@ -187,9 +187,11 @@ describe('ghostServiceImproved - Members', () => {
|
|
|
187
187
|
const error404 = new GhostAPIError('members.read', 'Member not found', 404);
|
|
188
188
|
api.members.read.mockRejectedValue(error404);
|
|
189
189
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
await expectRejection(
|
|
191
|
+
updateMember('non-existent', { name: 'Test' }),
|
|
192
|
+
NotFoundError,
|
|
193
|
+
'Member not found'
|
|
194
|
+
);
|
|
193
195
|
});
|
|
194
196
|
});
|
|
195
197
|
|
|
@@ -213,9 +215,7 @@ describe('ghostServiceImproved - Members', () => {
|
|
|
213
215
|
const error404 = new GhostAPIError('members.delete', 'Member not found', 404);
|
|
214
216
|
api.members.delete.mockRejectedValue(error404);
|
|
215
217
|
|
|
216
|
-
|
|
217
|
-
await expect(rejection).rejects.toBeInstanceOf(NotFoundError);
|
|
218
|
-
await expect(rejection).rejects.toThrow('Member not found');
|
|
218
|
+
await expectRejection(deleteMember('non-existent'), NotFoundError, 'Member not found');
|
|
219
219
|
});
|
|
220
220
|
});
|
|
221
221
|
|
|
@@ -360,9 +360,7 @@ describe('ghostServiceImproved - Members', () => {
|
|
|
360
360
|
const error404 = new GhostAPIError('members.read', 'Member not found', 404);
|
|
361
361
|
api.members.read.mockRejectedValue(error404);
|
|
362
362
|
|
|
363
|
-
|
|
364
|
-
await expect(rejection).rejects.toBeInstanceOf(NotFoundError);
|
|
365
|
-
await expect(rejection).rejects.toThrow('Member not found');
|
|
363
|
+
await expectRejection(getMember({ id: 'non-existent' }), NotFoundError, 'Member not found');
|
|
366
364
|
});
|
|
367
365
|
|
|
368
366
|
it('should throw not found error when member not found by email', async () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { createMockContextLogger } from '../../__tests__/helpers/mockLogger.js';
|
|
3
|
-
import { mockDotenv } from '../../__tests__/helpers/testUtils.js';
|
|
3
|
+
import { mockDotenv, expectRejection } from '../../__tests__/helpers/testUtils.js';
|
|
4
4
|
import { mockGhostApiModule } from '../../__tests__/helpers/mockGhostApi.js';
|
|
5
5
|
|
|
6
6
|
// Mock the Ghost Admin API using shared mock factory
|
|
@@ -210,9 +210,11 @@ describe('ghostServiceImproved - Pages', () => {
|
|
|
210
210
|
error422.response = { status: 422 };
|
|
211
211
|
api.pages.add.mockRejectedValue(error422);
|
|
212
212
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
await expectRejection(
|
|
214
|
+
createPage({ title: 'Test', html: '<p>Content</p>' }),
|
|
215
|
+
ValidationError,
|
|
216
|
+
'Page creation failed due to validation errors'
|
|
217
|
+
);
|
|
216
218
|
});
|
|
217
219
|
|
|
218
220
|
it('should NOT include tags in page creation (pages do not support tags)', async () => {
|
|
@@ -276,9 +278,11 @@ describe('ghostServiceImproved - Pages', () => {
|
|
|
276
278
|
const error404 = new GhostAPIError('pages.read', 'Page not found', 404);
|
|
277
279
|
api.pages.read.mockRejectedValue(error404);
|
|
278
280
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
281
|
+
await expectRejection(
|
|
282
|
+
updatePage('nonexistent-id', { title: 'Updated' }),
|
|
283
|
+
NotFoundError,
|
|
284
|
+
'Page not found'
|
|
285
|
+
);
|
|
282
286
|
});
|
|
283
287
|
|
|
284
288
|
it('should preserve updated_at timestamp for conflict resolution', async () => {
|
|
@@ -388,9 +392,7 @@ describe('ghostServiceImproved - Pages', () => {
|
|
|
388
392
|
const error404 = new GhostAPIError('pages.delete', 'Page not found', 404);
|
|
389
393
|
api.pages.delete.mockRejectedValue(error404);
|
|
390
394
|
|
|
391
|
-
|
|
392
|
-
await expect(rejection).rejects.toBeInstanceOf(NotFoundError);
|
|
393
|
-
await expect(rejection).rejects.toThrow('Page not found');
|
|
395
|
+
await expectRejection(deletePage('nonexistent-id'), NotFoundError, 'Page not found');
|
|
394
396
|
});
|
|
395
397
|
});
|
|
396
398
|
|
|
@@ -437,9 +439,7 @@ describe('ghostServiceImproved - Pages', () => {
|
|
|
437
439
|
const error404 = new GhostAPIError('pages.read', 'Page not found', 404);
|
|
438
440
|
api.pages.read.mockRejectedValue(error404);
|
|
439
441
|
|
|
440
|
-
|
|
441
|
-
await expect(rejection).rejects.toBeInstanceOf(NotFoundError);
|
|
442
|
-
await expect(rejection).rejects.toThrow('Page not found');
|
|
442
|
+
await expectRejection(getPage('nonexistent-id'), NotFoundError, 'Page not found');
|
|
443
443
|
});
|
|
444
444
|
});
|
|
445
445
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { createMockContextLogger } from '../../__tests__/helpers/mockLogger.js';
|
|
3
|
-
import { mockDotenv } from '../../__tests__/helpers/testUtils.js';
|
|
3
|
+
import { mockDotenv, expectRejection } from '../../__tests__/helpers/testUtils.js';
|
|
4
4
|
import { mockGhostApiModule } from '../../__tests__/helpers/mockGhostApi.js';
|
|
5
5
|
|
|
6
6
|
// Mock the Ghost Admin API using shared mock factory
|
|
@@ -95,9 +95,11 @@ describe('ghostServiceImproved - Posts (updatePost)', () => {
|
|
|
95
95
|
const error404 = new GhostAPIError('posts.read', 'Post not found', 404);
|
|
96
96
|
api.posts.read.mockRejectedValue(error404);
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
await expectRejection(
|
|
99
|
+
updatePost('nonexistent-id', { title: 'Updated' }),
|
|
100
|
+
NotFoundError,
|
|
101
|
+
'Post not found'
|
|
102
|
+
);
|
|
101
103
|
});
|
|
102
104
|
|
|
103
105
|
it('should throw ValidationError when updating to scheduled without published_at', async () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { createMockContextLogger } from '../../__tests__/helpers/mockLogger.js';
|
|
3
|
-
import { mockDotenv } from '../../__tests__/helpers/testUtils.js';
|
|
3
|
+
import { mockDotenv, expectRejection } from '../../__tests__/helpers/testUtils.js';
|
|
4
4
|
import { mockGhostApiModule } from '../../__tests__/helpers/mockGhostApi.js';
|
|
5
5
|
|
|
6
6
|
// Mock the Ghost Admin API using shared mock factory
|
|
@@ -254,9 +254,7 @@ describe('ghostServiceImproved - Tags', () => {
|
|
|
254
254
|
const error404 = new GhostAPIError('tags.read', 'Tag not found', 404);
|
|
255
255
|
api.tags.read.mockRejectedValue(error404);
|
|
256
256
|
|
|
257
|
-
|
|
258
|
-
await expect(rejection).rejects.toBeInstanceOf(NotFoundError);
|
|
259
|
-
await expect(rejection).rejects.toThrow('Tag not found');
|
|
257
|
+
await expectRejection(getTag('non-existent'), NotFoundError, 'Tag not found');
|
|
260
258
|
});
|
|
261
259
|
});
|
|
262
260
|
|
|
@@ -412,9 +410,11 @@ describe('ghostServiceImproved - Tags', () => {
|
|
|
412
410
|
const error404 = new GhostAPIError('tags.read', 'Tag not found', 404);
|
|
413
411
|
api.tags.read.mockRejectedValue(error404);
|
|
414
412
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
413
|
+
await expectRejection(
|
|
414
|
+
updateTag('non-existent', { name: 'Test' }),
|
|
415
|
+
NotFoundError,
|
|
416
|
+
'Tag not found'
|
|
417
|
+
);
|
|
418
418
|
});
|
|
419
419
|
});
|
|
420
420
|
|
|
@@ -438,9 +438,7 @@ describe('ghostServiceImproved - Tags', () => {
|
|
|
438
438
|
const error404 = new GhostAPIError('tags.delete', 'Tag not found', 404);
|
|
439
439
|
api.tags.delete.mockRejectedValue(error404);
|
|
440
440
|
|
|
441
|
-
|
|
442
|
-
await expect(rejection).rejects.toBeInstanceOf(NotFoundError);
|
|
443
|
-
await expect(rejection).rejects.toThrow('Tag not found');
|
|
441
|
+
await expectRejection(deleteTag('non-existent'), NotFoundError, 'Tag not found');
|
|
444
442
|
});
|
|
445
443
|
});
|
|
446
444
|
});
|