@dependabit/monitor 0.1.14 → 0.1.15

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,352 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { OpenAPIChecker } from '../../src/checkers/openapi.js';
3
- import type { AccessConfig, DependencySnapshot } from '../../src/types.js';
4
-
5
- describe('OpenAPIChecker', () => {
6
- let checker: OpenAPIChecker;
7
-
8
- beforeEach(() => {
9
- checker = new OpenAPIChecker();
10
- });
11
-
12
- afterEach(() => {
13
- vi.restoreAllMocks();
14
- });
15
-
16
- describe('fetch', () => {
17
- it('should fetch and parse JSON OpenAPI spec', async () => {
18
- const mockSpec = {
19
- openapi: '3.0.0',
20
- info: {
21
- title: 'Test API',
22
- version: '1.0.0',
23
- description: 'A test API'
24
- },
25
- paths: {
26
- '/users': {
27
- get: { operationId: 'getUsers' },
28
- post: { operationId: 'createUser' }
29
- },
30
- '/users/{id}': {
31
- get: { operationId: 'getUser' },
32
- delete: { operationId: 'deleteUser' }
33
- }
34
- },
35
- components: {
36
- schemas: {
37
- User: { type: 'object' },
38
- Error: { type: 'object' }
39
- }
40
- }
41
- };
42
-
43
- vi.spyOn(global, 'fetch').mockResolvedValue({
44
- ok: true,
45
- headers: new Headers({ 'content-type': 'application/json' }),
46
- text: async () => JSON.stringify(mockSpec)
47
- } as Response);
48
-
49
- const config: AccessConfig = {
50
- url: 'https://api.example.com/openapi.json',
51
- accessMethod: 'openapi'
52
- };
53
-
54
- const snapshot = await checker.fetch(config);
55
-
56
- expect(snapshot.version).toBe('1.0.0');
57
- expect(snapshot.stateHash).toBeDefined();
58
- expect(snapshot.fetchedAt).toBeInstanceOf(Date);
59
- expect(snapshot.metadata?.title).toBe('Test API');
60
- expect(snapshot.metadata?.endpointCount).toBe(2);
61
- expect(snapshot.metadata?.schemaCount).toBe(2);
62
- });
63
-
64
- it('should fetch and parse YAML OpenAPI spec', async () => {
65
- const yamlSpec = `
66
- openapi: '3.0.0'
67
- info:
68
- title: Test API
69
- version: '2.0.0'
70
- paths:
71
- /items:
72
- get:
73
- summary: List items
74
- post:
75
- summary: Create item
76
- components:
77
- schemas:
78
- Item:
79
- type: object
80
- `;
81
-
82
- vi.spyOn(global, 'fetch').mockResolvedValue({
83
- ok: true,
84
- headers: new Headers({ 'content-type': 'text/yaml' }),
85
- text: async () => yamlSpec
86
- } as Response);
87
-
88
- const config: AccessConfig = {
89
- url: 'https://api.example.com/openapi.yaml',
90
- accessMethod: 'openapi'
91
- };
92
-
93
- const snapshot = await checker.fetch(config);
94
-
95
- expect(snapshot.version).toBe('2.0.0');
96
- expect(snapshot.metadata?.title).toBe('Test API');
97
- });
98
-
99
- it('should handle authentication token', async () => {
100
- const mockSpec = { openapi: '3.0.0', info: { version: '1.0.0' } };
101
- const fetchSpy = vi.spyOn(global, 'fetch').mockResolvedValue({
102
- ok: true,
103
- headers: new Headers({ 'content-type': 'application/json' }),
104
- text: async () => JSON.stringify(mockSpec)
105
- } as Response);
106
-
107
- const config: AccessConfig = {
108
- url: 'https://api.example.com/openapi.json',
109
- accessMethod: 'openapi',
110
- auth: {
111
- type: 'token',
112
- secret: 'test-token'
113
- }
114
- };
115
-
116
- await checker.fetch(config);
117
-
118
- expect(fetchSpy).toHaveBeenCalledWith(
119
- 'https://api.example.com/openapi.json',
120
- expect.objectContaining({
121
- headers: expect.objectContaining({
122
- Authorization: 'Bearer test-token'
123
- })
124
- })
125
- );
126
- });
127
-
128
- it('should throw error on HTTP failure', async () => {
129
- vi.spyOn(global, 'fetch').mockResolvedValue({
130
- ok: false,
131
- status: 404,
132
- statusText: 'Not Found'
133
- } as Response);
134
-
135
- const config: AccessConfig = {
136
- url: 'https://api.example.com/openapi.json',
137
- accessMethod: 'openapi'
138
- };
139
-
140
- await expect(checker.fetch(config)).rejects.toThrow('HTTP error: 404 Not Found');
141
- });
142
-
143
- it('should throw error on invalid JSON', async () => {
144
- vi.spyOn(global, 'fetch').mockResolvedValue({
145
- ok: true,
146
- headers: new Headers({ 'content-type': 'application/json' }),
147
- text: async () => 'invalid json'
148
- } as Response);
149
-
150
- const config: AccessConfig = {
151
- url: 'https://api.example.com/openapi.json',
152
- accessMethod: 'openapi'
153
- };
154
-
155
- await expect(checker.fetch(config)).rejects.toThrow('Failed to fetch OpenAPI spec');
156
- });
157
- });
158
-
159
- describe('compare', () => {
160
- it('should detect no changes when specs are identical', async () => {
161
- const snapshot: DependencySnapshot = {
162
- version: '1.0.0',
163
- stateHash: 'abc123',
164
- fetchedAt: new Date(),
165
- metadata: {
166
- endpoints: { '/users': ['GET', 'POST'] },
167
- schemas: { User: {} }
168
- }
169
- };
170
-
171
- const result = await checker.compare(snapshot, { ...snapshot });
172
-
173
- expect(result.hasChanged).toBe(false);
174
- expect(result.changes).toHaveLength(0);
175
- });
176
-
177
- it('should detect added endpoints', async () => {
178
- const prev: DependencySnapshot = {
179
- version: '1.0.0',
180
- stateHash: 'abc123',
181
- fetchedAt: new Date(),
182
- metadata: {
183
- endpoints: { '/users': ['GET'] },
184
- schemas: {}
185
- }
186
- };
187
-
188
- const curr: DependencySnapshot = {
189
- version: '1.0.0',
190
- stateHash: 'def456',
191
- fetchedAt: new Date(),
192
- metadata: {
193
- endpoints: { '/users': ['GET'], '/items': ['GET', 'POST'] },
194
- schemas: {}
195
- }
196
- };
197
-
198
- const result = await checker.compare(prev, curr);
199
-
200
- expect(result.hasChanged).toBe(true);
201
- expect(result.changes).toContain('endpoints_added');
202
- expect(result.severity).toBe('minor');
203
- });
204
-
205
- it('should detect removed endpoints as breaking change', async () => {
206
- const prev: DependencySnapshot = {
207
- version: '1.0.0',
208
- stateHash: 'abc123',
209
- fetchedAt: new Date(),
210
- metadata: {
211
- endpoints: { '/users': ['GET'], '/items': ['GET'] },
212
- schemas: {}
213
- }
214
- };
215
-
216
- const curr: DependencySnapshot = {
217
- version: '1.0.0',
218
- stateHash: 'def456',
219
- fetchedAt: new Date(),
220
- metadata: {
221
- endpoints: { '/users': ['GET'] },
222
- schemas: {}
223
- }
224
- };
225
-
226
- const result = await checker.compare(prev, curr);
227
-
228
- expect(result.hasChanged).toBe(true);
229
- expect(result.changes).toContain('endpoints_removed');
230
- expect(result.severity).toBe('breaking');
231
- });
232
-
233
- it('should detect modified endpoints as major change', async () => {
234
- const prev: DependencySnapshot = {
235
- version: '1.0.0',
236
- stateHash: 'abc123',
237
- fetchedAt: new Date(),
238
- metadata: {
239
- endpoints: { '/users': ['GET', 'POST'] },
240
- schemas: {}
241
- }
242
- };
243
-
244
- const curr: DependencySnapshot = {
245
- version: '1.0.0',
246
- stateHash: 'def456',
247
- fetchedAt: new Date(),
248
- metadata: {
249
- endpoints: { '/users': ['GET', 'POST', 'PUT'] },
250
- schemas: {}
251
- }
252
- };
253
-
254
- const result = await checker.compare(prev, curr);
255
-
256
- expect(result.hasChanged).toBe(true);
257
- expect(result.changes).toContain('endpoints_modified');
258
- expect(result.severity).toBe('major');
259
- });
260
-
261
- it('should detect removed schemas as breaking change', async () => {
262
- const prev: DependencySnapshot = {
263
- version: '1.0.0',
264
- stateHash: 'abc123',
265
- fetchedAt: new Date(),
266
- metadata: {
267
- endpoints: {},
268
- schemas: { User: {}, Item: {} }
269
- }
270
- };
271
-
272
- const curr: DependencySnapshot = {
273
- version: '1.0.0',
274
- stateHash: 'def456',
275
- fetchedAt: new Date(),
276
- metadata: {
277
- endpoints: {},
278
- schemas: { User: {} }
279
- }
280
- };
281
-
282
- const result = await checker.compare(prev, curr);
283
-
284
- expect(result.hasChanged).toBe(true);
285
- expect(result.changes).toContain('schemas_removed');
286
- expect(result.severity).toBe('breaking');
287
- });
288
-
289
- it('should detect version changes', async () => {
290
- const prev: DependencySnapshot = {
291
- version: '1.0.0',
292
- stateHash: 'abc123',
293
- fetchedAt: new Date(),
294
- metadata: {
295
- endpoints: {},
296
- schemas: {}
297
- }
298
- };
299
-
300
- const curr: DependencySnapshot = {
301
- version: '2.0.0',
302
- stateHash: 'abc123',
303
- fetchedAt: new Date(),
304
- metadata: {
305
- endpoints: {},
306
- schemas: {}
307
- }
308
- };
309
-
310
- const result = await checker.compare(prev, curr);
311
-
312
- expect(result.hasChanged).toBe(true);
313
- expect(result.changes).toContain('version');
314
- expect(result.oldVersion).toBe('1.0.0');
315
- expect(result.newVersion).toBe('2.0.0');
316
- });
317
-
318
- it('should include diff details', async () => {
319
- const prev: DependencySnapshot = {
320
- version: '1.0.0',
321
- stateHash: 'abc123',
322
- fetchedAt: new Date(),
323
- metadata: {
324
- endpoints: { '/users': ['GET'] },
325
- schemas: { User: {} }
326
- }
327
- };
328
-
329
- const curr: DependencySnapshot = {
330
- version: '2.0.0',
331
- stateHash: 'def456',
332
- fetchedAt: new Date(),
333
- metadata: {
334
- endpoints: { '/users': ['GET'], '/items': ['POST'] },
335
- schemas: { User: {}, Item: {} }
336
- }
337
- };
338
-
339
- const result = await checker.compare(prev, curr);
340
-
341
- expect(result.diff).toBeDefined();
342
- const diff = result.diff as {
343
- addedEndpoints: string[];
344
- addedSchemas: string[];
345
- versionChanged: boolean;
346
- };
347
- expect(diff.addedEndpoints).toContain('/items');
348
- expect(diff.addedSchemas).toContain('Item');
349
- expect(diff.versionChanged).toBe(true);
350
- });
351
- });
352
- });
@@ -1,99 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { URLContentChecker } from '../../src/checkers/url-content.js';
3
-
4
- // Mock global fetch
5
- const mockFetch = vi.fn();
6
- global.fetch = mockFetch as any;
7
-
8
- describe('URLContentChecker', () => {
9
- let checker: URLContentChecker;
10
-
11
- beforeEach(() => {
12
- checker = new URLContentChecker();
13
- vi.clearAllMocks();
14
-
15
- // Default mock response for HTTP content
16
- mockFetch.mockResolvedValue({
17
- ok: true,
18
- status: 200,
19
- headers: {
20
- get: (name: string) => (name === 'content-type' ? 'text/html' : null)
21
- },
22
- text: async () => '<html><body>Test content</body></html>'
23
- });
24
- });
25
-
26
- describe('fetch', () => {
27
- it('should fetch and hash URL content', async () => {
28
- const config = {
29
- url: 'https://example.com/docs',
30
- accessMethod: 'http' as const
31
- };
32
-
33
- const result = await checker.fetch(config);
34
-
35
- expect(result).toBeDefined();
36
- expect(result.stateHash).toBeDefined();
37
- expect(result.stateHash).toMatch(/^[a-f0-9]{64}$/); // SHA256 hex
38
- expect(result.fetchedAt).toBeInstanceOf(Date);
39
- });
40
-
41
- it('should normalize HTML before hashing', async () => {
42
- const config = {
43
- url: 'https://example.com/docs',
44
- accessMethod: 'http' as const
45
- };
46
-
47
- const result = await checker.fetch(config);
48
-
49
- // Should produce consistent hash after normalization
50
- expect(result.stateHash).toBeDefined();
51
- });
52
-
53
- it('should throw error for unreachable URLs', async () => {
54
- mockFetch.mockRejectedValue(new Error('Network error'));
55
-
56
- const config = {
57
- url: 'https://invalid-url-that-does-not-exist.com',
58
- accessMethod: 'http' as const
59
- };
60
-
61
- await expect(checker.fetch(config)).rejects.toThrow();
62
- });
63
- });
64
-
65
- describe('compare', () => {
66
- it('should detect content changes via hash difference', async () => {
67
- const prev = {
68
- stateHash: 'abc123def456',
69
- fetchedAt: new Date('2024-01-01')
70
- };
71
-
72
- const curr = {
73
- stateHash: 'xyz789uvw012',
74
- fetchedAt: new Date('2024-01-02')
75
- };
76
-
77
- const result = await checker.compare(prev, curr);
78
-
79
- expect(result.hasChanged).toBe(true);
80
- expect(result.changes).toContain('content');
81
- });
82
-
83
- it('should return no change when hashes match', async () => {
84
- const prev = {
85
- stateHash: 'abc123def456',
86
- fetchedAt: new Date('2024-01-01')
87
- };
88
-
89
- const curr = {
90
- stateHash: 'abc123def456',
91
- fetchedAt: new Date('2024-01-02')
92
- };
93
-
94
- const result = await checker.compare(prev, curr);
95
-
96
- expect(result.hasChanged).toBe(false);
97
- });
98
- });
99
- });
@@ -1,108 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { StateComparator } from '../src/comparator.js';
3
-
4
- describe('StateComparator', () => {
5
- let comparator: StateComparator;
6
-
7
- beforeEach(() => {
8
- comparator = new StateComparator();
9
- });
10
-
11
- describe('compare', () => {
12
- it('should detect state hash changes', () => {
13
- const oldState = {
14
- stateHash: 'abc123',
15
- version: 'v1.0.0',
16
- fetchedAt: new Date('2024-01-01')
17
- };
18
-
19
- const newState = {
20
- stateHash: 'def456',
21
- version: 'v1.0.0',
22
- fetchedAt: new Date('2024-01-02')
23
- };
24
-
25
- const result = comparator.compare(oldState, newState);
26
-
27
- expect(result.hasChanged).toBe(true);
28
- expect(result.changes).toContain('stateHash');
29
- });
30
-
31
- it('should detect version changes', () => {
32
- const oldState = {
33
- stateHash: 'abc123',
34
- version: 'v1.0.0',
35
- fetchedAt: new Date('2024-01-01')
36
- };
37
-
38
- const newState = {
39
- stateHash: 'abc123',
40
- version: 'v2.0.0',
41
- fetchedAt: new Date('2024-01-02')
42
- };
43
-
44
- const result = comparator.compare(oldState, newState);
45
-
46
- expect(result.hasChanged).toBe(true);
47
- expect(result.changes).toContain('version');
48
- });
49
-
50
- it('should return no change when states match', () => {
51
- const oldState = {
52
- stateHash: 'abc123',
53
- version: 'v1.0.0',
54
- fetchedAt: new Date('2024-01-01')
55
- };
56
-
57
- const newState = {
58
- stateHash: 'abc123',
59
- version: 'v1.0.0',
60
- fetchedAt: new Date('2024-01-02')
61
- };
62
-
63
- const result = comparator.compare(oldState, newState);
64
-
65
- expect(result.hasChanged).toBe(false);
66
- expect(result.changes).toHaveLength(0);
67
- });
68
-
69
- it('should detect multiple changes', () => {
70
- const oldState = {
71
- stateHash: 'abc123',
72
- version: 'v1.0.0',
73
- metadata: { author: 'Alice' },
74
- fetchedAt: new Date('2024-01-01')
75
- };
76
-
77
- const newState = {
78
- stateHash: 'def456',
79
- version: 'v2.0.0',
80
- metadata: { author: 'Bob' },
81
- fetchedAt: new Date('2024-01-02')
82
- };
83
-
84
- const result = comparator.compare(oldState, newState);
85
-
86
- expect(result.hasChanged).toBe(true);
87
- expect(result.changes.length).toBeGreaterThan(1);
88
- });
89
-
90
- it('should handle missing version in old state', () => {
91
- const oldState = {
92
- stateHash: 'abc123',
93
- fetchedAt: new Date('2024-01-01')
94
- };
95
-
96
- const newState = {
97
- stateHash: 'abc123',
98
- version: 'v1.0.0',
99
- fetchedAt: new Date('2024-01-02')
100
- };
101
-
102
- const result = comparator.compare(oldState, newState);
103
-
104
- expect(result.hasChanged).toBe(true);
105
- expect(result.changes).toContain('version');
106
- });
107
- });
108
- });