From 362139edd29546e0a92e3783eb1d2b8fd2e16487 Mon Sep 17 00:00:00 2001 From: Ben Warzeski Date: Tue, 22 Feb 2022 12:45:30 -0500 Subject: [PATCH] feat: mock paragon and i18n library for tests --- .gitignore | 6 ++ .../EditorHeader/.HeaderTitle.jsx.swp | Bin 12288 -> 0 bytes src/setupTest.js | 38 +++++++++++ src/testUtils.js | 59 ++++++++++++++++++ 4 files changed, 103 insertions(+) delete mode 100644 src/editors/components/EditorHeader/.HeaderTitle.jsx.swp create mode 100644 src/testUtils.js diff --git a/.gitignore b/.gitignore index 67045665d..269a8d92f 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,9 @@ dist # TernJS port file .tern-port + +### Emacs/vi ### +*~ +*.swo +*.swp + diff --git a/src/editors/components/EditorHeader/.HeaderTitle.jsx.swp b/src/editors/components/EditorHeader/.HeaderTitle.jsx.swp deleted file mode 100644 index 0046a380691f4726ec4a5e6dff42a847dfd3af94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2UuYaf9LJ{?YFk?)`dH9ugx*E(c9TdjB)Jfq*d}OgiD?u?WbStEZp_~9c4w|h zx}4&RKB`~^ee07V=(G6HHxYc(2SGs)L|>$eK3P!kJNxH$Hx+|LXR{X4R?*+ccJtbow?g-_F(k_^v zj7_VYIXtwJ+lEjsw_cGuqca`C(2^wgwQ;^Fbr^nv>?A8=7j`bGhx zfKk9GU=%P47zK<1MuCH+fC>(g*O2mEY1%KO_d|Q`=}&Vr3K#{90!9I&fKk9GU=%P4 z7zK<1MggOMQQ&{50CNcOju7(a-3T84|DXN)|K~A6Zh{ZM`=ARN;GcU5`5SxzZh#P+ z2j@T)oC3$e?URK33Vs6bf$Lx!^uWvD5?BO}f>Yoa`0E5AKZ38pP4FrB2z&_M1#f~Y zpam|1$H9Z(DEQ+ZLVf{1fN#M!;7jl^5MTqG2Q%Oya01*qPRRG*b8rK^1>OJ=xC$iL z1j}FvoB@Zy@5c}y_zZjkUI&-KBcKA#fZIn2`3hVI?|`>~3zk3wEC8+fcUpII83l|2 zMggOMQQ*H(fbZ~~zz-F5c$@WIMNwJj@s_Ig*c}^!XBAU?!@m^zfvnLU3s!^-m}+%X z+eEccXg4uW$Y7pOD!Dp~g1@b}{BDl2mJ+@vEfxe;si{WNnGuRq`wUMTG{Tq|m{K9v zJfQ@0#Wn8CVGb9;qXaM>w$xaaI_ilUI;q`&ClT)Lk+%%p_Xbl;9+9Mew6RF5Iw~Dh zKFS=`B5hzkX-O3duVV?h&ad=E$Q>O@Df6OtyYIF3_?FTs`Zj&v-Q#Q96f^X9FvUx8 z&a@awmj%2U(N;eUQ9D^2ig~+qFw#K>qoYmgE7y6u*ah{M7u!0;>WieX?pBax9vC!_Sq#-x?-m)uNTa5^NCseuakj6N@1Zpe^#eD)6vX1ZB`rs&J9Z`K~)Z)L% u(Xns0LU6+mO`5qre(QQ6OQT{?{dpe_7IJ)t>sg}d>a1&HI!x? { + const i18n = jest.requireActual('@edx/frontend-platform/i18n'); + const PropTypes = jest.requireActual('prop-types'); + return { + ...i18n, + intlShape: PropTypes.shape({ + formatMessage: PropTypes.func, + }), + defineMessages: m => m, + FormattedMessage: () => 'FormattedMessage', + }; +}); + +jest.mock('@edx/paragon', () => jest.requireActual('testUtils').mockNestedComponents({ + ActionRow: 'ActionRow', + Button: 'Button', + Icon: 'Icon', + IconButton: 'IconButton', + ModalDialog: { + Header: 'ModalDialog.Header', + Title: 'ModalDialog.Title', + }, + Form: { + Control: { + Feedback: 'Form.Control.Feedback', + }, + Group: 'Form.Group', + Label: 'Form.Label', + }, + Spinner: 'Spinner', + Toast: 'Toast', +})); + +jest.mock('@edx/paragon/icons', () => ({ + Close: jest.fn().mockName('icons.Close'), + Edit: jest.fn().mockName('icons.Edit'), +})); diff --git a/src/testUtils.js b/src/testUtils.js new file mode 100644 index 000000000..b1f346b36 --- /dev/null +++ b/src/testUtils.js @@ -0,0 +1,59 @@ +/** + * Mocked formatMessage provided by react-intl + */ +export const formatMessage = (msg, values) => { + let message = msg.defaultMessage; + if (values === undefined) { + return message; + } + Object.keys(values).forEach((key) => { + // eslint-disable-next-line + message = message.replace(`{${key}}`, values[key]); + }); + return message; +}; + +/** + * Mock a single component, or a nested component so that its children render nicely + * in snapshots. + * @param {string} name - parent component name + * @param {obj} contents - object of child components with intended component + * render name. + * @return {func} - mock component with nested children. + * + * usage: + * mockNestedComponent('Card', { Body: 'Card.Body', Form: { Control: { Feedback: 'Form.Control.Feedback' }}... }); + * mockNestedComponent('IconButton', 'IconButton'); + */ +export const mockNestedComponent = (name, contents) => { + if (typeof contents !== 'object') { + return contents; + } + const fn = () => name; + Object.defineProperty(fn, 'name', { value: name }); + Object.keys(contents).forEach((nestedName) => { + const value = contents[nestedName]; + fn[nestedName] = typeof value !== 'object' + ? value + : mockNestedComponent(`${name}.${nestedName}`, value); + }); + return fn; +}; + +/** + * Mock a module of components. nested components will be rendered nicely in snapshots. + * @param {obj} mapping - component module mock config. + * @return {obj} - module of flat and nested components that will render nicely in snapshots. + * usage: + * mockNestedComponents({ + * Card: { Body: 'Card.Body' }, + * IconButton: 'IconButton', + * }) + */ +export const mockNestedComponents = (mapping) => Object.entries(mapping).reduce( + (obj, [name, value]) => ({ + ...obj, + [name]: mockNestedComponent(name, value), + }), + {}, +);