mcp-rubber-duck 1.5.1 → 1.6.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.
Files changed (69) hide show
  1. package/.claude/agents/pricing-updater.md +111 -0
  2. package/.claude/commands/update-pricing.md +22 -0
  3. package/.releaserc.json +4 -0
  4. package/CHANGELOG.md +14 -0
  5. package/dist/config/types.d.ts +72 -0
  6. package/dist/config/types.d.ts.map +1 -1
  7. package/dist/config/types.js +8 -0
  8. package/dist/config/types.js.map +1 -1
  9. package/dist/data/default-pricing.d.ts +18 -0
  10. package/dist/data/default-pricing.d.ts.map +1 -0
  11. package/dist/data/default-pricing.js +307 -0
  12. package/dist/data/default-pricing.js.map +1 -0
  13. package/dist/providers/enhanced-manager.d.ts +2 -1
  14. package/dist/providers/enhanced-manager.d.ts.map +1 -1
  15. package/dist/providers/enhanced-manager.js +20 -2
  16. package/dist/providers/enhanced-manager.js.map +1 -1
  17. package/dist/providers/manager.d.ts +3 -1
  18. package/dist/providers/manager.d.ts.map +1 -1
  19. package/dist/providers/manager.js +12 -1
  20. package/dist/providers/manager.js.map +1 -1
  21. package/dist/server.d.ts +2 -0
  22. package/dist/server.d.ts.map +1 -1
  23. package/dist/server.js +35 -4
  24. package/dist/server.js.map +1 -1
  25. package/dist/services/pricing.d.ts +56 -0
  26. package/dist/services/pricing.d.ts.map +1 -0
  27. package/dist/services/pricing.js +124 -0
  28. package/dist/services/pricing.js.map +1 -0
  29. package/dist/services/usage.d.ts +48 -0
  30. package/dist/services/usage.d.ts.map +1 -0
  31. package/dist/services/usage.js +243 -0
  32. package/dist/services/usage.js.map +1 -0
  33. package/dist/tools/get-usage-stats.d.ts +8 -0
  34. package/dist/tools/get-usage-stats.d.ts.map +1 -0
  35. package/dist/tools/get-usage-stats.js +92 -0
  36. package/dist/tools/get-usage-stats.js.map +1 -0
  37. package/package.json +1 -1
  38. package/src/config/types.ts +51 -0
  39. package/src/data/default-pricing.ts +368 -0
  40. package/src/providers/enhanced-manager.ts +41 -4
  41. package/src/providers/manager.ts +22 -1
  42. package/src/server.ts +42 -4
  43. package/src/services/pricing.ts +155 -0
  44. package/src/services/usage.ts +293 -0
  45. package/src/tools/get-usage-stats.ts +109 -0
  46. package/tests/approval.test.ts +440 -0
  47. package/tests/cache.test.ts +240 -0
  48. package/tests/config.test.ts +468 -0
  49. package/tests/consensus.test.ts +10 -0
  50. package/tests/conversation.test.ts +86 -0
  51. package/tests/duck-debate.test.ts +105 -1
  52. package/tests/duck-iterate.test.ts +30 -0
  53. package/tests/duck-judge.test.ts +93 -0
  54. package/tests/duck-vote.test.ts +46 -0
  55. package/tests/health.test.ts +129 -0
  56. package/tests/pricing.test.ts +335 -0
  57. package/tests/providers.test.ts +591 -0
  58. package/tests/safe-logger.test.ts +314 -0
  59. package/tests/tools/approve-mcp-request.test.ts +239 -0
  60. package/tests/tools/ask-duck.test.ts +159 -0
  61. package/tests/tools/chat-duck.test.ts +191 -0
  62. package/tests/tools/compare-ducks.test.ts +190 -0
  63. package/tests/tools/duck-council.test.ts +219 -0
  64. package/tests/tools/get-pending-approvals.test.ts +195 -0
  65. package/tests/tools/get-usage-stats.test.ts +236 -0
  66. package/tests/tools/list-ducks.test.ts +144 -0
  67. package/tests/tools/list-models.test.ts +163 -0
  68. package/tests/tools/mcp-status.test.ts +330 -0
  69. package/tests/usage.test.ts +661 -0
