diff --git a/client/.babelrc b/client/.babelrc index 68cee27920..9c442fbe77 100644 --- a/client/.babelrc +++ b/client/.babelrc @@ -43,10 +43,6 @@ "react-bootstrap": { "transform": "react-bootstrap/lib/${member}", "preventFullImport": true - }, - "lodash": { - "transform": "lodash/${member}", - "preventFullImport": true } } ], diff --git a/client/gatsby-node.js b/client/gatsby-node.js index 133a2a1b1f..6ffe2d7e96 100644 --- a/client/gatsby-node.js +++ b/client/gatsby-node.js @@ -2,6 +2,8 @@ const env = require('../config/env'); const webpack = require('webpack'); const { createFilePath } = require('gatsby-source-filesystem'); +// TODO: ideally we'd remove lodash and just use lodash-es, but we can't require +// es modules here. const uniq = require('lodash/uniq'); const { blockNameify } = require('../utils/block-nameify'); @@ -231,10 +233,6 @@ exports.onCreateBabelConfig = ({ actions }) => { '@freecodecamp/react-bootstrap': { transform: '@freecodecamp/react-bootstrap/lib/${member}', preventFullImport: true - }, - lodash: { - transform: 'lodash/${member}', - preventFullImport: true } } }); diff --git a/client/jest.config.js b/client/jest.config.js index 94d6f71b77..45a8315c6d 100644 --- a/client/jest.config.js +++ b/client/jest.config.js @@ -6,7 +6,8 @@ module.exports = { '^(?!.*\\.module\\.css$).*\\.css$': '/src/__mocks__/styleMock.js', // CSS Modules - match files that end with 'module.css' '\\.module\\.css$': 'identity-obj-proxy', - 'react-i18next': '/src/__mocks__/react-i18nextMock.js' + 'react-i18next': '/src/__mocks__/react-i18nextMock.js', + '^lodash-es$': 'lodash' }, testPathIgnorePatterns: ['/node_modules/', '/.cache/'], globals: { diff --git a/client/jest.transform.js b/client/jest.transform.js index 76ecf60501..662fd2b752 100644 --- a/client/jest.transform.js +++ b/client/jest.transform.js @@ -8,10 +8,6 @@ const babelOptions = { '@freecodecamp/react-bootstrap': { transform: '@freecodecamp/react-bootstrap/lib/${member}', preventFullImport: true - }, - lodash: { - transform: 'lodash/${member}', - preventFullImport: true } } ] diff --git a/client/package-lock.json b/client/package-lock.json index d43d011a85..35ffcb8773 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -5236,6 +5236,15 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -9765,6 +9774,12 @@ "typedarray-to-buffer": "^3.1.5" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, "filesize": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz", @@ -17136,6 +17151,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -18133,6 +18153,12 @@ "resolved": "https://registry.npmjs.org/name-all-modules-plugin/-/name-all-modules-plugin-1.0.1.tgz", "integrity": "sha1-Cr+2rYNXGLn7Te8GdOBmV6lUN1w=" }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "optional": true + }, "nanoid": { "version": "3.1.22", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", @@ -25479,7 +25505,11 @@ "version": "1.2.13", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "optional": true + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } }, "globby": { "version": "6.1.0", diff --git a/client/package.json b/client/package.json index 8b8eff295a..e425d2b4d1 100644 --- a/client/package.json +++ b/client/package.json @@ -81,6 +81,7 @@ "i18next": "19.9.2", "jquery": "3.6.0", "lodash": "4.17.21", + "lodash-es": "4.17.21", "monaco-editor": "0.22.3", "nanoid": "3.1.22", "path-browserify": "1.0.1", diff --git a/client/src/client-only-routes/ShowCertification.js b/client/src/client-only-routes/ShowCertification.js index 54342fa76f..e98c7af2cd 100644 --- a/client/src/client-only-routes/ShowCertification.js +++ b/client/src/client-only-routes/ShowCertification.js @@ -32,7 +32,7 @@ import envData from '../../../config/env.json'; import RedirectHome from '../components/RedirectHome'; import { Loader, Spacer } from '../components/helpers'; -import { isEmpty } from 'lodash'; +import { isEmpty } from 'lodash-es'; import { User } from '../redux/propTypes'; const { clientLocale } = envData; diff --git a/client/src/client-only-routes/ShowProfileOrFourOhFour.js b/client/src/client-only-routes/ShowProfileOrFourOhFour.js index c752db7d3b..f61428f56b 100644 --- a/client/src/client-only-routes/ShowProfileOrFourOhFour.js +++ b/client/src/client-only-routes/ShowProfileOrFourOhFour.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import { isEmpty } from 'lodash'; +import { isEmpty } from 'lodash-es'; import Loader from '../components/helpers/Loader'; import { diff --git a/client/src/client-only-routes/ShowProjectLinks.js b/client/src/client-only-routes/ShowProjectLinks.js index 783cea9666..6abf6599b4 100644 --- a/client/src/client-only-routes/ShowProjectLinks.js +++ b/client/src/client-only-routes/ShowProjectLinks.js @@ -6,7 +6,7 @@ import { maybeUrlRE } from '../utils'; import { Spacer, Link } from '../components/helpers'; import { projectMap, legacyProjectMap } from '../resources/certAndProjectMap'; import ProjectModal from '../components/SolutionViewer/ProjectModal'; -import { find, first } from 'lodash'; +import { find, first } from 'lodash-es'; import { Trans, useTranslation } from 'react-i18next'; const propTypes = { diff --git a/client/src/client/workers/test-evaluator.js b/client/src/client/workers/test-evaluator.js index cec40e4eba..c6415642cd 100644 --- a/client/src/client/workers/test-evaluator.js +++ b/client/src/client/workers/test-evaluator.js @@ -1,6 +1,6 @@ import chai from 'chai'; import '@babel/polyfill'; -import __toString from 'lodash/toString'; +import { toString as __toString } from 'lodash-es'; import { format as __format } from '../../utils/format'; import curriculumHelpers from '../../utils/curriculum-helpers'; diff --git a/client/src/components/formHelpers/FormFields.js b/client/src/components/formHelpers/FormFields.js index 12ae3ab1fc..1864462d12 100644 --- a/client/src/components/formHelpers/FormFields.js +++ b/client/src/components/formHelpers/FormFields.js @@ -1,5 +1,5 @@ import React from 'react'; -import { kebabCase } from 'lodash'; +import { kebabCase } from 'lodash-es'; import normalizeUrl from 'normalize-url'; import PropTypes from 'prop-types'; import { diff --git a/client/src/components/profile/components/Certifications.js b/client/src/components/profile/components/Certifications.js index 70b1e43963..9b325c4991 100644 --- a/client/src/components/profile/components/Certifications.js +++ b/client/src/components/profile/components/Certifications.js @@ -1,6 +1,6 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import { curry } from 'lodash'; +import { curry } from 'lodash-es'; import { createSelector } from 'reselect'; import { connect } from 'react-redux'; import { Row, Col } from '@freecodecamp/react-bootstrap'; diff --git a/client/src/components/profile/components/TimeLine.js b/client/src/components/profile/components/TimeLine.js index f6f2f773cc..111624c20a 100644 --- a/client/src/components/profile/components/TimeLine.js +++ b/client/src/components/profile/components/TimeLine.js @@ -1,6 +1,6 @@ import React, { Component, useMemo } from 'react'; import PropTypes from 'prop-types'; -import { reverse, sortBy } from 'lodash'; +import { reverse, sortBy } from 'lodash-es'; import { Button, Modal, diff --git a/client/src/components/search/searchBar/SearchBar.js b/client/src/components/search/searchBar/SearchBar.js index dfd00e7994..3d35637f7e 100644 --- a/client/src/components/search/searchBar/SearchBar.js +++ b/client/src/components/search/searchBar/SearchBar.js @@ -5,7 +5,7 @@ import { bindActionCreators } from 'redux'; import { createSelector } from 'reselect'; import { SearchBox } from 'react-instantsearch-dom'; import { HotKeys, ObserveKeys } from 'react-hotkeys'; -import { isEqual } from 'lodash'; +import { isEqual } from 'lodash-es'; import { withTranslation } from 'react-i18next'; import { searchPageUrl } from '../../../utils/algolia-locale-setup'; diff --git a/client/src/components/search/searchBar/SearchHits.js b/client/src/components/search/searchBar/SearchHits.js index 99e35b20a0..2284fbacac 100644 --- a/client/src/components/search/searchBar/SearchHits.js +++ b/client/src/components/search/searchBar/SearchHits.js @@ -1,7 +1,7 @@ import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import { connectStateResults, connectHits } from 'react-instantsearch-dom'; -import isEmpty from 'lodash/isEmpty'; +import { isEmpty } from 'lodash-es'; import { useTranslation } from 'react-i18next'; import { searchPageUrl } from '../../../utils/algolia-locale-setup'; diff --git a/client/src/components/search/searchPage/SearchPageHits.js b/client/src/components/search/searchPage/SearchPageHits.js index c86879043f..3a78e45cb8 100644 --- a/client/src/components/search/searchPage/SearchPageHits.js +++ b/client/src/components/search/searchPage/SearchPageHits.js @@ -5,7 +5,7 @@ import { connectStateResults, connectAutoComplete } from 'react-instantsearch-dom'; -import { isEmpty } from 'lodash'; +import { isEmpty } from 'lodash-es'; import EmptySearch from './EmptySearch'; import NoResults from './NoResults'; diff --git a/client/src/components/settings/Certification.js b/client/src/components/settings/Certification.js index d4fa6f0cef..bfe08b93b6 100644 --- a/client/src/components/settings/Certification.js +++ b/client/src/components/settings/Certification.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { find, first, values, isString } from 'lodash'; +import { find, first, values, isString } from 'lodash-es'; import { Table, Button, diff --git a/client/src/components/settings/Portfolio.js b/client/src/components/settings/Portfolio.js index fdf683dc2f..91f15c001f 100644 --- a/client/src/components/settings/Portfolio.js +++ b/client/src/components/settings/Portfolio.js @@ -8,7 +8,7 @@ import { FormControl, HelpBlock } from '@freecodecamp/react-bootstrap'; -import { findIndex, find, isEqual } from 'lodash'; +import { findIndex, find, isEqual } from 'lodash-es'; import isURL from 'validator/lib/isURL'; import { withTranslation } from 'react-i18next'; diff --git a/client/src/pages/update-email.js b/client/src/pages/update-email.js index 6f7472499b..6c0b63814e 100644 --- a/client/src/pages/update-email.js +++ b/client/src/pages/update-email.js @@ -16,7 +16,7 @@ import { } from '@freecodecamp/react-bootstrap'; import Helmet from 'react-helmet'; import isEmail from 'validator/lib/isEmail'; -import { isString } from 'lodash'; +import { isString } from 'lodash-es'; import { withTranslation } from 'react-i18next'; import { Spacer } from '../components/helpers'; diff --git a/client/src/redux/error-saga.js b/client/src/redux/error-saga.js index 7da7be605f..7d4e60d9cb 100644 --- a/client/src/redux/error-saga.js +++ b/client/src/redux/error-saga.js @@ -1,6 +1,6 @@ import { navigate } from 'gatsby'; import { takeEvery, put } from 'redux-saga/effects'; -import { isError } from 'lodash'; +import { isError } from 'lodash-es'; import { isHandledError, unwrapHandledError } from '../utils/handled-error'; import { reportClientSideError } from '../utils/report-error'; diff --git a/client/src/redux/index.js b/client/src/redux/index.js index a2aefef204..9e3175f7c5 100644 --- a/client/src/redux/index.js +++ b/client/src/redux/index.js @@ -1,5 +1,5 @@ import { createAction, handleActions } from 'redux-actions'; -import { uniqBy } from 'lodash'; +import { uniqBy } from 'lodash-es'; import store from 'store'; import { createTypes, createAsyncTypes } from '../utils/createTypes'; diff --git a/client/src/templates/Challenges/classic/DesktopLayout.js b/client/src/templates/Challenges/classic/DesktopLayout.js index f342e40334..cfd8797d9a 100644 --- a/client/src/templates/Challenges/classic/DesktopLayout.js +++ b/client/src/templates/Challenges/classic/DesktopLayout.js @@ -1,7 +1,7 @@ import React, { Component, Fragment } from 'react'; import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex'; import PropTypes from 'prop-types'; -import { first } from 'lodash'; +import { first } from 'lodash-es'; import EditorTabs from './EditorTabs'; import ActionRow from './ActionRow'; import envData from '../../../../../config/env.json'; diff --git a/client/src/templates/Challenges/components/CompletionModal.js b/client/src/templates/Challenges/components/CompletionModal.js index 8ebfaf9d87..4862d89dd6 100644 --- a/client/src/templates/Challenges/components/CompletionModal.js +++ b/client/src/templates/Challenges/components/CompletionModal.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import noop from 'lodash/noop'; +import { noop } from 'lodash-es'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { Button, Modal } from '@freecodecamp/react-bootstrap'; diff --git a/client/src/templates/Challenges/components/Output.js b/client/src/templates/Challenges/components/Output.js index ee1a5c90b6..02e36a898e 100644 --- a/client/src/templates/Challenges/components/Output.js +++ b/client/src/templates/Challenges/components/Output.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import sanitizeHtml from 'sanitize-html'; import './output.css'; -import { isEmpty } from 'lodash'; +import { isEmpty } from 'lodash-es'; const propTypes = { defaultOutput: PropTypes.string, diff --git a/client/src/templates/Challenges/rechallenge/builders.js b/client/src/templates/Challenges/rechallenge/builders.js index 180644b7b5..5d1a0dbf6e 100644 --- a/client/src/templates/Challenges/rechallenge/builders.js +++ b/client/src/templates/Challenges/rechallenge/builders.js @@ -6,7 +6,7 @@ import { partial, stubTrue, template as _template -} from 'lodash'; +} from 'lodash-es'; import { compileHeadTail, diff --git a/client/src/templates/Challenges/rechallenge/throwers.js b/client/src/templates/Challenges/rechallenge/throwers.js index 80e862ee07..36219388fc 100644 --- a/client/src/templates/Challenges/rechallenge/throwers.js +++ b/client/src/templates/Challenges/rechallenge/throwers.js @@ -1,4 +1,4 @@ -import { cond, identity, stubTrue, conforms } from 'lodash'; +import { cond, identity, stubTrue, conforms } from 'lodash-es'; const HTML$JSReg = /html|js/; diff --git a/client/src/templates/Challenges/rechallenge/transformers.js b/client/src/templates/Challenges/rechallenge/transformers.js index 59e5a52e41..80a67a556f 100644 --- a/client/src/templates/Challenges/rechallenge/transformers.js +++ b/client/src/templates/Challenges/rechallenge/transformers.js @@ -8,7 +8,7 @@ import { overSome, partial, stubTrue -} from 'lodash'; +} from 'lodash-es'; import protect from '@freecodecamp/loop-protect'; diff --git a/client/src/templates/Challenges/redux/execute-challenge-saga.js b/client/src/templates/Challenges/redux/execute-challenge-saga.js index d54c17be9d..436ccfa6ed 100644 --- a/client/src/templates/Challenges/redux/execute-challenge-saga.js +++ b/client/src/templates/Challenges/redux/execute-challenge-saga.js @@ -11,7 +11,7 @@ import { cancel } from 'redux-saga/effects'; import { channel } from 'redux-saga'; -import escape from 'lodash/escape'; +import { escape } from 'lodash-es'; import i18next from 'i18next'; import { diff --git a/client/src/templates/Challenges/redux/index.js b/client/src/templates/Challenges/redux/index.js index cd9e664b94..866b98f5dd 100644 --- a/client/src/templates/Challenges/redux/index.js +++ b/client/src/templates/Challenges/redux/index.js @@ -14,7 +14,7 @@ import { createCurrentChallengeSaga } from './current-challenge-saga'; import { challengeTypes } from '../../../../utils/challengeTypes'; import { getTargetEditor } from '../utils/getTargetEditor'; import { completedChallengesSelector } from '../../../redux'; -import { isEmpty } from 'lodash'; +import { isEmpty } from 'lodash-es'; export const ns = 'challenge'; export const backendNS = 'backendChallenge'; diff --git a/client/src/templates/Challenges/utils/frame.js b/client/src/templates/Challenges/utils/frame.js index 60c44be152..47e1cfa1c3 100644 --- a/client/src/templates/Challenges/utils/frame.js +++ b/client/src/templates/Challenges/utils/frame.js @@ -1,4 +1,4 @@ -import { toString, flow } from 'lodash'; +import { toString, flow } from 'lodash-es'; import { format } from '../../../utils/format'; // we use two different frames to make them all essentially pure functions diff --git a/client/src/templates/Challenges/utils/getTargetEditor.js b/client/src/templates/Challenges/utils/getTargetEditor.js index 950ab5153f..9c9972ddb7 100644 --- a/client/src/templates/Challenges/utils/getTargetEditor.js +++ b/client/src/templates/Challenges/utils/getTargetEditor.js @@ -1,5 +1,5 @@ import { toSortedArray } from '../../../../../utils/sort-files'; -import { isEmpty } from 'lodash'; +import { isEmpty } from 'lodash-es'; export function getTargetEditor(challengeFiles) { if (isEmpty(challengeFiles)) return null; diff --git a/client/src/templates/Introduction/SuperBlockIntro.js b/client/src/templates/Introduction/SuperBlockIntro.js index bc3fd497bf..4d0d104c01 100644 --- a/client/src/templates/Introduction/SuperBlockIntro.js +++ b/client/src/templates/Introduction/SuperBlockIntro.js @@ -2,7 +2,7 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import Helmet from 'react-helmet'; import { graphql } from 'gatsby'; -import { uniq } from 'lodash'; +import { uniq } from 'lodash-es'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { bindActionCreators } from 'redux'; diff --git a/client/src/utils/handled-error.js b/client/src/utils/handled-error.js index eb66ebac14..8aa7ce6ec0 100644 --- a/client/src/utils/handled-error.js +++ b/client/src/utils/handled-error.js @@ -1,4 +1,4 @@ -import { has } from 'lodash'; +import { has } from 'lodash-es'; import standardErrorMessage from './standardErrorMessage'; import reportedErrorMessage from './reportedErrorMessage'; diff --git a/client/src/utils/handled-error.test.js b/client/src/utils/handled-error.test.js index 08a6866a33..0048eb8d95 100644 --- a/client/src/utils/handled-error.test.js +++ b/client/src/utils/handled-error.test.js @@ -1,5 +1,5 @@ /* global expect */ -import { isObject } from 'lodash'; +import { isObject } from 'lodash-es'; import sinon from 'sinon'; import { isHandledError, diff --git a/curriculum/package-lock.json b/curriculum/package-lock.json index e5c5f5a03f..1b6435982e 100644 --- a/curriculum/package-lock.json +++ b/curriculum/package-lock.json @@ -5905,6 +5905,27 @@ } } }, + "mock-require": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz", + "integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==", + "dev": true, + "requires": { + "get-caller-file": "^1.0.2", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, "morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", diff --git a/curriculum/package.json b/curriculum/package.json index 801bb11afa..af1bd698ce 100644 --- a/curriculum/package.json +++ b/curriculum/package.json @@ -55,6 +55,7 @@ "live-server": "1.2.1", "lodash": "4.17.21", "mocha": "8.3.2", + "mock-require": "3.0.3", "puppeteer": "8.0.0", "readdirp": "3.6.0", "rehype": "11.0.0", diff --git a/curriculum/test/test-challenges.js b/curriculum/test/test-challenges.js index 572443c95c..b4840dedd1 100644 --- a/curriculum/test/test-challenges.js +++ b/curriculum/test/test-challenges.js @@ -17,6 +17,13 @@ require('@babel/register')({ only: [clientPath] }); +const mockRequire = require('mock-require'); +const lodash = require('lodash'); + +// lodash-es can't easily be used in node environments, so we just mock it out +// for the original lodash in testing. +mockRequire('lodash-es', lodash); + const createPseudoWorker = require('./utils/pseudo-worker'); const { default: createWorker @@ -24,7 +31,8 @@ const { const { assert, AssertionError } = require('chai'); const Mocha = require('mocha'); -const { flatten, isEmpty, cloneDeep, isEqual } = require('lodash'); + +const { flatten, isEmpty, cloneDeep, isEqual } = lodash; const { getLines } = require('../../utils/get-lines'); const jsdom = require('jsdom');