const { createStore, Store, extractBrands } = require('../models/Store'); describe('Store model', () => { it('uses store_number from data when no explicit number given', () => { const s = createStore({ store_number: '305', name: 'Foo' }); expect(s.number).toBe('305'); expect(s.name).toBe('Foo'); }); it('falls back to `Store ` when name is missing', () => { const s = createStore({}, 42); expect(s.name).toBe('Store 42'); }); it('handles missing address fields without throwing', () => { const s = createStore({}, 1); expect(() => s.toSummary()).not.toThrow(); const summary = s.toSummary(); expect(summary).toContain('Store 1'); expect(summary).toContain('District ID: N/A'); }); it('handles null location data without throwing (regression: store 2477)', () => { const s = createStore(null, 2477); expect(s.hasLocationData).toBe(false); expect(s.name).toBe('Store 2477'); const summary = s.toSummary(); expect(summary).toContain('Store 2477'); expect(summary).toContain('No SIW record found'); }); it('handles undefined location data without throwing', () => { const s = createStore(undefined, 305); expect(s.hasLocationData).toBe(false); expect(() => s.toSummary()).not.toThrow(); }); it('builds a full address from optional parts', () => { const s = new Store( { address: '123 Main', address2: 'Suite 5', city: 'Anytown', state: 'CA', postal_code: '90210', phone: '555-1234', }, '305' ); const addr = s.fullAddress; expect(addr).toContain('123 Main'); expect(addr).toContain('Suite 5'); expect(addr).toContain('Anytown, CA 90210'); expect(addr).toContain('Phone: 555-1234'); }); it('summary ends with a blank line so the section splitter works', () => { const s = createStore({ name: 'Foo' }, '305'); // The Meraki section starts with `\n\n**🌐...`. Combined with toSummary's // trailing newline this gives a clean \n\n** boundary. expect(s.toSummary()).toMatch(/\n$/); }); }); describe('extractBrands', () => { it('returns [] for null / missing data', () => { expect(extractBrands(null)).toEqual([]); expect(extractBrands({})).toEqual([]); }); it('reads an array of plain strings', () => { expect(extractBrands({ brands: ['AEO', 'Aerie', 'Offline'] })).toEqual([ 'AEO', 'Aerie', 'Offline', ]); }); it('reads an array of objects with brand_display_name', () => { expect( extractBrands({ brands: [{ brand_display_name: 'AEO' }, { brand_name: 'Aerie' }, { name: 'Offline' }], }) ).toEqual(['AEO', 'Aerie', 'Offline']); }); it('reads numbered brand_1..brand_3 fields', () => { expect(extractBrands({ brand_1: 'AEO', brand_2: 'Aerie', brand_3: 'Offline' })).toEqual([ 'AEO', 'Aerie', 'Offline', ]); }); it('reads brand_display_name_1..3 fields', () => { expect( extractBrands({ brand_display_name_1: 'AEO', brand_display_name_2: 'Aerie', }) ).toEqual(['AEO', 'Aerie']); }); it('falls back to a single brand field', () => { expect(extractBrands({ brand_display_name: 'AEO' })).toEqual(['AEO']); expect(extractBrands({ brand: 'AEO' })).toEqual(['AEO']); }); it('deduplicates case-insensitively and caps at 3', () => { expect( extractBrands({ brands: ['AEO', 'aeo', 'Aerie', 'Offline', 'Todd Snyder', 'Unsubsidiary'] }) ).toEqual(['AEO', 'Aerie', 'Offline']); }); it('Store.brands is populated and rendered in the summary', () => { const s = createStore( { name: 'Mall Store', brand_1: 'AEO', brand_2: 'Aerie', address: '1 Main' }, '2477' ); expect(s.brands).toEqual(['AEO', 'Aerie']); const summary = s.toSummary(); expect(summary).toContain('Brands: AEO, Aerie'); }); it('uses singular "Brand:" label when only one brand is present', () => { const s = createStore({ name: 'X', brand: 'AEO' }, '1'); expect(s.toSummary()).toContain('Brand: AEO'); }); it('reads brands from the real SIW /StoreGeneral shape (incl. `pimary` typo)', () => { const general = { pimary_brand_name: 'American Eagle Outfitters', secondary_brand_name: 'Aerie', tertiary_brand_name: 'Offline', }; expect(extractBrands(general)).toEqual(['American Eagle Outfitters', 'Aerie', 'Offline']); }); it('also reads brands from the spelled-correctly `primary_brand_name` form', () => { const general = { primary_brand_name: 'AEO', secondary_brand_name: 'Aerie', }; expect(extractBrands(general)).toEqual(['AEO', 'Aerie']); }); it('dedupes when primary and tertiary are the same brand (real store 782 case)', () => { const general = { pimary_brand_name: 'American Eagle Outfitters', secondary_brand_name: null, tertiary_brand_name: 'American Eagle Outfitters', }; expect(extractBrands(general)).toEqual(['American Eagle Outfitters']); }); }); describe('Store with /StoreGeneral data', () => { const location = { name: 'AEO #782', address: '1 Mall Way', city: 'Pittsburgh', state: 'PA', postal_code: '15222', }; const general = { store_number: 782, brand_code: 'AE', pimary_brand_name: 'American Eagle Outfitters', secondary_brand_name: null, tertiary_brand_name: 'American Eagle Outfitters', environment_name: 'Prd', store_status_name: 'Live', }; it('exposes brands, status, and environment from the general payload', () => { const s = createStore(location, 782, { general }); expect(s.brands).toEqual(['American Eagle Outfitters']); expect(s.status).toBe('Live'); expect(s.environment).toBe('Prd'); expect(s.hasGeneralData).toBe(true); }); it('renders Status and Environment on a single line in the summary', () => { const s = createStore(location, 782, { general }); const summary = s.toSummary(); expect(summary).toContain('Brand: American Eagle Outfitters'); expect(summary).toMatch(/Status: Live\s+\|\s+Environment: Prd/); }); it('skips the status/env line when both are missing', () => { const s = createStore(location, 782, { general: {} }); const summary = s.toSummary(); expect(summary).not.toContain('Status:'); expect(summary).not.toContain('Environment:'); }); it('still renders when only general data is available (no location)', () => { const s = createStore(null, 782, { general }); expect(s.hasLocationData).toBe(false); expect(s.hasGeneralData).toBe(true); const summary = s.toSummary(); expect(summary).toContain('Store 782'); expect(summary).toContain('Brand: American Eagle Outfitters'); expect(summary).toContain('Status: Live'); }); });