From 3483f1930e03c935d405ca222137e0afe3a8c08c Mon Sep 17 00:00:00 2001 From: Paul Sealock Date: Fri, 19 Feb 2021 07:06:28 +1300 Subject: [PATCH] Navigation: Add test to container component (https://github.com/woocommerce/woocommerce-admin/pull/6344) * getCategoriesMap * getMenuItemsByCategory * changelog --- .../navigation/components/container/index.js | 118 +++++----- .../components/container/test/index.js | 204 ++++++++++++++++++ plugins/woocommerce-admin/package-lock.json | 18 +- plugins/woocommerce-admin/readme.txt | 1 + 4 files changed, 282 insertions(+), 59 deletions(-) create mode 100644 plugins/woocommerce-admin/client/navigation/components/container/test/index.js diff --git a/plugins/woocommerce-admin/client/navigation/components/container/index.js b/plugins/woocommerce-admin/client/navigation/components/container/index.js index 64d1ffa562e..af929c59ec3 100644 --- a/plugins/woocommerce-admin/client/navigation/components/container/index.js +++ b/plugins/woocommerce-admin/client/navigation/components/container/index.js @@ -22,6 +22,70 @@ import CategoryTitle from '../category-title'; import Header from '../header'; import Item from '../../components/Item'; +/** + * Get a map of all categories, including the topmost WooCommerce parentCategory + * + * @param {Array} menuItems Array of menuItems + * @return {Object} Map of categories by id + */ +export const getCategoriesMap = ( menuItems ) => { + return menuItems.reduce( + ( acc, item ) => { + if ( item.isCategory ) { + return { ...acc, [ item.id ]: item }; + } + return acc; + }, + { + woocommerce: { + capability: 'manage_woocommerce', + id: 'woocommerce', + isCategory: true, + menuId: 'primary', + migrate: true, + order: 10, + parent: '', + title: 'WooCommerce', + }, + } + ); +}; + +/** + * Get a flat tree structure of all Categories and thier children grouped by menuId + * + * @param {Object} categoriesMap Map of categories by id + * @param {Array} menuItems Array of menuItems + * @return {Object} a;dslkfj + */ +export const getMenuItemsByCategory = ( categoriesMap, menuItems ) => { + return menuItems.reduce( ( acc, item ) => { + // Set up the category if it doesn't yet exist. + if ( ! acc[ item.parent ] ) { + acc[ item.parent ] = {}; + } + + // Check if parent category is in the same menu. + if ( + item.parent !== 'woocommerce' && + categoriesMap[ item.parent ] && + categoriesMap[ item.parent ].menuId !== item.menuId && + // Allow favorites to exist under any menu. + categoriesMap[ item.parent ].menuId !== 'favorites' + ) { + return acc; + } + + // Create the menu object if it doesn't exist in this category. + if ( ! acc[ item.parent ][ item.menuId ] ) { + acc[ item.parent ][ item.menuId ] = []; + } + + acc[ item.parent ][ item.menuId ].push( item ); + return acc; + }, {} ); +}; + const Container = ( { menuItems } ) => { useEffect( () => { // Collapse the original WP Menu. @@ -38,27 +102,7 @@ const Container = ( { menuItems } ) => { const { rootBackLabel, rootBackUrl } = window.wcNavigation; - const parentCategory = { - capability: 'manage_woocommerce', - id: 'woocommerce', - isCategory: true, - menuId: 'primary', - migrate: true, - order: 10, - parent: '', - title: 'WooCommerce', - }; - const categoriesMap = menuItems.reduce( - ( acc, item ) => { - if ( item.isCategory ) { - return { ...acc, [ item.id ]: item }; - } - return acc; - }, - { - woocommerce: parentCategory, - } - ); + const categoriesMap = getCategoriesMap( menuItems ); const categories = Object.values( categoriesMap ); const [ activeItem, setActiveItem ] = useState( 'woocommerce-home' ); @@ -83,37 +127,9 @@ const Container = ( { menuItems } ) => { return removeListener; }, [ menuItems ] ); - const getMenuItemsByCategory = ( items ) => { - return items.reduce( ( acc, item ) => { - // Set up the category if it doesn't yet exist. - if ( ! acc[ item.parent ] ) { - acc[ item.parent ] = {}; - } - - // Check if parent category is in the same menu. - if ( - item.parent !== 'woocommerce' && - categoriesMap[ item.parent ] && - categoriesMap[ item.parent ].menuId !== item.menuId && - // Allow favorites to exist under any menu. - categoriesMap[ item.parent ].menuId !== 'favorites' - ) { - return acc; - } - - // Create the menu object if it doesn't exist in this category. - if ( ! acc[ item.parent ][ item.menuId ] ) { - acc[ item.parent ][ item.menuId ] = []; - } - - acc[ item.parent ][ item.menuId ].push( item ); - return acc; - }, {} ); - }; - const categorizedItems = useMemo( - () => getMenuItemsByCategory( menuItems ), - [ menuItems ] + () => getMenuItemsByCategory( categoriesMap, menuItems ), + [ categoriesMap, menuItems ] ); const navDomRef = useRef( null ); diff --git a/plugins/woocommerce-admin/client/navigation/components/container/test/index.js b/plugins/woocommerce-admin/client/navigation/components/container/test/index.js new file mode 100644 index 00000000000..12a0bf23ab0 --- /dev/null +++ b/plugins/woocommerce-admin/client/navigation/components/container/test/index.js @@ -0,0 +1,204 @@ +/** + * Internal dependencies + */ +import { getCategoriesMap, getMenuItemsByCategory } from '../'; + +describe( 'getCategoriesMap', () => { + const menuItems = [ + { id: 'zero', title: 'zero', isCategory: true }, + { id: 'one', title: 'one', isCategory: true }, + { id: 'two', title: 'two', isCategory: true }, + { id: 'three', title: 'three', isCategory: false }, + { id: 'four', title: 'four', isCategory: false }, + ]; + + it( 'should get a map of all categories', () => { + const categoriesMap = getCategoriesMap( menuItems ); + + expect( categoriesMap.zero ).toMatchObject( menuItems[ 0 ] ); + expect( categoriesMap.one ).toMatchObject( menuItems[ 1 ] ); + expect( categoriesMap.two ).toMatchObject( menuItems[ 2 ] ); + expect( categoriesMap.three ).toBeUndefined(); + expect( categoriesMap.four ).toBeUndefined(); + } ); + + it( 'should include the topmost WooCommerce parent category', () => { + const categoriesMap = getCategoriesMap( menuItems ); + + expect( categoriesMap.woocommerce ).toBeDefined(); + } ); + + it( 'should have the correct number of values', () => { + const categoriesMap = getCategoriesMap( menuItems ); + + expect( Object.keys( categoriesMap ).length ).toBe( 4 ); + } ); +} ); + +describe( 'getMenuItemsByCategory', () => { + it( 'should get a map of all categories and child elements', () => { + const menuItems = [ + { + id: 'child-one', + title: 'child-one', + isCategory: false, + parent: 'parent', + menuId: 'plugins', + }, + { + id: 'child-two', + title: 'child-two', + isCategory: false, + parent: 'parent', + menuId: 'plugins', + }, + { + id: 'parent', + title: 'parent', + isCategory: true, + parent: 'woocommerce', + menuId: 'plugins', + }, + ]; + const categoriesMap = getCategoriesMap( menuItems ); + const categorizedItems = getMenuItemsByCategory( + categoriesMap, + menuItems + ); + + expect( categorizedItems.woocommerce ).toBeDefined(); + expect( categorizedItems.woocommerce.plugins ).toBeDefined(); + expect( categorizedItems.woocommerce.plugins.length ).toBe( 1 ); + + expect( categorizedItems.parent ).toBeDefined(); + expect( categorizedItems.parent.plugins ).toBeDefined(); + expect( categorizedItems.parent.plugins.length ).toBe( 2 ); + } ); + + it( 'should handle multiple depths', () => { + const menuItems = [ + { + id: 'grand-child', + title: 'grand-child', + isCategory: false, + parent: 'child', + menuId: 'plugins', + }, + { + id: 'child', + title: 'child', + isCategory: true, + parent: 'grand-parent', + menuId: 'plugins', + }, + { + id: 'grand-parent', + title: 'grand-parent', + isCategory: true, + parent: 'woocommerce', + menuId: 'plugins', + }, + ]; + const categoriesMap = getCategoriesMap( menuItems ); + const categorizedItems = getMenuItemsByCategory( + categoriesMap, + menuItems + ); + + expect( categorizedItems[ 'grand-parent' ] ).toBeDefined(); + expect( categorizedItems[ 'grand-parent' ] ).toBeDefined(); + expect( categorizedItems[ 'grand-parent' ].plugins.length ).toBe( 1 ); + + expect( categorizedItems.child ).toBeDefined(); + expect( categorizedItems.child ).toBeDefined(); + expect( categorizedItems.child.plugins.length ).toBe( 1 ); + + expect( categorizedItems[ 'grand-child' ] ).not.toBeDefined(); + } ); + + it( 'should group by menuId', () => { + const menuItems = [ + { + id: 'parent', + title: 'parent', + isCategory: true, + parent: 'woocommerce', + menuId: 'primary', + }, + { + id: 'primary-one', + title: 'primary-one', + isCategory: false, + parent: 'parent', + menuId: 'primary', + }, + { + id: 'primary-two', + title: 'primary-two', + isCategory: false, + parent: 'parent', + menuId: 'primary', + }, + ]; + const categoriesMap = getCategoriesMap( menuItems ); + const categorizedItems = getMenuItemsByCategory( + categoriesMap, + menuItems + ); + + expect( categorizedItems.parent ).toBeDefined(); + expect( categorizedItems.parent.primary ).toBeDefined(); + expect( categorizedItems.parent.primary.length ).toBe( 2 ); + } ); + + it( 'should group children only if their menuId matches parent', () => { + const menuItems = [ + { + id: 'plugin-one', + title: 'plugin-one', + isCategory: false, + parent: 'parent', + menuId: 'plugins', + }, + { + id: 'plugin-two', + title: 'plugin-two', + isCategory: false, + parent: 'parent', + menuId: 'plugins', + }, + { + id: 'parent', + title: 'parent', + isCategory: true, + parent: 'woocommerce', + menuId: 'plugins', + }, + { + id: 'primary-one', + title: 'primary-one', + isCategory: false, + parent: 'parent', + menuId: 'primary', + }, + { + id: 'primary-two', + title: 'primary-two', + isCategory: false, + parent: 'parent', + menuId: 'primary', + }, + ]; + const categoriesMap = getCategoriesMap( menuItems ); + const categorizedItems = getMenuItemsByCategory( + categoriesMap, + menuItems + ); + + expect( categorizedItems.parent ).toBeDefined(); + expect( categorizedItems.parent.plugins ).toBeDefined(); + expect( categorizedItems.parent.plugins.length ).toBe( 2 ); + + expect( categorizedItems.primary ).not.toBeDefined(); + } ); +} ); diff --git a/plugins/woocommerce-admin/package-lock.json b/plugins/woocommerce-admin/package-lock.json index d25d699172a..afb94271fbb 100644 --- a/plugins/woocommerce-admin/package-lock.json +++ b/plugins/woocommerce-admin/package-lock.json @@ -48,6 +48,7 @@ "config": "^3.2.4", "eslint": "6.7.2", "jest": "^24.9.0", + "prettier": "npm:wp-prettier@1.19.1", "puppeteer": "^2.0.0" }, "dependencies": { @@ -142,6 +143,11 @@ } } } + }, + "prettier": { + "version": "npm:wp-prettier@1.19.1", + "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-1.19.1.tgz", + "integrity": "sha512-mqAC2r1NDmRjG+z3KCJ/i61tycKlmADIjxnDhQab+KBxSAGbF/W7/zwB2guy/ypIeKrrftNsIYkNZZQKf3vJcg==" } } }, @@ -9049,8 +9055,7 @@ } }, "@woocommerce/currency": { - "version": "3.0.0", - "resolved": "/mnt/renovate/gh/woocommerce/woocommerce-admin/packages/currency", + "version": "file:packages/currency", "dev": true, "requires": { "@babel/runtime-corejs2": "7.12.5", @@ -9167,8 +9172,7 @@ } }, "@woocommerce/data": { - "version": "1.1.1", - "resolved": "/mnt/renovate/gh/woocommerce/woocommerce-admin/packages/data", + "version": "file:packages/data", "dev": true, "requires": { "@babel/runtime-corejs2": "7.12.5", @@ -9178,8 +9182,7 @@ } }, "@woocommerce/date": { - "version": "2.1.0", - "resolved": "/mnt/renovate/gh/woocommerce/woocommerce-admin/packages/date", + "version": "file:packages/date", "dev": true, "requires": { "@babel/runtime-corejs2": "7.12.5", @@ -10192,8 +10195,7 @@ } }, "@woocommerce/navigation": { - "version": "5.2.0", - "resolved": "/mnt/renovate/gh/woocommerce/woocommerce-admin/packages/navigation", + "version": "file:packages/navigation", "dev": true, "requires": { "lodash": "4.17.15" diff --git a/plugins/woocommerce-admin/readme.txt b/plugins/woocommerce-admin/readme.txt index 324eb363696..697fda1c9af 100644 --- a/plugins/woocommerce-admin/readme.txt +++ b/plugins/woocommerce-admin/readme.txt @@ -78,6 +78,7 @@ Release and roadmap notes are available on the [WooCommerce Developers Blog](htt - Dev: Allow highlight tooltip to use body tag as parent. #6309 - Dev: Remove Google fonts and material icons. #6343 - Add: Remove CES actions for adding and editing a product and editing an order #6355 +- Dev: Add unit tests to Navigation's Container component. #6344 == 2.0.0 02/05/2021 ==