/**
* Census Service Tests
*
* Tests for pure domain logic functions that handle census data
*/
import { describe, it, expect } from 'vitest';
import {
parseCensusResponse,
formatCensusData,
buildStateQuery,
createSuccessResult,
createErrorResult,
validatePopulationRequest,
} from '../../src/domain/census-service.js';
import type { CensusApiResponse, CensusData, PopulationRequest } from '../../src/domain/types.js';
describe('Census Service - Domain Logic', () => {
describe('parseCensusResponse', () => {
it('should parse valid census response', () => {
const rawResponse: CensusApiResponse = [
['NAME', 'P1_001N', 'state'],
['California', '39538223', '06'],
['Texas', '29145505', '48']
];
const result = parseCensusResponse(rawResponse);
expect(result).toHaveLength(2);
expect(result[0]).toEqual({
stateName: 'California',
population: 39538223,
stateCode: '06'
});
expect(result[1]).toEqual({
stateName: 'Texas',
population: 29145505,
stateCode: '48'
});
});
it('should return empty array for empty response', () => {
const result = parseCensusResponse([]);
expect(result).toEqual([]);
});
it('should return empty array for null response', () => {
const result = parseCensusResponse(null as any);
expect(result).toEqual([]);
});
it('should throw error for missing NAME column', () => {
const invalidResponse: CensusApiResponse = [
['P1_001N', 'state'],
['39538223', '06']
];
expect(() => parseCensusResponse(invalidResponse))
.toThrow('Invalid Census API response: missing required columns');
});
it('should throw error for missing P1_001N column', () => {
const invalidResponse: CensusApiResponse = [
['NAME', 'state'],
['California', '06']
];
expect(() => parseCensusResponse(invalidResponse))
.toThrow('Invalid Census API response: missing required columns');
});
it('should throw error for missing state column', () => {
const invalidResponse: CensusApiResponse = [
['NAME', 'P1_001N'],
['California', '39538223']
];
expect(() => parseCensusResponse(invalidResponse))
.toThrow('Invalid Census API response: missing required columns');
});
it('should handle single state response', () => {
const singleResponse: CensusApiResponse = [
['NAME', 'P1_001N', 'state'],
['New York', '20201249', '36']
];
const result = parseCensusResponse(singleResponse);
expect(result).toHaveLength(1);
expect(result[0].stateName).toBe('New York');
expect(result[0].population).toBe(20201249);
});
it('should parse numeric population correctly', () => {
const response: CensusApiResponse = [
['NAME', 'P1_001N', 'state'],
['Wyoming', '576851', '56']
];
const result = parseCensusResponse(response);
expect(typeof result[0].population).toBe('number');
expect(result[0].population).toBe(576851);
});
});
describe('formatCensusData', () => {
const mockData: CensusData[] = [
{ stateName: 'California', population: 39538223, stateCode: '06' },
{ stateName: 'Texas', population: 29145505, stateCode: '48' }
];
it('should format census data with headers', () => {
const formatted = formatCensusData(mockData);
expect(formatted).toContain('Census Population Data:');
expect(formatted).toContain('State Name');
expect(formatted).toContain('Population');
expect(formatted).toContain('California');
expect(formatted).toContain('39538223');
});
it('should format empty data', () => {
const formatted = formatCensusData([]);
expect(formatted).toBe('No census data available');
});
it('should use raw response for formatting when provided', () => {
const rawResponse: CensusApiResponse = [
['NAME', 'P1_001N', 'state'],
['California', '39538223', '06'],
['Texas', '29145505', '48']
];
const formatted = formatCensusData(mockData, rawResponse);
expect(formatted).toContain('NAME');
expect(formatted).toContain('P1_001N');
expect(formatted).toContain('state');
});
it('should include separator line', () => {
const formatted = formatCensusData(mockData);
expect(formatted).toContain('---');
});
it('should format single state', () => {
const singleState: CensusData[] = [
{ stateName: 'Wyoming', population: 576851, stateCode: '56' }
];
const formatted = formatCensusData(singleState);
expect(formatted).toContain('Wyoming');
expect(formatted).toContain('576851');
expect(formatted).toContain('56');
});
});
describe('buildStateQuery', () => {
it('should return * for state code 0', () => {
const query = buildStateQuery([0]);
expect(query).toBe('*');
});
it('should return * for empty array', () => {
const query = buildStateQuery([]);
expect(query).toBe('*');
});
it('should return single state code', () => {
const query = buildStateQuery([6]);
expect(query).toBe('6');
});
it('should return comma-separated state codes', () => {
const query = buildStateQuery([6, 48, 36]);
expect(query).toBe('6,48,36');
});
it('should handle two state codes', () => {
const query = buildStateQuery([48, 36]);
expect(query).toBe('48,36');
});
it('should handle null/undefined gracefully', () => {
const query = buildStateQuery(null as any);
expect(query).toBe('*');
});
});
describe('createSuccessResult', () => {
const mockData: CensusData[] = [
{ stateName: 'California', population: 39538223, stateCode: '06' }
];
it('should create success result with data', () => {
const result = createSuccessResult(mockData, 'Formatted output');
expect(result.success).toBe(true);
expect(result.data).toEqual(mockData);
expect(result.formattedOutput).toBe('Formatted output');
});
it('should handle empty data', () => {
const result = createSuccessResult([], 'No data');
expect(result.success).toBe(true);
expect(result.data).toEqual([]);
expect(result.formattedOutput).toBe('No data');
});
it('should handle multiline formatted output', () => {
const output = 'Line 1\nLine 2\nLine 3';
const result = createSuccessResult(mockData, output);
expect(result.formattedOutput).toBe(output);
});
});
describe('createErrorResult', () => {
it('should create error result with message', () => {
const result = createErrorResult('Error message');
expect(result.success).toBe(false);
expect(result.error).toBe('Error message');
});
it('should handle different error messages', () => {
const result = createErrorResult('Test error');
expect(result.success).toBe(false);
expect(result.error).toBe('Test error');
});
});
describe('validatePopulationRequest', () => {
it('should validate request with single state', () => {
const request: PopulationRequest = { states: [6] };
const result = validatePopulationRequest(request);
expect(result.valid).toBe(true);
expect(result.error).toBeUndefined();
});
it('should validate request with multiple states', () => {
const request: PopulationRequest = { states: [6, 36, 48] };
const result = validatePopulationRequest(request);
expect(result.valid).toBe(true);
});
it('should validate request with code 0 (all states)', () => {
const request: PopulationRequest = { states: [0] };
const result = validatePopulationRequest(request);
expect(result.valid).toBe(true);
});
it('should reject empty states array', () => {
const request: PopulationRequest = { states: [] };
const result = validatePopulationRequest(request);
expect(result.valid).toBe(false);
expect(result.error).toContain('cannot be empty');
});
it('should reject missing states parameter', () => {
const request = {} as PopulationRequest;
const result = validatePopulationRequest(request);
expect(result.valid).toBe(false);
expect(result.error).toContain('must be an array');
});
it('should reject non-array states parameter', () => {
const request = { states: 'not-an-array' } as any;
const result = validatePopulationRequest(request);
expect(result.valid).toBe(false);
expect(result.error).toContain('must be an array');
});
it('should reject non-numeric state codes', () => {
const request = { states: ['06', '48'] } as any;
const result = validatePopulationRequest(request);
expect(result.valid).toBe(false);
expect(result.error).toContain('must be numbers');
});
it('should reject negative state codes', () => {
const request: PopulationRequest = { states: [-1] };
const result = validatePopulationRequest(request);
expect(result.valid).toBe(false);
expect(result.error).toContain('invalid FIPS state code');
});
it('should reject state code above 56', () => {
const request: PopulationRequest = { states: [99] };
const result = validatePopulationRequest(request);
expect(result.valid).toBe(false);
expect(result.error).toContain('invalid FIPS state code');
});
it('should validate minimum state code 1', () => {
const request: PopulationRequest = { states: [1] };
const result = validatePopulationRequest(request);
expect(result.valid).toBe(true);
});
it('should validate maximum state code 56', () => {
const request: PopulationRequest = { states: [56] };
const result = validatePopulationRequest(request);
expect(result.valid).toBe(true);
});
it('should validate common state codes', () => {
const request: PopulationRequest = { states: [6, 12, 17, 36, 48] }; // CA, FL, IL, NY, TX
const result = validatePopulationRequest(request);
expect(result.valid).toBe(true);
});
it('should identify which code is invalid', () => {
const request: PopulationRequest = { states: [6, -5, 48] };
const result = validatePopulationRequest(request);
expect(result.valid).toBe(false);
expect(result.error).toContain('-5');
});
});
});