@@ -0,0 +1,159 @@
1
+ import { describe, it, expect, jest, beforeEach } from '@jest/globals';
2
+ import { askDuckTool } from '../../src/tools/ask-duck.js';
3
+ import { ProviderManager } from '../../src/providers/manager.js';
4
+ import { ResponseCache } from '../../src/services/cache.js';
5
+
6
+ // Mock dependencies
7
+ jest.mock('../../src/utils/logger');
8
+ jest.mock('../../src/providers/manager.js');
9
+ jest.mock('../../src/services/cache.js');
10
+
11
+ describe('askDuckTool', () => {
12
+ let mockProviderManager: jest.Mocked<ProviderManager>;
13
+ let mockCache: jest.Mocked<ResponseCache>;
14
+
15
+ const mockResponse = {
16
+ provider: 'openai',
17
+ nickname: 'OpenAI Duck',
18
+ content: 'This is a test response from the duck.',
19
+ model: 'gpt-4',
20
+ latency: 150,
21
+ usage: {
22
+ prompt_tokens: 10,
23
+ completion_tokens: 20,
24
+ total_tokens: 30,
25
+ },
26
+ };
27
+
28
+ beforeEach(() => {
29
+ mockProviderManager = {
30
+ askDuck: jest.fn().mockResolvedValue(mockResponse),
31
+ validateModel: jest.fn().mockReturnValue(true),
32
+ } as unknown as jest.Mocked<ProviderManager>;
33
+
34
+ mockCache = {
35
+ generateKey: jest.fn().mockReturnValue('test-cache-key'),
36
+ getOrSet: jest.fn().mockImplementation(async (_key, fetcher) => {
37
+ const value = await fetcher();
38
+ return { value, cached: false };
39
+ }),
40
+ } as unknown as jest.Mocked<ResponseCache>;
41
+ });
42
+
43
+ it('should throw error when prompt is missing', async () => {
44
+ await expect(askDuckTool(mockProviderManager, mockCache, {})).rejects.toThrow(
45
+ 'Prompt is required'
46
+ );
47
+ });
48
+
49
+ it('should ask duck with basic prompt', async () => {
50
+ const result = await askDuckTool(mockProviderManager, mockCache, {
51
+ prompt: 'What is TypeScript?',
52
+ });
53
+
54
+ expect(mockCache.generateKey).toHaveBeenCalledWith('default', 'What is TypeScript?', {
55
+ model: undefined,
56
+ temperature: undefined,
57
+ });
58
+ expect(result.content).toHaveLength(1);
59
+ expect(result.content[0].type).toBe('text');
60
+ expect(result.content[0].text).toContain('OpenAI Duck');
61
+ expect(result.content[0].text).toContain('test response');
62
+ });
63
+
64
+ it('should include usage info in response', async () => {
65
+ const result = await askDuckTool(mockProviderManager, mockCache, {
66
+ prompt: 'Test prompt',
67
+ });
68
+
69
+ expect(result.content[0].text).toContain('Tokens used: 30');
70
+ expect(result.content[0].text).toContain('10 prompt');
71
+ expect(result.content[0].text).toContain('20 completion');
72
+ });
73
+
74
+ it('should show latency and fresh status for non-cached response', async () => {
75
+ const result = await askDuckTool(mockProviderManager, mockCache, {
76
+ prompt: 'Test prompt',
77
+ });
78
+
79
+ expect(result.content[0].text).toContain('150ms');
80
+ expect(result.content[0].text).toContain('Fresh');
81
+ });
82
+
83
+ it('should show cached status for cached response', async () => {
84
+ mockCache.getOrSet.mockResolvedValue({ value: mockResponse, cached: true });
85
+
86
+ const result = await askDuckTool(mockProviderManager, mockCache, {
87
+ prompt: 'Test prompt',
88
+ });
89
+
90
+ expect(result.content[0].text).toContain('Cached');
91
+ });
92
+
93
+ it('should pass provider option', async () => {
94
+ await askDuckTool(mockProviderManager, mockCache, {
95
+ prompt: 'Test',
96
+ provider: 'groq',
97
+ });
98
+
99
+ expect(mockCache.generateKey).toHaveBeenCalledWith('groq', 'Test', expect.any(Object));
100
+ });
101
+
102
+ it('should pass model and temperature options', async () => {
103
+ await askDuckTool(mockProviderManager, mockCache, {
104
+ prompt: 'Test',
105
+ provider: 'openai',
106
+ model: 'gpt-3.5-turbo',
107
+ temperature: 0.5,
108
+ });
109
+
110
+ expect(mockCache.generateKey).toHaveBeenCalledWith('openai', 'Test', {
111
+ model: 'gpt-3.5-turbo',
112
+ temperature: 0.5,
113
+ });
114
+ });
115
+
116
+ it('should validate model when both provider and model are specified', async () => {
117
+ await askDuckTool(mockProviderManager, mockCache, {
118
+ prompt: 'Test',
119
+ provider: 'openai',
120
+ model: 'gpt-4',
121
+ });
122
+
123
+ expect(mockProviderManager.validateModel).toHaveBeenCalledWith('openai', 'gpt-4');
124
+ });
125
+
126
+ it('should not validate model when provider is not specified', async () => {
127
+ await askDuckTool(mockProviderManager, mockCache, {
128
+ prompt: 'Test',
129
+ model: 'gpt-4',
130
+ });
131
+
132
+ expect(mockProviderManager.validateModel).not.toHaveBeenCalled();
133
+ });
134
+
135
+ it('should handle response without usage info', async () => {
136
+ const responseWithoutUsage = { ...mockResponse, usage: undefined };
137
+ mockCache.getOrSet.mockResolvedValue({ value: responseWithoutUsage, cached: false });
138
+
139
+ const result = await askDuckTool(mockProviderManager, mockCache, {
140
+ prompt: 'Test',
141
+ });
142
+
143
+ expect(result.content[0].text).not.toContain('Tokens used');
144
+ });
145
+
146
+ it('should warn when model is not valid for provider', async () => {
147
+ mockProviderManager.validateModel.mockReturnValue(false);
148
+
149
+ // Should still work, just log a warning
150
+ const result = await askDuckTool(mockProviderManager, mockCache, {
151
+ prompt: 'Test',
152
+ provider: 'openai',
153
+ model: 'invalid-model',
154
+ });
155
+
156
+ expect(mockProviderManager.validateModel).toHaveBeenCalledWith('openai', 'invalid-model');
157
+ expect(result.content[0].text).toContain('test response');
158
+ });
159
+ });
@@ -0,0 +1,191 @@
1
+ import { describe, it, expect, jest, beforeEach } from '@jest/globals';
2
+ import { chatDuckTool } from '../../src/tools/chat-duck.js';
3
+ import { ProviderManager } from '../../src/providers/manager.js';
4
+ import { ConversationManager } from '../../src/services/conversation.js';
5
+
6
+ // Mock dependencies
7
+ jest.mock('../../src/utils/logger');
8
+ jest.mock('../../src/providers/manager.js');
9
+ jest.mock('../../src/services/conversation.js');
10
+
11
+ describe('chatDuckTool', () => {
12
+ let mockProviderManager: jest.Mocked<ProviderManager>;
13
+ let mockConversationManager: jest.Mocked<ConversationManager>;
14
+
15
+ const mockResponse = {
16
+ provider: 'openai',
17
+ nickname: 'OpenAI Duck',
18
+ content: 'This is a test response.',
19
+ model: 'gpt-4',
20
+ latency: 150,
21
+ };
22
+
23
+ const mockConversation = {
24
+ id: 'test-conv',
25
+ provider: 'openai',
26
+ messages: [],
27
+ createdAt: new Date(),
28
+ updatedAt: new Date(),
29
+ };
30
+
31
+ beforeEach(() => {
32
+ mockProviderManager = {
33
+ askDuck: jest.fn().mockResolvedValue(mockResponse),
34
+ getProviderNames: jest.fn().mockReturnValue(['openai', 'groq']),
35
+ } as unknown as jest.Mocked<ProviderManager>;
36
+
37
+ mockConversationManager = {
38
+ getConversation: jest.fn().mockReturnValue(mockConversation),
39
+ createConversation: jest.fn().mockReturnValue(mockConversation),
40
+ switchProvider: jest.fn().mockReturnValue({ ...mockConversation, provider: 'groq' }),
41
+ addMessage: jest.fn().mockReturnValue(mockConversation),
42
+ getConversationContext: jest.fn().mockReturnValue([]),
43
+ } as unknown as jest.Mocked<ConversationManager>;
44
+ });
45
+
46
+ it('should throw error when conversation_id is missing', async () => {
47
+ await expect(
48
+ chatDuckTool(mockProviderManager, mockConversationManager, { message: 'Hello' })
49
+ ).rejects.toThrow('conversation_id and message are required');
50
+ });
51
+
52
+ it('should throw error when message is missing', async () => {
53
+ await expect(
54
+ chatDuckTool(mockProviderManager, mockConversationManager, { conversation_id: 'test' })
55
+ ).rejects.toThrow('conversation_id and message are required');
56
+ });
57
+
58
+ it('should create new conversation if not exists', async () => {
59
+ mockConversationManager.getConversation.mockReturnValue(undefined);
60
+
61
+ await chatDuckTool(mockProviderManager, mockConversationManager, {
62
+ conversation_id: 'new-conv',
63
+ message: 'Hello',
64
+ });
65
+
66
+ expect(mockConversationManager.createConversation).toHaveBeenCalledWith('new-conv', 'openai');
67
+ });
68
+
69
+ it('should use existing conversation', async () => {
70
+ await chatDuckTool(mockProviderManager, mockConversationManager, {
71
+ conversation_id: 'test-conv',
72
+ message: 'Hello',
73
+ });
74
+
75
+ expect(mockConversationManager.createConversation).not.toHaveBeenCalled();
76
+ });
77
+
78
+ it('should switch provider when requested', async () => {
79
+ await chatDuckTool(mockProviderManager, mockConversationManager, {
80
+ conversation_id: 'test-conv',
81
+ message: 'Hello',
82
+ provider: 'groq',
83
+ });
84
+
85
+ expect(mockConversationManager.switchProvider).toHaveBeenCalledWith('test-conv', 'groq');
86
+ });
87
+
88
+ it('should not switch provider if same as current', async () => {
89
+ await chatDuckTool(mockProviderManager, mockConversationManager, {
90
+ conversation_id: 'test-conv',
91
+ message: 'Hello',
92
+ provider: 'openai', // Same as mockConversation.provider
93
+ });
94
+
95
+ expect(mockConversationManager.switchProvider).not.toHaveBeenCalled();
96
+ });
97
+
98
+ it('should add user message to conversation', async () => {
99
+ await chatDuckTool(mockProviderManager, mockConversationManager, {
100
+ conversation_id: 'test-conv',
101
+ message: 'What is TypeScript?',
102
+ });
103
+
104
+ expect(mockConversationManager.addMessage).toHaveBeenCalledWith(
105
+ 'test-conv',
106
+ expect.objectContaining({
107
+ role: 'user',
108
+ content: 'What is TypeScript?',
109
+ })
110
+ );
111
+ });
112
+
113
+ it('should add assistant response to conversation', async () => {
114
+ await chatDuckTool(mockProviderManager, mockConversationManager, {
115
+ conversation_id: 'test-conv',
116
+ message: 'Hello',
117
+ });
118
+
119
+ expect(mockConversationManager.addMessage).toHaveBeenCalledWith(
120
+ 'test-conv',
121
+ expect.objectContaining({
122
+ role: 'assistant',
123
+ content: 'This is a test response.',
124
+ })
125
+ );
126
+ });
127
+
128
+ it('should pass conversation context to provider', async () => {
129
+ const contextMessages = [
130
+ { role: 'user' as const, content: 'Previous', timestamp: new Date() },
131
+ ];
132
+ mockConversationManager.getConversationContext.mockReturnValue(contextMessages);
133
+
134
+ await chatDuckTool(mockProviderManager, mockConversationManager, {
135
+ conversation_id: 'test-conv',
136
+ message: 'Hello',
137
+ });
138
+
139
+ expect(mockProviderManager.askDuck).toHaveBeenCalledWith(
140
+ 'openai',
141
+ '',
142
+ expect.objectContaining({
143
+ messages: contextMessages,
144
+ })
145
+ );
146
+ });
147
+
148
+ it('should pass model option to provider', async () => {
149
+ await chatDuckTool(mockProviderManager, mockConversationManager, {
150
+ conversation_id: 'test-conv',
151
+ message: 'Hello',
152
+ model: 'gpt-3.5-turbo',
153
+ });
154
+
155
+ expect(mockProviderManager.askDuck).toHaveBeenCalledWith(
156
+ 'openai',
157
+ '',
158
+ expect.objectContaining({
159
+ model: 'gpt-3.5-turbo',
160
+ })
161
+ );
162
+ });
163
+
164
+ it('should format response with conversation info', async () => {
165
+ mockConversationManager.getConversationContext.mockReturnValue([
166
+ { role: 'user' as const, content: 'Hello', timestamp: new Date() },
167
+ ]);
168
+
169
+ const result = await chatDuckTool(mockProviderManager, mockConversationManager, {
170
+ conversation_id: 'test-conv',
171
+ message: 'Hello',
172
+ });
173
+
174
+ expect(result.content[0].text).toContain('OpenAI Duck');
175
+ expect(result.content[0].text).toContain('test-conv');
176
+ expect(result.content[0].text).toContain('Messages: 2'); // context (1) + 1 new
177
+ expect(result.content[0].text).toContain('150ms');
178
+ });
179
+
180
+ it('should use specified provider for new conversation', async () => {
181
+ mockConversationManager.getConversation.mockReturnValue(undefined);
182
+
183
+ await chatDuckTool(mockProviderManager, mockConversationManager, {
184
+ conversation_id: 'new-conv',
185
+ message: 'Hello',
186
+ provider: 'groq',
187
+ });
188
+
189
+ expect(mockConversationManager.createConversation).toHaveBeenCalledWith('new-conv', 'groq');
190
+ });
191
+ });
@@ -0,0 +1,190 @@
1
+ import { describe, it, expect, jest, beforeEach } from '@jest/globals';
2
+ import { compareDucksTool } from '../../src/tools/compare-ducks.js';
3
+ import { ProviderManager } from '../../src/providers/manager.js';
4
+
5
+ // Mock dependencies
6
+ jest.mock('../../src/utils/logger');
7
+ jest.mock('../../src/providers/manager.js');
8
+
9
+ describe('compareDucksTool', () => {
10
+ let mockProviderManager: jest.Mocked<ProviderManager>;
11
+
12
+ const mockResponses = [
13
+ {
14
+ provider: 'openai',
15
+ nickname: 'OpenAI Duck',
16
+ content: 'OpenAI says: TypeScript is great!',
17
+ model: 'gpt-4',
18
+ latency: 150,
19
+ cached: false,
20
+ usage: {
21
+ prompt_tokens: 10,
22
+ completion_tokens: 20,
23
+ total_tokens: 30,
24
+ },
25
+ },
26
+ {
27
+ provider: 'groq',
28
+ nickname: 'Groq Duck',
29
+ content: 'Groq says: TypeScript rocks!',
30
+ model: 'llama-3.1-70b',
31
+ latency: 80,
32
+ cached: false,
33
+ usage: {
34
+ prompt_tokens: 10,
35
+ completion_tokens: 15,
36
+ total_tokens: 25,
37
+ },
38
+ },
39
+ ];
40
+
41
+ beforeEach(() => {
42
+ mockProviderManager = {
43
+ compareDucks: jest.fn().mockResolvedValue(mockResponses),
44
+ } as unknown as jest.Mocked<ProviderManager>;
45
+ });
46
+
47
+ it('should throw error when prompt is missing', async () => {
48
+ await expect(compareDucksTool(mockProviderManager, {})).rejects.toThrow('Prompt is required');
49
+ });
50
+
51
+ it('should compare ducks with basic prompt', async () => {
52
+ const result = await compareDucksTool(mockProviderManager, {
53
+ prompt: 'What is TypeScript?',
54
+ });
55
+
56
+ expect(mockProviderManager.compareDucks).toHaveBeenCalledWith(
57
+ 'What is TypeScript?',
58
+ undefined,
59
+ { model: undefined }
60
+ );
61
+ expect(result.content).toHaveLength(1);
62
+ expect(result.content[0].type).toBe('text');
63
+ expect(result.content[0].text).toContain('Asked:');
64
+ expect(result.content[0].text).toContain('What is TypeScript?');
65
+ });
66
+
67
+ it('should display all duck responses', async () => {
68
+ const result = await compareDucksTool(mockProviderManager, {
69
+ prompt: 'Test',
70
+ });
71
+
72
+ expect(result.content[0].text).toContain('OpenAI Duck');
73
+ expect(result.content[0].text).toContain('Groq Duck');
74
+ expect(result.content[0].text).toContain('OpenAI says');
75
+ expect(result.content[0].text).toContain('Groq says');
76
+ });
77
+
78
+ it('should display model and token usage', async () => {
79
+ const result = await compareDucksTool(mockProviderManager, {
80
+ prompt: 'Test',
81
+ });
82
+
83
+ expect(result.content[0].text).toContain('gpt-4');
84
+ expect(result.content[0].text).toContain('llama-3.1-70b');
85
+ expect(result.content[0].text).toContain('Tokens: 30');
86
+ expect(result.content[0].text).toContain('Tokens: 25');
87
+ });
88
+
89
+ it('should display latency info', async () => {
90
+ const result = await compareDucksTool(mockProviderManager, {
91
+ prompt: 'Test',
92
+ });
93
+
94
+ expect(result.content[0].text).toContain('150ms');
95
+ expect(result.content[0].text).toContain('80ms');
96
+ });
97
+
98
+ it('should show cached indicator when response is cached', async () => {
99
+ mockProviderManager.compareDucks.mockResolvedValue([
100
+ {
101
+ ...mockResponses[0],
102
+ cached: true,
103
+ },
104
+ ]);
105
+
106
+ const result = await compareDucksTool(mockProviderManager, {
107
+ prompt: 'Test',
108
+ });
109
+
110
+ expect(result.content[0].text).toContain('Cached');
111
+ });
112
+
113
+ it('should show success count in summary', async () => {
114
+ const result = await compareDucksTool(mockProviderManager, {
115
+ prompt: 'Test',
116
+ });
117
+
118
+ expect(result.content[0].text).toContain('2/2 ducks responded successfully');
119
+ });
120
+
121
+ it('should handle error responses', async () => {
122
+ mockProviderManager.compareDucks.mockResolvedValue([
123
+ mockResponses[0],
124
+ {
125
+ provider: 'groq',
126
+ nickname: 'Groq Duck',
127
+ content: 'Error: API key invalid',
128
+ model: '',
129
+ latency: 0,
130
+ cached: false,
131
+ },
132
+ ]);
133
+
134
+ const result = await compareDucksTool(mockProviderManager, {
135
+ prompt: 'Test',
136
+ });
137
+
138
+ expect(result.content[0].text).toContain('Error: API key invalid');
139
+ expect(result.content[0].text).toContain('1/2 ducks responded successfully');
140
+ });
141
+
142
+ it('should pass specific providers when provided', async () => {
143
+ await compareDucksTool(mockProviderManager, {
144
+ prompt: 'Test',
145
+ providers: ['openai', 'groq'],
146
+ });
147
+
148
+ expect(mockProviderManager.compareDucks).toHaveBeenCalledWith('Test', ['openai', 'groq'], {
149
+ model: undefined,
150
+ });
151
+ });
152
+
153
+ it('should pass model option', async () => {
154
+ await compareDucksTool(mockProviderManager, {
155
+ prompt: 'Test',
156
+ model: 'gpt-3.5-turbo',
157
+ });
158
+
159
+ expect(mockProviderManager.compareDucks).toHaveBeenCalledWith('Test', undefined, {
160
+ model: 'gpt-3.5-turbo',
161
+ });
162
+ });
163
+
164
+ it('should handle empty response list', async () => {
165
+ mockProviderManager.compareDucks.mockResolvedValue([]);
166
+
167
+ const result = await compareDucksTool(mockProviderManager, {
168
+ prompt: 'Test',
169
+ });
170
+
171
+ expect(result.content[0].text).toContain('0/0 ducks responded successfully');
172
+ });
173
+
174
+ it('should not show latency when zero', async () => {
175
+ mockProviderManager.compareDucks.mockResolvedValue([
176
+ {
177
+ ...mockResponses[0],
178
+ latency: 0,
179
+ },
180
+ ]);
181
+
182
+ const result = await compareDucksTool(mockProviderManager, {
183
+ prompt: 'Test',
184
+ });
185
+
186
+ // When latency is 0, the ms indicator should not be shown for that response
187
+ // (the code checks latency > 0)
188
+ expect(result.content[0].text).not.toContain('0ms');
189
+ });
190
+ });