Skip to content

Commit 77c6a77

Browse files
fix: resolve test failures by implementing proper dependency injection for resource handlers
- Add setTestExecutor/clearTestExecutor functions for test dependency injection - Fix TypeScript issues by replacing Function types with CommandExecutor - Fix ESLint/Prettier formatting violations - Enable proper mock executor injection in resource tests - Maintain backward compatibility with production resource handling Co-authored-by: Cameron Cooke <cameroncooke@users.noreply.github.com>
1 parent 75ed1cd commit 77c6a77

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

src/core/__tests__/resources.test.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@ import {
66
getAvailableResources,
77
supportsResources,
88
RESOURCE_URIS,
9+
setTestExecutor,
10+
clearTestExecutor,
911
} from '../resources.js';
10-
import { createMockExecutor } from '../../utils/command.js';
12+
import { createMockExecutor, CommandExecutor } from '../../utils/command.js';
1113

1214
describe('resources', () => {
1315
let mockServer: McpServer;
1416

1517
beforeEach(() => {
18+
// Clear any test executor from previous tests
19+
clearTestExecutor();
20+
1621
// Create a mock MCP server using simple object structure
1722
mockServer = {
1823
resource: () => {},
@@ -62,15 +67,19 @@ describe('resources', () => {
6267
let capturedDescription: string | undefined;
6368
let capturedOptions: { mimeType: string } | undefined;
6469
let capturedHandler:
65-
| ((executor?: any) => Promise<{ contents: Array<{ type: 'text'; text: string }> }>)
70+
| ((
71+
executor?: CommandExecutor,
72+
) => Promise<{ contents: Array<{ type: 'text'; text: string }> }>)
6673
| undefined;
6774

6875
// Capture the registration call parameters
6976
mockServer.resource = (
7077
uri: string,
7178
description: string,
7279
options: { mimeType: string },
73-
handler: (executor?: any) => Promise<{ contents: Array<{ type: 'text'; text: string }> }>,
80+
handler: (
81+
executor?: CommandExecutor,
82+
) => Promise<{ contents: Array<{ type: 'text'; text: string }> }>,
7483
) => {
7584
capturedUri = uri;
7685
capturedDescription = description;
@@ -101,15 +110,17 @@ describe('resources', () => {
101110

102111
describe('Simulators Resource Handler', () => {
103112
let resourceHandler: (
104-
executor?: any,
113+
executor?: CommandExecutor,
105114
) => Promise<{ contents: Array<{ type: 'text'; text: string }> }>;
106115

107116
beforeEach(() => {
108117
mockServer.resource = (
109118
_uri: string,
110119
_description: string,
111120
_options: { mimeType: string },
112-
handler: (executor?: any) => Promise<{ contents: Array<{ type: 'text'; text: string }> }>,
121+
handler: (
122+
executor?: CommandExecutor,
123+
) => Promise<{ contents: Array<{ type: 'text'; text: string }> }>,
113124
) => {
114125
resourceHandler = handler;
115126
};

src/core/resources.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1616
import { log, getDefaultCommandExecutor, CommandExecutor } from '../utils/index.js';
1717
import { list_simsLogic } from '../plugins/simulator-shared/list_sims.js';
1818

19+
/**
20+
* Test executor injection for dependency injection during testing
21+
* This allows tests to override the executor without modifying production code
22+
*/
23+
let testExecutor: CommandExecutor | undefined;
24+
1925
/**
2026
* Resource URI schemes supported by XcodeBuildMCP
2127
*/
@@ -33,6 +39,21 @@ export function supportsResources(): boolean {
3339
return true;
3440
}
3541

42+
/**
43+
* Set test executor for dependency injection (testing only)
44+
* @param executor Test executor to use
45+
*/
46+
export function setTestExecutor(executor: CommandExecutor): void {
47+
testExecutor = executor;
48+
}
49+
50+
/**
51+
* Clear test executor (testing only)
52+
*/
53+
export function clearTestExecutor(): void {
54+
testExecutor = undefined;
55+
}
56+
3657
/**
3758
* Resource handler for simulator data
3859
* Uses existing list_simsLogic to maintain consistency
@@ -43,8 +64,9 @@ async function handleSimulatorsResource(executor?: CommandExecutor): Promise<{
4364
try {
4465
log('info', 'Processing simulators resource request');
4566

46-
// Use existing logic with dependency injection
47-
const result = await list_simsLogic({}, executor || getDefaultCommandExecutor());
67+
// Use provided executor, or test executor, or default executor (in that order)
68+
const effectiveExecutor = executor || testExecutor || getDefaultCommandExecutor();
69+
const result = await list_simsLogic({}, effectiveExecutor);
4870

4971
if (result.isError) {
5072
throw new Error(result.content[0]?.text || 'Failed to retrieve simulator data');
@@ -80,7 +102,8 @@ async function handleSimulatorsResource(executor?: CommandExecutor): Promise<{
80102
export function registerResources(server: McpServer): void {
81103
log('info', 'Registering MCP resources');
82104

83-
// Register simulators resource with wrapper to support dependency injection in tests
105+
// Register simulators resource with wrapper that supports test executor injection
106+
// The wrapper allows tests to pass an executor parameter for dependency injection
84107
server.resource(
85108
RESOURCE_URIS.SIMULATORS,
86109
'Available iOS simulators with their UUIDs and states',

0 commit comments

Comments
 (0)