common-allergies-js
Version:
An NPM package to import common allergies in a JavaScript application
574 lines (480 loc) • 23.6 kB
JavaScript
const assert = require('assert');
const {
getAllergies,
getAllergiesByType,
getEnvironmentalAllergies,
getFoodAllergies,
getInsectAllergies,
getMedicationAllergies,
getOtherAllergies,
getAllergiesBySymptom,
getAllergiesByCategory,
getAllergiesByCrossReactivity,
getAllergyById,
filterAllergies,
advancedSearch,
// New name-only functions
getAllergyNames,
getAllAllergyNames,
getFoodAllergyNames,
getEnvironmentalAllergyNames,
getInsectAllergyNames,
getMedicationAllergyNames,
getOtherAllergyNames,
getAllergyNamesByType
} = require('../index');
describe('Allergies Module', () => {
it('should return a list of all allergies', () => {
const result = getAllergies();
assert(Array.isArray(result), 'Result should be an array');
assert(result.length > 0, 'Result should not be empty');
});
it('should filter allergies by type correctly', () => {
const environmentalType = getAllergiesByType('Environmental');
assert(Array.isArray(environmentalType), 'Environmental allergies should be an array');
assert(environmentalType.every(item => item.type === 'Environmental'),
'All items should be of Environmental type');
const foodType = getAllergiesByType('Food');
assert(Array.isArray(foodType), 'Food allergies should be an array');
assert(foodType.every(item => item.type === 'Food'),
'All items should be of Food type');
});
it('should return specific allergy categories', () => {
// Test environmental allergies
const environmental = getEnvironmentalAllergies();
assert(Array.isArray(environmental), 'Environmental allergies should be an array');
assert(environmental.length > 0, 'Environmental allergies should not be empty');
// Test food allergies
const food = getFoodAllergies();
assert(Array.isArray(food), 'Food allergies should be an array');
assert(food.length > 0, 'Food allergies should not be empty');
// Test insect allergies
const insect = getInsectAllergies();
assert(Array.isArray(insect), 'Insect allergies should be an array');
// Test medication allergies
const medication = getMedicationAllergies();
assert(Array.isArray(medication), 'Medication allergies should be an array');
// Test other allergies
const other = getOtherAllergies();
assert(Array.isArray(other), 'Other allergies should be an array');
});
it('should have the expected structure for allergy objects', () => {
const allergies = getAllergies();
const sampleAllergy = allergies[0];
// Check required properties exist
assert(sampleAllergy.hasOwnProperty('id'), 'Allergy should have an id');
assert(sampleAllergy.hasOwnProperty('name'), 'Allergy should have a name');
assert(sampleAllergy.hasOwnProperty('type'), 'Allergy should have a type');
assert(sampleAllergy.hasOwnProperty('commonSymptoms'), 'Allergy should have common symptoms');
assert(Array.isArray(sampleAllergy.commonSymptoms), 'Common symptoms should be an array');
});
// Tests for new filtering functions
it('should filter allergies by symptom', () => {
// Case-insensitive by default
const hivesAllergies = getAllergiesBySymptom('hives');
assert(Array.isArray(hivesAllergies), 'Hives allergies should be an array');
assert(hivesAllergies.length > 0, 'Should find allergies with hives symptom');
assert(hivesAllergies.every(allergy =>
allergy.commonSymptoms.some(symptom =>
symptom.toLowerCase().includes('hives')
)
), 'All allergies should include hives in symptoms');
// Test case sensitivity
const caseSensitiveHives = getAllergiesBySymptom('Hives', true);
assert(caseSensitiveHives.every(allergy =>
allergy.commonSymptoms.some(symptom =>
symptom.includes('Hives')
)
), 'Case sensitive search should only match exact case');
});
it('should filter allergies by category', () => {
const legumeAllergies = getAllergiesByCategory('Legume');
assert(Array.isArray(legumeAllergies), 'Legume allergies should be an array');
assert(legumeAllergies.every(allergy => allergy.category === 'Legume'),
'All allergies should be in Legume category');
});
it('should filter allergies by cross-reactivity', () => {
const peanutCross = getAllergiesByCrossReactivity('peanut');
assert(Array.isArray(peanutCross), 'Cross-reactive allergies should be an array');
assert(peanutCross.every(allergy =>
allergy.crossReactivity.some(item =>
item.toLowerCase().includes('peanut')
)
), 'All allergies should have peanut cross-reactivity');
});
it('should find an allergy by ID', () => {
// Get a known ID from the first allergy
const firstAllergy = getAllergies()[0];
const id = firstAllergy.id;
const foundAllergy = getAllergyById(id);
assert(foundAllergy !== null, 'Should find an allergy with the ID');
assert(foundAllergy.id === id, 'Found allergy should have matching ID');
// Test with unknown ID
const unknownAllergy = getAllergyById('unknown-id-999');
assert(unknownAllergy === null, 'Should return null for unknown ID');
});
// Tests for advanced filtering capabilities
describe('Advanced filtering', () => {
it('should filter allergies by multiple criteria with AND logic', () => {
// Find food allergies that cause hives
const foodAndHives = filterAllergies({
type: 'Food',
symptom: 'hives'
});
assert(Array.isArray(foodAndHives), 'Result should be an array');
assert(foodAndHives.every(allergy => allergy.type === 'Food'),
'All allergies should be of type Food');
assert(foodAndHives.every(allergy =>
allergy.commonSymptoms.some(symptom =>
symptom.toLowerCase().includes('hives')
)
), 'All allergies should have hives in symptoms');
});
it('should filter allergies by multiple criteria with OR logic', () => {
// Find allergies that are either food type OR cause hives
const foodOrHives = filterAllergies({
type: 'Food',
symptom: 'hives',
logicOperator: 'OR'
});
assert(Array.isArray(foodOrHives), 'Result should be an array');
assert(foodOrHives.length > 0, 'Should find some allergies');
// Every allergy should either be Food type OR have hives symptom
const allMatch = foodOrHives.every(allergy =>
allergy.type === 'Food' ||
allergy.commonSymptoms.some(symptom =>
symptom.toLowerCase().includes('hives')
)
);
assert(allMatch, 'All allergies should either be Food type OR contain hives symptom');
});
it('should filter by treatment content', () => {
const avoidanceAllergies = filterAllergies({
treatmentContains: 'avoidance'
});
assert(Array.isArray(avoidanceAllergies), 'Result should be an array');
assert(avoidanceAllergies.every(allergy =>
allergy.treatment.toLowerCase().includes('avoidance')
), 'All allergies should mention avoidance in treatment');
});
it('should filter by allergy name', () => {
const nutAllergies = filterAllergies({
nameContains: 'nut'
});
assert(Array.isArray(nutAllergies), 'Result should be an array');
assert(nutAllergies.every(allergy =>
allergy.name.toLowerCase().includes('nut')
), 'All allergies should include "nut" in their name');
});
it('should work with case-sensitive filtering', () => {
// Case-sensitive search for "Hives" (capital H)
const caseSensitiveAllergies = filterAllergies({
symptom: 'Hives',
caseSensitive: true
});
// Case-insensitive search
const caseInsensitiveAllergies = filterAllergies({
symptom: 'Hives',
caseSensitive: false
});
// Sensitive search should return fewer results than insensitive search
assert(caseSensitiveAllergies.length <= caseInsensitiveAllergies.length,
'Case-sensitive search should return fewer or equal results');
});
it('should support custom filter functions with advancedSearch', () => {
// Create custom filters
const isEnvironmental = allergy => allergy.type === 'Environmental';
const causesItching = allergy =>
allergy.commonSymptoms.some(s =>
s.toLowerCase().includes('itch')
);
// Find environmental allergies that cause itching using AND logic
const result = advancedSearch([isEnvironmental, causesItching]);
assert(Array.isArray(result), 'Result should be an array');
assert(result.every(isEnvironmental), 'All allergies should be environmental');
assert(result.every(causesItching), 'All allergies should cause itching');
});
it('should support OR logic with advancedSearch', () => {
// Create custom filters
const isFood = allergy => allergy.type === 'Food';
const isInsect = allergy => allergy.type === 'Insect';
// Find allergies that are either food OR insect type
const result = advancedSearch([isFood, isInsect], 'OR');
assert(Array.isArray(result), 'Result should be an array');
assert(result.every(allergy => allergy.type === 'Food' || allergy.type === 'Insect'),
'All allergies should be either Food or Insect type');
});
});
// Tests for the new allergy name functions
describe('Allergy name functions', () => {
it('should extract names from an array of allergies', () => {
const allergies = getAllergies().slice(0, 3); // Get first 3 allergies
const names = getAllergyNames(allergies);
assert(Array.isArray(names), 'Result should be an array');
assert.strictEqual(names.length, 3, 'Should have 3 names');
assert(names.every(name => typeof name === 'string'), 'All items should be strings');
// Check that names match the original allergies
allergies.forEach((allergy, index) => {
assert.strictEqual(names[index], allergy.name, 'Name should match the original allergy');
});
});
it('should return all allergy names', () => {
const allNames = getAllAllergyNames();
const allAllergies = getAllergies();
assert(Array.isArray(allNames), 'Result should be an array');
assert.strictEqual(allNames.length, allAllergies.length, 'Should have same length as all allergies');
});
it('should return food allergy names', () => {
const foodNames = getFoodAllergyNames();
const foodAllergies = getFoodAllergies();
assert(Array.isArray(foodNames), 'Result should be an array');
assert.strictEqual(foodNames.length, foodAllergies.length, 'Should have same length as food allergies');
// Verify if the returned names are indeed food allergies
const allFoodNames = foodAllergies.map(allergy => allergy.name);
assert(foodNames.every(name => allFoodNames.includes(name)),
'All names should be food allergy names');
});
it('should return environmental allergy names', () => {
const envNames = getEnvironmentalAllergyNames();
const envAllergies = getEnvironmentalAllergies();
assert(Array.isArray(envNames), 'Result should be an array');
assert.strictEqual(envNames.length, envAllergies.length,
'Should have same length as environmental allergies');
});
it('should return allergy names by type', () => {
const foodNamesViaType = getAllergyNamesByType('Food');
const foodNames = getFoodAllergyNames();
assert(Array.isArray(foodNamesViaType), 'Result should be an array');
assert.strictEqual(foodNamesViaType.length, foodNames.length,
'Should match direct call to getFoodAllergyNames');
// Check the two arrays have the same content
const sortedDirect = [...foodNames].sort();
const sortedViaType = [...foodNamesViaType].sort();
assert.deepStrictEqual(sortedViaType, sortedDirect,
'Arrays should have the same content');
});
});
describe('Error handling and edge cases', () => {
it('should handle invalid allergy type', () => {
const invalidType = getAllergiesByType('InvalidType');
assert(Array.isArray(invalidType), 'Should return empty array for invalid type');
assert.strictEqual(invalidType.length, 0, 'Should return empty array for invalid type');
});
it('should handle null/undefined inputs', () => {
const nullResult = getAllergiesByType(null);
const undefinedResult = getAllergiesByType(undefined);
assert(Array.isArray(nullResult), 'Should handle null input');
assert(Array.isArray(undefinedResult), 'Should handle undefined input');
assert.strictEqual(nullResult.length, 0, 'Should return empty array for null');
assert.strictEqual(undefinedResult.length, 0, 'Should return empty array for undefined');
});
it('should handle empty symptom search', () => {
const emptySymptom = getAllergiesBySymptom('');
assert(Array.isArray(emptySymptom), 'Should return empty array for empty symptom');
assert.strictEqual(emptySymptom.length, 0, 'Should return empty array for empty symptom');
});
});
describe('Additional name function tests', () => {
it('should return insect allergy names', () => {
const insectNames = getInsectAllergyNames();
const insectAllergies = getInsectAllergies();
assert(Array.isArray(insectNames), 'Result should be an array');
assert.strictEqual(insectNames.length, insectAllergies.length, 'Should have same length as insect allergies');
assert(insectNames.every(name => typeof name === 'string'), 'All items should be strings');
});
it('should return medication allergy names', () => {
const medNames = getMedicationAllergyNames();
const medAllergies = getMedicationAllergies();
assert(Array.isArray(medNames), 'Result should be an array');
assert.strictEqual(medNames.length, medAllergies.length, 'Should have same length as medication allergies');
assert(medNames.every(name => typeof name === 'string'), 'All items should be strings');
});
it('should return other allergy names', () => {
const otherNames = getOtherAllergyNames();
const otherAllergies = getOtherAllergies();
assert(Array.isArray(otherNames), 'Result should be an array');
assert.strictEqual(otherNames.length, otherAllergies.length, 'Should have same length as other allergies');
});
it('should handle invalid inputs in name functions', () => {
const invalidNames = getAllergyNames(null);
const undefinedNames = getAllergyNames(undefined);
const emptyNames = getAllergyNames([]);
assert(Array.isArray(invalidNames), 'Should handle null input');
assert(Array.isArray(undefinedNames), 'Should handle undefined input');
assert(Array.isArray(emptyNames), 'Should handle empty array');
assert.strictEqual(invalidNames.length, 0, 'Should return empty array for null');
assert.strictEqual(undefinedNames.length, 0, 'Should return empty array for undefined');
assert.strictEqual(emptyNames.length, 0, 'Should return empty array for empty input');
});
});
describe('Advanced filter edge cases', () => {
it('should handle empty filter criteria', () => {
const result = filterAllergies({});
const allAllergies = getAllergies();
assert(Array.isArray(result), 'Result should be an array');
assert.strictEqual(result.length, allAllergies.length, 'Should return all allergies when no criteria');
});
it('should handle non-existent symptom', () => {
const result = filterAllergies({ symptom: 'nonexistentsymptom123' });
assert(Array.isArray(result), 'Result should be an array');
assert.strictEqual(result.length, 0, 'Should return empty array for non-existent symptom');
});
it('should handle multiple invalid criteria', () => {
const result = filterAllergies({
type: 'InvalidType',
symptom: 'InvalidSymptom',
category: 'InvalidCategory'
});
assert(Array.isArray(result), 'Result should be an array');
assert.strictEqual(result.length, 0, 'Should return empty array for all invalid criteria');
});
});
describe('Cross-reactivity detailed tests', () => {
it('should handle case sensitivity in cross-reactivity search', () => {
const caseSensitive = getAllergiesByCrossReactivity('Peanut', true);
const caseInsensitive = getAllergiesByCrossReactivity('peanut', false);
assert(Array.isArray(caseSensitive), 'Case sensitive result should be array');
assert(Array.isArray(caseInsensitive), 'Case insensitive result should be array');
assert(caseInsensitive.length >= caseSensitive.length, 'Case insensitive should return >= results');
});
it('should handle multiple cross-reactivity patterns', () => {
const multiPattern = getAllergies().filter(allergy =>
allergy.crossReactivity && allergy.crossReactivity.length > 1
);
assert(Array.isArray(multiPattern), 'Result should be array');
assert(multiPattern.every(allergy => allergy.crossReactivity.length > 1),
'Should only include allergies with multiple cross-reactivities');
});
});
describe('Data Validation Tests', () => {
it('should validate allergy ID format', () => {
const allergies = getAllergies();
allergies.forEach(allergy => {
assert(allergy.id.includes('-'), 'ID should contain a hyphen');
assert(/^[a-zA-Z0-9-]+$/.test(allergy.id), 'ID should only contain letters, numbers, and hyphens');
assert(allergy.id.split('-').length >= 2, 'ID should have at least two parts separated by hyphens');
});
});
it('should ensure no duplicate IDs exist', () => {
const allergies = getAllergies();
const ids = allergies.map(a => a.id);
const uniqueIds = new Set(ids);
assert.strictEqual(ids.length, uniqueIds.size, 'Should have no duplicate IDs');
});
it('should validate cross-reactivity data', () => {
const allergies = getAllergies();
allergies.forEach(allergy => {
if (allergy.crossReactivity) {
assert(Array.isArray(allergy.crossReactivity), 'Cross-reactivity should be an array');
allergy.crossReactivity.forEach(item => {
assert(typeof item === 'string', 'Cross-reactivity items should be strings');
assert(item.length > 0, 'Cross-reactivity items should not be empty');
});
}
});
});
});
describe('Performance Tests', () => {
it('should handle large dataset filtering efficiently', () => {
const start = process.hrtime();
const result = filterAllergies({
symptom: 'rash',
type: 'Food',
treatmentContains: 'avoidance'
});
const [seconds, nanoseconds] = process.hrtime(start);
assert(seconds === 0 && nanoseconds < 50000000, 'Should complete filtering in under 50ms');
});
it('should efficiently search cross-reactivity patterns', () => {
const start = process.hrtime();
getAllergiesByCrossReactivity('peanut');
const [seconds, nanoseconds] = process.hrtime(start);
assert(seconds === 0 && nanoseconds < 10000000, 'Should complete cross-reactivity search in under 10ms');
});
});
describe('Data Integrity Tests', () => {
it('should validate required fields across all allergy types', () => {
const allergies = getAllergies();
const requiredFields = ['id', 'name', 'type', 'commonSymptoms', 'medicalName', 'treatment'];
allergies.forEach(allergy => {
requiredFields.forEach(field => {
assert(allergy.hasOwnProperty(field), `Allergy ${allergy.id} missing required field: ${field}`);
assert(allergy[field] !== undefined, `Required field ${field} should not be undefined`);
assert(allergy[field] !== null, `Required field ${field} should not be null`);
assert(allergy[field] !== '', `Required field ${field} should not be empty`);
});
});
});
it('should validate treatment patterns', () => {
const allergies = getAllergies();
allergies.forEach(allergy => {
assert(typeof allergy.treatment === 'string', 'Treatment should be a string');
assert(allergy.treatment.length >= 5, 'Treatment description should be meaningful');
});
});
it('should validate prevalence data format', () => {
const allergies = getAllergies();
allergies.forEach(allergy => {
assert(typeof allergy.prevalence === 'object', 'Prevalence should be an object');
Object.entries(allergy.prevalence).forEach(([key, value]) => {
assert(typeof key === 'string', 'Prevalence key should be a string');
assert(typeof value === 'string', 'Prevalence value should be a string');
assert(key.length > 0, 'Prevalence key should not be empty');
assert(value.length > 0, 'Prevalence value should not be empty');
});
});
});
it('should validate medical names', () => {
const allergies = getAllergies();
allergies.forEach(allergy => {
assert(typeof allergy.medicalName === 'string', 'Medical name should be a string');
assert(allergy.medicalName.length > 0, 'Medical name should not be empty');
});
});
});
describe('Type-specific Data Tests', () => {
it('should validate food allergy specific fields', () => {
const foodAllergies = getFoodAllergies();
foodAllergies.forEach(allergy => {
if (allergy.avoidFoods) {
assert(Array.isArray(allergy.avoidFoods), 'avoidFoods should be an array');
assert(allergy.avoidFoods.every(food => typeof food === 'string'),
'avoidFoods items should be strings');
}
});
});
it('should validate medication allergy specific fields', () => {
const medAllergies = getMedicationAllergies();
medAllergies.forEach(allergy => {
assert(allergy.category, 'Medication allergies should have a category');
assert(typeof allergy.category === 'string', 'Category should be a string');
});
});
});
describe('Search Performance Tests', () => {
it('should efficiently filter by multiple criteria', () => {
const start = process.hrtime();
const result = filterAllergies({
type: 'Food',
symptom: 'hives',
treatmentContains: 'avoidance',
category: 'Legume'
});
const [seconds, nanoseconds] = process.hrtime(start);
assert(seconds === 0 && nanoseconds < 100000000,
'Complex filtering should complete in under 100ms');
});
it('should handle large AND/OR operations efficiently', () => {
const start = process.hrtime();
const result = filterAllergies({
type: 'Food',
symptom: 'anaphylaxis',
category: 'Legume',
logicOperator: 'OR'
});
const [seconds, nanoseconds] = process.hrtime(start);
assert(seconds === 0 && nanoseconds < 100000000,
'OR operations should complete in under 100ms');
});
});
});