Skip to content

Commit 6f512e2

Browse files
Tests for bonus product grouping on order summary bug
1 parent 7faf699 commit 6f512e2

File tree

1 file changed

+353
-0
lines changed
  • packages/template-retail-react-app/app/utils/bonus-product

1 file changed

+353
-0
lines changed

packages/template-retail-react-app/app/utils/bonus-product/cart.test.js

Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,4 +1639,357 @@ describe('Bonus Product Cart Utilities', () => {
16391639
expect(result[0].productId).toBe('bonus-product-1')
16401640
})
16411641
})
1642+
1643+
describe('consolidateDuplicateBonusProducts', () => {
1644+
test('returns empty array for null input', () => {
1645+
const result = cartUtils.consolidateDuplicateBonusProducts(null)
1646+
expect(result).toEqual([])
1647+
})
1648+
1649+
test('returns empty array for undefined input', () => {
1650+
const result = cartUtils.consolidateDuplicateBonusProducts(undefined)
1651+
expect(result).toEqual([])
1652+
})
1653+
1654+
test('returns empty array for empty array input', () => {
1655+
const result = cartUtils.consolidateDuplicateBonusProducts([])
1656+
expect(result).toEqual([])
1657+
})
1658+
1659+
test('returns regular products as-is when no bonus products', () => {
1660+
const productItems = [
1661+
{
1662+
productId: 'regular-product-1',
1663+
itemId: 'item-1',
1664+
quantity: 2
1665+
},
1666+
{
1667+
productId: 'regular-product-2',
1668+
itemId: 'item-2',
1669+
quantity: 1
1670+
}
1671+
]
1672+
1673+
const result = cartUtils.consolidateDuplicateBonusProducts(productItems)
1674+
1675+
expect(result).toHaveLength(2)
1676+
expect(result[0].productId).toBe('regular-product-1')
1677+
expect(result[0].quantity).toBe(2)
1678+
expect(result[1].productId).toBe('regular-product-2')
1679+
expect(result[1].quantity).toBe(1)
1680+
})
1681+
1682+
test('consolidates duplicate bonus products by productId', () => {
1683+
const productItems = [
1684+
{
1685+
productId: 'bonus-product-1',
1686+
itemId: 'bonus-item-1',
1687+
quantity: 1,
1688+
bonusProductLineItem: true,
1689+
bonusDiscountLineItemId: 'bonus-123'
1690+
},
1691+
{
1692+
productId: 'bonus-product-1',
1693+
itemId: 'bonus-item-2',
1694+
quantity: 2,
1695+
bonusProductLineItem: true,
1696+
bonusDiscountLineItemId: 'bonus-123'
1697+
},
1698+
{
1699+
productId: 'bonus-product-1',
1700+
itemId: 'bonus-item-3',
1701+
quantity: 1,
1702+
bonusProductLineItem: true,
1703+
bonusDiscountLineItemId: 'bonus-456'
1704+
}
1705+
]
1706+
1707+
const result = cartUtils.consolidateDuplicateBonusProducts(productItems)
1708+
1709+
expect(result).toHaveLength(1)
1710+
expect(result[0].productId).toBe('bonus-product-1')
1711+
expect(result[0].quantity).toBe(4) // 1 + 2 + 1
1712+
expect(result[0].bonusProductLineItem).toBe(true)
1713+
})
1714+
1715+
test('keeps different bonus products separate', () => {
1716+
const productItems = [
1717+
{
1718+
productId: 'bonus-product-1',
1719+
itemId: 'bonus-item-1',
1720+
quantity: 2,
1721+
bonusProductLineItem: true,
1722+
bonusDiscountLineItemId: 'bonus-123'
1723+
},
1724+
{
1725+
productId: 'bonus-product-2',
1726+
itemId: 'bonus-item-2',
1727+
quantity: 1,
1728+
bonusProductLineItem: true,
1729+
bonusDiscountLineItemId: 'bonus-456'
1730+
}
1731+
]
1732+
1733+
const result = cartUtils.consolidateDuplicateBonusProducts(productItems)
1734+
1735+
expect(result).toHaveLength(2)
1736+
expect(result[0].productId).toBe('bonus-product-1')
1737+
expect(result[0].quantity).toBe(2)
1738+
expect(result[1].productId).toBe('bonus-product-2')
1739+
expect(result[1].quantity).toBe(1)
1740+
})
1741+
1742+
test('preserves order: regular products first, then bonus products', () => {
1743+
const productItems = [
1744+
{
1745+
productId: 'bonus-product-1',
1746+
itemId: 'bonus-item-1',
1747+
quantity: 1,
1748+
bonusProductLineItem: true,
1749+
bonusDiscountLineItemId: 'bonus-123'
1750+
},
1751+
{
1752+
productId: 'regular-product-1',
1753+
itemId: 'regular-item-1',
1754+
quantity: 2
1755+
},
1756+
{
1757+
productId: 'bonus-product-2',
1758+
itemId: 'bonus-item-2',
1759+
quantity: 1,
1760+
bonusProductLineItem: true,
1761+
bonusDiscountLineItemId: 'bonus-456'
1762+
},
1763+
{
1764+
productId: 'regular-product-2',
1765+
itemId: 'regular-item-2',
1766+
quantity: 1
1767+
}
1768+
]
1769+
1770+
const result = cartUtils.consolidateDuplicateBonusProducts(productItems)
1771+
1772+
expect(result).toHaveLength(4)
1773+
// Regular products should come first
1774+
expect(result[0].productId).toBe('regular-product-1')
1775+
expect(result[0].bonusProductLineItem).toBeUndefined()
1776+
expect(result[1].productId).toBe('regular-product-2')
1777+
expect(result[1].bonusProductLineItem).toBeUndefined()
1778+
// Bonus products should come after
1779+
expect(result[2].productId).toBe('bonus-product-1')
1780+
expect(result[2].bonusProductLineItem).toBe(true)
1781+
expect(result[3].productId).toBe('bonus-product-2')
1782+
expect(result[3].bonusProductLineItem).toBe(true)
1783+
})
1784+
1785+
test('consolidates multiple duplicate bonus products and preserves other properties', () => {
1786+
const productItems = [
1787+
{
1788+
productId: 'bonus-product-1',
1789+
itemId: 'bonus-item-1',
1790+
quantity: 1,
1791+
bonusProductLineItem: true,
1792+
bonusDiscountLineItemId: 'bonus-123'
1793+
},
1794+
{
1795+
productId: 'bonus-product-1',
1796+
itemId: 'bonus-item-2',
1797+
quantity: 3,
1798+
bonusProductLineItem: true,
1799+
bonusDiscountLineItemId: 'bonus-123'
1800+
},
1801+
{
1802+
productId: 'bonus-product-2',
1803+
itemId: 'bonus-item-3',
1804+
quantity: 2,
1805+
bonusProductLineItem: true,
1806+
bonusDiscountLineItemId: 'bonus-456'
1807+
}
1808+
]
1809+
1810+
const result = cartUtils.consolidateDuplicateBonusProducts(productItems)
1811+
1812+
expect(result).toHaveLength(2)
1813+
// First bonus product should be consolidated
1814+
expect(result[0].productId).toBe('bonus-product-1')
1815+
expect(result[0].quantity).toBe(4) // 1 + 3
1816+
expect(result[0].bonusProductLineItem).toBe(true)
1817+
expect(result[0].bonusDiscountLineItemId).toBe('bonus-123')
1818+
// Second bonus product should remain separate
1819+
expect(result[1].productId).toBe('bonus-product-2')
1820+
expect(result[1].quantity).toBe(2)
1821+
})
1822+
1823+
test('handles mixed regular and bonus products with duplicates', () => {
1824+
const productItems = [
1825+
{
1826+
productId: 'regular-product-1',
1827+
itemId: 'regular-item-1',
1828+
quantity: 1
1829+
},
1830+
{
1831+
productId: 'bonus-product-1',
1832+
itemId: 'bonus-item-1',
1833+
quantity: 1,
1834+
bonusProductLineItem: true,
1835+
bonusDiscountLineItemId: 'bonus-123'
1836+
},
1837+
{
1838+
productId: 'regular-product-2',
1839+
itemId: 'regular-item-2',
1840+
quantity: 2
1841+
},
1842+
{
1843+
productId: 'bonus-product-1',
1844+
itemId: 'bonus-item-2',
1845+
quantity: 2,
1846+
bonusProductLineItem: true,
1847+
bonusDiscountLineItemId: 'bonus-123'
1848+
},
1849+
{
1850+
productId: 'bonus-product-2',
1851+
itemId: 'bonus-item-3',
1852+
quantity: 1,
1853+
bonusProductLineItem: true,
1854+
bonusDiscountLineItemId: 'bonus-456'
1855+
}
1856+
]
1857+
1858+
const result = cartUtils.consolidateDuplicateBonusProducts(productItems)
1859+
1860+
expect(result).toHaveLength(4)
1861+
// Regular products first
1862+
expect(result[0].productId).toBe('regular-product-1')
1863+
expect(result[0].quantity).toBe(1)
1864+
expect(result[1].productId).toBe('regular-product-2')
1865+
expect(result[1].quantity).toBe(2)
1866+
// Consolidated bonus products
1867+
expect(result[2].productId).toBe('bonus-product-1')
1868+
expect(result[2].quantity).toBe(3) // 1 + 2
1869+
expect(result[3].productId).toBe('bonus-product-2')
1870+
expect(result[3].quantity).toBe(1)
1871+
})
1872+
1873+
test('handles bonus products with zero quantity', () => {
1874+
const productItems = [
1875+
{
1876+
productId: 'bonus-product-1',
1877+
itemId: 'bonus-item-1',
1878+
quantity: 0,
1879+
bonusProductLineItem: true,
1880+
bonusDiscountLineItemId: 'bonus-123'
1881+
},
1882+
{
1883+
productId: 'bonus-product-1',
1884+
itemId: 'bonus-item-2',
1885+
quantity: 2,
1886+
bonusProductLineItem: true,
1887+
bonusDiscountLineItemId: 'bonus-123'
1888+
}
1889+
]
1890+
1891+
const result = cartUtils.consolidateDuplicateBonusProducts(productItems)
1892+
1893+
expect(result).toHaveLength(1)
1894+
expect(result[0].productId).toBe('bonus-product-1')
1895+
expect(result[0].quantity).toBe(2) // 0 + 2
1896+
})
1897+
1898+
test('handles bonus products with missing quantity property', () => {
1899+
const productItems = [
1900+
{
1901+
productId: 'bonus-product-1',
1902+
itemId: 'bonus-item-1',
1903+
bonusProductLineItem: true,
1904+
bonusDiscountLineItemId: 'bonus-123'
1905+
},
1906+
{
1907+
productId: 'bonus-product-1',
1908+
itemId: 'bonus-item-2',
1909+
quantity: 2,
1910+
bonusProductLineItem: true,
1911+
bonusDiscountLineItemId: 'bonus-123'
1912+
}
1913+
]
1914+
1915+
const result = cartUtils.consolidateDuplicateBonusProducts(productItems)
1916+
1917+
expect(result).toHaveLength(1)
1918+
expect(result[0].productId).toBe('bonus-product-1')
1919+
expect(result[0].quantity).toBe(2) // undefined treated as 0, then + 2
1920+
})
1921+
1922+
test('consolidates same bonus product from different qualifying products', () => {
1923+
// Scenario: Same product (bonus-product-1) is a bonus for two different qualifying products
1924+
// This tests that consolidation happens by productId only, regardless of which
1925+
// qualifying product triggered the bonus or which bonusDiscountLineItemId it has
1926+
const productItems = [
1927+
{
1928+
productId: 'regular-product-A',
1929+
itemId: 'regular-item-A',
1930+
quantity: 1
1931+
},
1932+
{
1933+
productId: 'bonus-product-1',
1934+
itemId: 'bonus-item-1',
1935+
quantity: 2,
1936+
bonusProductLineItem: true,
1937+
bonusDiscountLineItemId: 'bonus-123' // From regular-product-A
1938+
},
1939+
{
1940+
productId: 'regular-product-B',
1941+
itemId: 'regular-item-B',
1942+
quantity: 1
1943+
},
1944+
{
1945+
productId: 'bonus-product-1',
1946+
itemId: 'bonus-item-2',
1947+
quantity: 1,
1948+
bonusProductLineItem: true,
1949+
bonusDiscountLineItemId: 'bonus-456' // From regular-product-B (different line item)
1950+
}
1951+
]
1952+
1953+
const result = cartUtils.consolidateDuplicateBonusProducts(productItems)
1954+
1955+
expect(result).toHaveLength(3)
1956+
// Regular products first
1957+
expect(result[0].productId).toBe('regular-product-A')
1958+
expect(result[1].productId).toBe('regular-product-B')
1959+
// Bonus products consolidated - same productId from different sources merged
1960+
expect(result[2].productId).toBe('bonus-product-1')
1961+
expect(result[2].quantity).toBe(3) // 2 + 1, consolidated from both qualifying products
1962+
expect(result[2].bonusProductLineItem).toBe(true)
1963+
// Note: The bonusDiscountLineItemId will be from the first item found (bonus-123)
1964+
// This is a side effect of using sampleItem - information about the second source is lost
1965+
})
1966+
1967+
test('itemId is not used in consolidation logic (only for display keys)', () => {
1968+
// itemId is unique per line item but consolidation only uses productId
1969+
const productItems = [
1970+
{
1971+
productId: 'bonus-product-1',
1972+
itemId: 'unique-item-id-1',
1973+
quantity: 1,
1974+
bonusProductLineItem: true,
1975+
bonusDiscountLineItemId: 'bonus-123'
1976+
},
1977+
{
1978+
productId: 'bonus-product-1',
1979+
itemId: 'unique-item-id-2', // Different itemId
1980+
quantity: 2,
1981+
bonusProductLineItem: true,
1982+
bonusDiscountLineItemId: 'bonus-123'
1983+
}
1984+
]
1985+
1986+
const result = cartUtils.consolidateDuplicateBonusProducts(productItems)
1987+
1988+
expect(result).toHaveLength(1)
1989+
expect(result[0].productId).toBe('bonus-product-1')
1990+
expect(result[0].quantity).toBe(3) // Consolidated despite different itemIds
1991+
// The itemId in result will be from the first item found (unique-item-id-1)
1992+
// This is preserved for React key generation but not used in consolidation logic
1993+
})
1994+
})
16421995
})

0 commit comments

Comments
 (0)