/**
* Tests for get_company tool
*
* Tests single record retrieval by ID with full attribute handling.
*/
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { handleGetCompany } from '../../../src/tools/get-company.js';
import { createMockAttioClient } from '../../helpers/mock-attio-client.js';
import { loadFixture } from '../../helpers/fixtures.js';
import * as attioClientModule from '../../../src/attio-client.js';
vi.mock('../../../src/attio-client.js', () => ({
createAttioClient: vi.fn(),
}));
describe('get_company', () => {
let mockClient: ReturnType<typeof createMockAttioClient>;
let originalApiKey: string | undefined;
beforeEach(() => {
originalApiKey = process.env.ATTIO_API_KEY;
process.env.ATTIO_API_KEY = 'test-api-key';
mockClient = createMockAttioClient();
vi.mocked(attioClientModule.createAttioClient).mockReturnValue(
mockClient as any
);
});
afterEach(() => {
if (originalApiKey) {
process.env.ATTIO_API_KEY = originalApiKey;
} else {
delete process.env.ATTIO_API_KEY;
}
mockClient.reset();
});
describe('Successful retrieval', () => {
it('should get company by record_id', async () => {
const companyData = loadFixture('companies.json', 'acme-corp');
mockClient.mockResponse(
'GET',
'/objects/companies/records/company-acme-123',
{
data: { data: companyData },
}
);
const result = await handleGetCompany({
record_id: 'company-acme-123',
});
const parsed = JSON.parse(result.content[0].text);
expect(parsed.success).toBe(true);
expect(parsed.data.record_id).toBe('company-acme-123');
expect(parsed.data.name).toBe('Acme Corporation');
});
it('should include all standard fields', async () => {
const companyData = loadFixture('companies.json', 'acme-corp');
mockClient.mockResponse(
'GET',
'/objects/companies/records/company-acme-123',
{
data: { data: companyData },
}
);
const result = await handleGetCompany({
record_id: 'company-acme-123',
});
const parsed = JSON.parse(result.content[0].text);
expect(parsed.data).toMatchObject({
record_id: 'company-acme-123',
workspace_id: 'workspace-123',
object_id: 'companies',
name: 'Acme Corporation',
domains: ['acme.com'],
description: 'Enterprise software company specializing in workflow automation',
});
});
it('should include all_attributes with raw data', async () => {
const companyData = loadFixture('companies.json', 'acme-corp');
mockClient.mockResponse(
'GET',
'/objects/companies/records/company-acme-123',
{
data: { data: companyData },
}
);
const result = await handleGetCompany({
record_id: 'company-acme-123',
});
const parsed = JSON.parse(result.content[0].text);
expect(parsed.data.all_attributes).toBeDefined();
expect(parsed.data.all_attributes.name).toBeDefined();
expect(parsed.data.all_attributes.domains).toBeDefined();
});
it('should handle company with minimal data', async () => {
const minimalCompany = loadFixture('companies.json', 'minimal-company');
mockClient.mockResponse(
'GET',
'/objects/companies/records/company-minimal-789',
{
data: { data: minimalCompany },
}
);
const result = await handleGetCompany({
record_id: 'company-minimal-789',
});
const parsed = JSON.parse(result.content[0].text);
expect(parsed.success).toBe(true);
expect(parsed.data.name).toBe('Minimal Corp');
expect(parsed.data.domains).toEqual([]);
expect(parsed.data.description).toBeNull();
expect(parsed.data.linkedin).toBeNull();
});
it('should handle companies with multiple domains', async () => {
const mockResponse = {
data: {
id: {
workspace_id: 'ws-123',
object_id: 'companies',
record_id: 'rec-multi-123',
},
values: {
name: [{ value: 'Multi Domain Corp' }],
domains: [
{ domain: 'example.com' },
{ domain: 'example.io' },
{ domain: 'example.org' },
],
},
},
};
mockClient.mockResponse(
'GET',
'/objects/companies/records/rec-multi-123',
{
data: mockResponse,
}
);
const result = await handleGetCompany({ record_id: 'rec-multi-123' });
const parsed = JSON.parse(result.content[0].text);
expect(parsed.data.domains).toEqual([
'example.com',
'example.io',
'example.org',
]);
});
it('should use GET method with correct path', async () => {
mockClient.mockResponse(
'GET',
'/objects/companies/records/test-id',
{
data: {
data: {
id: { record_id: 'test-id' },
values: { name: [{ value: 'Test' }] },
},
},
}
);
await handleGetCompany({ record_id: 'test-id' });
const calls = mockClient.getCallsFor('GET');
expect(calls).toHaveLength(1);
expect(calls[0].path).toBe('/objects/companies/records/test-id');
});
});
describe('Validation errors', () => {
it('should fail if ATTIO_API_KEY is not configured', async () => {
delete process.env.ATTIO_API_KEY;
const result = await handleGetCompany({ record_id: 'test-id' });
const parsed = JSON.parse(result.content[0].text);
expect(parsed.success).toBe(false);
expect(parsed.error.type).toBe('validation_error');
expect(parsed.error.message).toContain('ATTIO_API_KEY');
});
it('should fail if record_id is empty string', async () => {
const result = await handleGetCompany({ record_id: '' });
const parsed = JSON.parse(result.content[0].text);
expect(parsed.success).toBe(false);
expect(parsed.error.type).toBe('validation_error');
expect(parsed.error.field).toBe('record_id');
expect(parsed.error.message).toContain('required');
});
it('should fail if record_id is only whitespace', async () => {
const result = await handleGetCompany({ record_id: ' ' });
const parsed = JSON.parse(result.content[0].text);
expect(parsed.success).toBe(false);
expect(parsed.error.field).toBe('record_id');
});
});
describe('API errors', () => {
it('should handle 404 Not Found', async () => {
const notFoundError = loadFixture('api-errors.json', 'not-found');
mockClient.mockResponse(
'GET',
'/objects/companies/records/nonexistent-id',
{
error: {
statusCode: notFoundError.error.status,
message: notFoundError.error.message,
response: { message: notFoundError.error.message },
},
}
);
const result = await handleGetCompany({ record_id: 'nonexistent-id' });
const parsed = JSON.parse(result.content[0].text);
expect(parsed.success).toBe(false);
expect(parsed.error.type).toBe('not_found_error');
expect(parsed.error.http_status).toBe(404);
expect(parsed.error.suggestions).toContain('Verify the record_id is correct');
});
it('should handle authentication errors', async () => {
const authError = loadFixture('api-errors.json', 'authentication');
mockClient.mockResponse(
'GET',
'/objects/companies/records/test-id',
{
error: {
statusCode: authError.error.status,
message: authError.error.message,
},
}
);
const result = await handleGetCompany({ record_id: 'test-id' });
const parsed = JSON.parse(result.content[0].text);
expect(parsed.success).toBe(false);
expect(parsed.error.type).toBe('authentication_error');
});
it('should handle permission errors', async () => {
const permError = loadFixture('api-errors.json', 'authorization');
mockClient.mockResponse(
'GET',
'/objects/companies/records/test-id',
{
error: {
statusCode: permError.error.status,
message: permError.error.message,
},
}
);
const result = await handleGetCompany({ record_id: 'test-id' });
const parsed = JSON.parse(result.content[0].text);
expect(parsed.success).toBe(false);
expect(parsed.error.type).toBe('permission_error');
});
it('should handle server errors with retryable flag', async () => {
const serverError = loadFixture('api-errors.json', 'server-error');
mockClient.mockResponse(
'GET',
'/objects/companies/records/test-id',
{
error: {
statusCode: serverError.error.status,
message: serverError.error.message,
},
}
);
const result = await handleGetCompany({ record_id: 'test-id' });
const parsed = JSON.parse(result.content[0].text);
expect(parsed.success).toBe(false);
expect(parsed.error.type).toBe('server_error');
expect(parsed.error.retryable).toBe(true);
});
it('should include helpful suggestions for errors', async () => {
mockClient.mockResponse(
'GET',
'/objects/companies/records/test-id',
{
error: {
statusCode: 404,
message: 'Not found',
},
}
);
const result = await handleGetCompany({ record_id: 'test-id' });
const parsed = JSON.parse(result.content[0].text);
expect(parsed.error.suggestions).toBeDefined();
expect(Array.isArray(parsed.error.suggestions)).toBe(true);
expect(parsed.error.suggestions.length).toBeGreaterThan(0);
});
});
describe('Response transformation', () => {
it('should filter out null domain values', async () => {
const mockResponse = {
data: {
id: {
workspace_id: 'ws-123',
object_id: 'companies',
record_id: 'rec-123',
},
values: {
name: [{ value: 'Test' }],
domains: [
{ domain: 'example.com' },
{ domain: null }, // Null domain
{ domain: 'test.com' },
],
},
},
};
mockClient.mockResponse('GET', '/objects/companies/records/rec-123', {
data: mockResponse,
});
const result = await handleGetCompany({ record_id: 'rec-123' });
const parsed = JSON.parse(result.content[0].text);
// Null values should be filtered out
expect(parsed.data.domains).toEqual(['example.com', 'test.com']);
});
it('should handle missing optional fields gracefully', async () => {
const mockResponse = {
data: {
id: {
workspace_id: 'ws-123',
object_id: 'companies',
record_id: 'rec-123',
},
values: {
name: [{ value: 'Bare Minimum' }],
// No domains, description, linkedin
},
},
};
mockClient.mockResponse('GET', '/objects/companies/records/rec-123', {
data: mockResponse,
});
const result = await handleGetCompany({ record_id: 'rec-123' });
const parsed = JSON.parse(result.content[0].text);
expect(parsed.data.name).toBe('Bare Minimum');
expect(parsed.data.domains).toEqual([]);
expect(parsed.data.description).toBeNull();
expect(parsed.data.linkedin).toBeNull();
});
});
});