Skip to content

Commit

Permalink
Fix lint issues
Browse files Browse the repository at this point in the history
  • Loading branch information
domdomegg committed Dec 13, 2024
1 parent c0a273b commit 5c89294
Show file tree
Hide file tree
Showing 9 changed files with 389 additions and 374 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"eslint-config-domdomegg"
],
"rules": {
"import/extensions": "always"
"import/extensions": ["error", "always"]
}
}
}
106 changes: 54 additions & 52 deletions src/airtableService.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { describe, test, expect, vi, beforeEach, Mock, MockedFunction } from 'vitest';
import {
describe, test, expect, vi, beforeEach, MockedFunction,
} from 'vitest';
import nodeFetch, { Response } from 'node-fetch';
import { AirtableService } from './airtableService.js';
import { Response } from 'node-fetch';

describe('AirtableService', () => {
const mockApiKey = 'test-api-key';
Expand All @@ -12,21 +14,21 @@ describe('AirtableService', () => {
// Create a mock fetch function that we'll inject
mockFetch = vi.fn().mockResolvedValue({
ok: true,
text: () => Promise.resolve(JSON.stringify({ success: true }))
text: () => Promise.resolve(JSON.stringify({ success: true })),
});

// Initialize service with our mock fetch
service = new AirtableService(mockApiKey, mockBaseUrl, mockFetch as any);
service = new AirtableService(mockApiKey, mockBaseUrl, mockFetch as typeof nodeFetch);
});

describe('constructor', () => {
test('initializes with default base URL', () => {
const defaultService = new AirtableService(mockApiKey, undefined, mockFetch as any);
const defaultService = new AirtableService(mockApiKey, undefined, mockFetch as typeof nodeFetch);
expect(defaultService).toBeInstanceOf(AirtableService);
});

test('initializes with custom base URL', () => {
const customService = new AirtableService(mockApiKey, 'https://custom.url', mockFetch as any);
const customService = new AirtableService(mockApiKey, 'https://custom.url', mockFetch as typeof nodeFetch);
expect(customService).toBeInstanceOf(AirtableService);
});
});
Expand All @@ -35,26 +37,26 @@ describe('AirtableService', () => {
describe('listBases', () => {
const mockResponse = {
bases: [
{ id: 'base1', name: 'Base 1', permissionLevel: 'create' }
]
{ id: 'base1', name: 'Base 1', permissionLevel: 'create' },
],
};

test('fetches bases list successfully', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
text: () => Promise.resolve(JSON.stringify(mockResponse))
text: () => Promise.resolve(JSON.stringify(mockResponse)),
});

const result = await service.listBases();

expect(mockFetch).toHaveBeenCalledWith(
`${mockBaseUrl}/v0/meta/bases`,
expect.objectContaining({
headers: expect.objectContaining({
'Authorization': `Bearer ${mockApiKey}`,
'Accept': 'application/json'
})
})
Authorization: `Bearer ${mockApiKey}`,
Accept: 'application/json',
}),
}),
);
expect(result).toEqual(mockResponse);
});
Expand All @@ -72,35 +74,35 @@ describe('AirtableService', () => {
{
id: 'fld1',
name: 'Name',
type: 'singleLineText'
}
type: 'singleLineText',
},
],
views: [
{
id: 'viw1',
name: 'Grid view',
type: 'grid'
}
]
}
]
type: 'grid',
},
],
},
],
};

test('fetches base schema successfully', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
text: () => Promise.resolve(JSON.stringify(mockResponse))
text: () => Promise.resolve(JSON.stringify(mockResponse)),
});

const result = await service.getBaseSchema(mockBaseId);

expect(mockFetch).toHaveBeenCalledWith(
`${mockBaseUrl}/v0/meta/bases/${mockBaseId}/tables`,
expect.objectContaining({
headers: expect.objectContaining({
'Authorization': `Bearer ${mockApiKey}`
})
})
Authorization: `Bearer ${mockApiKey}`,
}),
}),
);
expect(result).toEqual(mockResponse);
});
Expand All @@ -111,36 +113,36 @@ describe('AirtableService', () => {
const mockTableId = 'table123';
const mockResponse = {
records: [
{ id: 'rec1', fields: { name: 'Test' } }
]
{ id: 'rec1', fields: { name: 'Test' } },
],
};

test('lists records successfully', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
text: () => Promise.resolve(JSON.stringify(mockResponse))
text: () => Promise.resolve(JSON.stringify(mockResponse)),
});

