@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jgardner04/ghost-mcp-server",
3
- "version": "1.14.2",
3
+ "version": "1.14.3",
4
4
  "description": "A Model Context Protocol (MCP) server for interacting with Ghost CMS via the Admin API",
5
5
  "author": "Jonathan Gardner",
6
6
  "type": "module",
@@ -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
- const rejection = updateMember('non-existent', { name: 'Test' });
191
- await expect(rejection).rejects.toBeInstanceOf(NotFoundError);
192
- await expect(rejection).rejects.toThrow('Member not found');
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
- const rejection = deleteMember('non-existent');
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
- const rejection = getMember({ id: 'non-existent' });
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
- const rejection = createPage({ title: 'Test', html: '<p>Content</p>' });
214
- await expect(rejection).rejects.toBeInstanceOf(ValidationError);
215
- await expect(rejection).rejects.toThrow('Page creation failed due to validation errors');
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
- const rejection = updatePage('nonexistent-id', { title: 'Updated' });
280
- await expect(rejection).rejects.toBeInstanceOf(NotFoundError);
281
- await expect(rejection).rejects.toThrow('Page not found');
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
- const rejection = deletePage('nonexistent-id');
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
- const rejection = getPage('nonexistent-id');
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
- const rejection = updatePost('nonexistent-id', { title: 'Updated' });
99
- await expect(rejection).rejects.toBeInstanceOf(NotFoundError);
100
- await expect(rejection).rejects.toThrow('Post not found');
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
- const rejection = getTag('non-existent');
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
- const rejection = updateTag('non-existent', { name: 'Test' });
416
- await expect(rejection).rejects.toBeInstanceOf(NotFoundError);
417
- await expect(rejection).rejects.toThrow('Tag not found');
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
- const rejection = deleteTag('non-existent');
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
  });