const result = await service.listRecords(mockBaseId, mockTableId);

expect(mockFetch).toHaveBeenCalledWith(
`${mockBaseUrl}/v0/${mockBaseId}/${mockTableId}`,
expect.any(Object)
expect.any(Object),
);
expect(result).toEqual(mockResponse.records);
});

test('handles maxRecords option', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
text: () => Promise.resolve(JSON.stringify(mockResponse))
text: () => Promise.resolve(JSON.stringify(mockResponse)),
});

await service.listRecords(mockBaseId, mockTableId, { maxRecords: 100 });

expect(mockFetch).toHaveBeenCalledWith(
`${mockBaseUrl}/v0/${mockBaseId}/${mockTableId}?maxRecords=100`,
expect.any(Object)
expect.any(Object),
);
});
});
Expand All @@ -151,7 +153,7 @@ describe('AirtableService', () => {
mockFetch.mockResolvedValueOnce({
ok: false,
statusText: errorMessage,
text: () => Promise.resolve('Error response')
text: () => Promise.resolve('Error response'),
});

await expect(service.listBases()).rejects.toThrow('Airtable API Error');
Expand All @@ -160,7 +162,7 @@ describe('AirtableService', () => {
test('handles JSON parse errors', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
text: () => Promise.resolve('invalid json')
text: () => Promise.resolve('invalid json'),
});

await expect(service.listBases()).rejects.toThrow('Failed to parse API response');
Expand All @@ -169,7 +171,7 @@ describe('AirtableService', () => {
test('handles schema validation errors', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
text: () => Promise.resolve('{"invalidData": true}')
text: () => Promise.resolve('{"invalidData": true}'),
});

await expect(service.listBases()).rejects.toThrow();
Expand All @@ -185,59 +187,59 @@ describe('AirtableService', () => {
const mockRecord = { id: mockRecordId, fields: { name: 'Test' } };
mockFetch.mockResolvedValueOnce({
ok: true,
text: () => Promise.resolve(JSON.stringify(mockRecord))
text: () => Promise.resolve(JSON.stringify(mockRecord)),
});

const result = await service.createRecord(mockBaseId, mockTableId, { name: 'Test' });

expect(mockFetch).toHaveBeenCalledWith(
`${mockBaseUrl}/v0/${mockBaseId}/${mockTableId}`,
expect.objectContaining({
method: 'POST',
body: expect.any(String)
})
body: expect.any(String),
}),
);
expect(result).toEqual(mockRecord);
});

test('updates records successfully', async () => {
const mockResponse = {
records: [{ id: mockRecordId, fields: { name: 'Updated' } }]
records: [{ id: mockRecordId, fields: { name: 'Updated' } }],
};
mockFetch.mockResolvedValueOnce({
ok: true,
text: () => Promise.resolve(JSON.stringify(mockResponse))
text: () => Promise.resolve(JSON.stringify(mockResponse)),
});

const records = [{ id: mockRecordId, fields: { name: 'Updated' } }];
const result = await service.updateRecords(mockBaseId, mockTableId, records);

expect(mockFetch).toHaveBeenCalledWith(
`${mockBaseUrl}/v0/${mockBaseId}/${mockTableId}`,
expect.objectContaining({
method: 'PATCH',
body: expect.any(String)
})
body: expect.any(String),
}),
);
expect(result).toEqual(mockResponse.records);
});

test('deletes records successfully', async () => {
const mockResponse = {
records: [{ id: mockRecordId, deleted: true }]
records: [{ id: mockRecordId, deleted: true }],
};
mockFetch.mockResolvedValueOnce({
ok: true,
text: () => Promise.resolve(JSON.stringify(mockResponse))
text: () => Promise.resolve(JSON.stringify(mockResponse)),
});

const result = await service.deleteRecords(mockBaseId, mockTableId, [mockRecordId]);

expect(mockFetch).toHaveBeenCalledWith(
expect.stringContaining(`${mockBaseUrl}/v0/${mockBaseId}/${mockTableId}?records[]=${mockRecordId}`),
expect.objectContaining({
method: 'DELETE'
})
method: 'DELETE',
}),
);
expect(result).toEqual([{ id: mockRecordId }]);
});
Expand Down
Loading

0 comments on commit 5c89294

Please sign in to comment.