diff --git a/package-lock.json b/package-lock.json index 839316e68..2dd4aab60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38877,6 +38877,7 @@ "eslint-plugin-react": "^7.22.0", "eslint-plugin-unicorn": "^44.0.0", "intl": "^1.2.5", + "jest": "^29.3.1", "jsdom": "^20.0.0", "mocha": "^10.0.0", "nyc": "^15.1.0", @@ -43074,6 +43075,7 @@ "eslint-plugin-unicorn": "^44.0.0", "hoist-non-react-statics": "^3.0.0", "intl": "^1.2.5", + "jest": "^29.3.1", "jsdom": "^20.0.0", "just-extend": "^6.2.0", "mocha": "^10.0.0", diff --git a/packages/gasket-react-intl/jest.config.js b/packages/gasket-react-intl/jest.config.js new file mode 100644 index 000000000..e0e1a49e9 --- /dev/null +++ b/packages/gasket-react-intl/jest.config.js @@ -0,0 +1,5 @@ +module.exports = { + collectCoverageFrom: ['lib/**/*.js'], + setupFiles: ['/test/setup.js'], + testEnvironment: 'jsdom' +}; diff --git a/packages/gasket-react-intl/package.json b/packages/gasket-react-intl/package.json index 37cbe2ef9..b80b8d488 100644 --- a/packages/gasket-react-intl/package.json +++ b/packages/gasket-react-intl/package.json @@ -15,7 +15,7 @@ "scripts": { "lint": "eslint .", "lint:fix": "npm run lint -- --fix", - "test": "npm run test:runner", + "test": "jest", "test:runner": "mocha --require setup-env --require test/setup.js \"test/*.test.js\"", "test:watch": "npm run test:runner -- --watch", "test:coverage": "nyc --reporter=text --reporter=json-summary npm run test:runner", @@ -73,6 +73,7 @@ "eslint-plugin-react": "^7.22.0", "eslint-plugin-unicorn": "^44.0.0", "intl": "^1.2.5", + "jest": "^29.3.1", "jsdom": "^20.0.0", "mocha": "^10.0.0", "nyc": "^15.1.0", @@ -92,7 +93,8 @@ }, "eslintConfig": { "extends": [ - "godaddy-react" + "godaddy-react", + "plugin:jest/recommended" ], "plugins": [ "unicorn" diff --git a/packages/gasket-react-intl/test/locale-required.test.js b/packages/gasket-react-intl/test/locale-required.test.js index 3eb51efb7..5f366f235 100644 --- a/packages/gasket-react-intl/test/locale-required.test.js +++ b/packages/gasket-react-intl/test/locale-required.test.js @@ -1,74 +1,60 @@ import React from 'react'; -import assume from 'assume'; -import sinon from 'sinon'; -import proxyquire from 'proxyquire'; import { render } from '@testing-library/react'; -import mockManifest from './fixtures/mock-manifest.json'; import { LocaleStatus } from '../src/utils'; +import LocaleRequired from '../src/locale-required'; +import useLocaleRequired from '../src/use-locale-required'; + +jest.mock('../src/use-locale-required'); + const { ERROR, LOADED, LOADING } = LocaleStatus; describe('LocaleRequired', function () { - let mockConfig, useLocaleRequiredStub, LocaleRequired, wrapper; + let wrapper; const doMount = props => MockComponent; beforeEach(function () { - useLocaleRequiredStub = sinon.stub(); - mockConfig = { - defaultLocale: 'en-US', - manifest: { ...mockManifest, paths: { ...mockManifest.paths } }, - isBrowser: false - }; - LocaleRequired = proxyquire('../src/locale-required', { - './config': mockConfig, - './use-locale-required': { - default: useLocaleRequiredStub - } - }).default; - }); - - afterEach(function () { - sinon.restore(); + useLocaleRequired.mockClear(); }); describe('#render', function () { it('renders null if loading', function () { - useLocaleRequiredStub.returns(LOADING); + useLocaleRequired.mockReturnValue(LOADING); wrapper = render(doMount({})); - assume(wrapper.baseElement.textContent).eqls(''); + expect(wrapper.baseElement.textContent).toEqual(''); }); it('renders custom loader if loading', function () { - useLocaleRequiredStub.returns(LOADING); + useLocaleRequired.mockReturnValue(LOADING); wrapper = render(doMount({ loading: 'loading...' })); - assume(wrapper.baseElement.textContent).eqls('loading...'); + expect(wrapper.baseElement.textContent).toEqual('loading...'); }); it('renders wrapped component if LOADED', function () { - useLocaleRequiredStub.returns(LOADED); + useLocaleRequired.mockReturnValue(LOADED); wrapper = render(doMount({ loading: 'loading...' })); - assume(wrapper.baseElement.textContent).includes('MockComponent'); + expect(wrapper.baseElement.textContent).toContain('MockComponent'); }); it('renders wrapped component if ERROR', function () { - useLocaleRequiredStub.returns(ERROR); + useLocaleRequired.mockReturnValue(ERROR); wrapper = render(doMount({ loading: 'loading...' })); - assume(wrapper.baseElement.textContent).includes('MockComponent'); + expect(wrapper.baseElement.textContent).toContain('MockComponent'); }); it('supports localesPath', function () { - useLocaleRequiredStub.returns(LOADING); + useLocaleRequired.mockReturnValue(LOADING); wrapper = render(doMount({ localesPath: '/bogus' })); - assume(useLocaleRequiredStub).calledWith('/bogus'); - assume(wrapper.baseElement.textContent).eqls(''); + expect(useLocaleRequired).toHaveBeenCalledWith('/bogus'); + expect(wrapper.baseElement.textContent).toEqual(''); }); it('supports localesPath as thunk', function () { - const mockThunk = sinon.stub(); - useLocaleRequiredStub.returns(LOADING); + const mockThunk = jest.fn(); + useLocaleRequired.mockReturnValue(LOADING); wrapper = render(doMount({ localesPath: mockThunk })); - assume(useLocaleRequiredStub).calledWith(mockThunk); - assume(wrapper.baseElement.textContent).eqls(''); + expect(useLocaleRequired).toHaveBeenCalledWith(mockThunk); + expect(wrapper.baseElement.textContent).toEqual(''); }); }); }); diff --git a/packages/gasket-react-intl/test/next.test.js b/packages/gasket-react-intl/test/next.test.js index 2370fb56d..99a58d04f 100644 --- a/packages/gasket-react-intl/test/next.test.js +++ b/packages/gasket-react-intl/test/next.test.js @@ -1,13 +1,11 @@ /* eslint-disable no-console */ -import assume from 'assume'; -import sinon from 'sinon'; -import proxyquire from 'proxyquire'; +import { jest } from '@jest/globals'; describe('Next.js functions', function () { let next, res; beforeEach(function () { - sinon.stub(console, 'error'); + jest.spyOn(console, 'error').mockImplementation(() => {}); res = { locals: { gasketData: { @@ -17,29 +15,22 @@ describe('Next.js functions', function () { } } }; - next = proxyquire('../src/next', { - ['./config']: { - manifest: { - defaultPath: '/locales', - defaultLocale: 'en-US' - } - } - }); + next = require('../src/next'); }); afterEach(function () { - sinon.restore(); + jest.restoreAllMocks(); }); describe('intlGetStaticProps', function () { it('makes getStaticProps function', function () { const results = next.intlGetStaticProps(); - assume(results).instanceOf(Function); + expect(typeof results).toBe('function'); }); it('returns localesProps for default path', async function () { - const results = await next.intlGetStaticProps()({ params: { locale: 'en-US' } }); - assume(results).eqls({ + const results = await next.intlGetStaticProps('/locales')({ params: { locale: 'en-US' } }); + expect(results).toEqual({ props: { localesProps: { locale: 'en-US', @@ -52,7 +43,7 @@ describe('Next.js functions', function () { it('returns localesProps for other path part', async function () { const results = await next.intlGetStaticProps('/locales/extra')({ params: { locale: 'en-US' } }); - assume(results).eqls({ + expect(results).toEqual({ props: { localesProps: { locale: 'en-US', @@ -65,11 +56,11 @@ describe('Next.js functions', function () { it('handles thunks for locale path part', async function () { const mockContext = { params: { locale: 'en-US' }, extra: true }; - const mockThunk = sinon.stub().callsFake((context) => context.extra ? '/locales/extra' : '/locales'); + const mockThunk = jest.fn().mockImplementation((context) => context.extra ? '/locales/extra' : '/locales'); const results = await next.intlGetStaticProps(mockThunk)(mockContext); - assume(mockThunk).calledWith(mockContext); - assume(results).eqls({ + expect(mockThunk).toHaveBeenCalledWith(mockContext); + expect(results).toEqual({ props: { localesProps: { locale: 'en-US', @@ -82,7 +73,7 @@ describe('Next.js functions', function () { it('returns localesProps for multiple locale path parts', async function () { const results = await next.intlGetStaticProps(['/locales', '/locales/extra'])({ params: { locale: 'en-US' } }); - assume(results).eqls({ + expect(results).toEqual({ props: { localesProps: { locale: 'en-US', @@ -97,8 +88,9 @@ describe('Next.js functions', function () { }); it('returns localesProps with error for missing path', async function () { + const consoleSpy = jest.spyOn(console, 'error'); const results = await next.intlGetStaticProps('/locales/missing')({ params: { locale: 'en-US' } }); - assume(results).eqls({ + expect(results).toEqual({ props: { localesProps: { locale: 'en-US', @@ -107,12 +99,13 @@ describe('Next.js functions', function () { } } }); - assume(console.error).is.calledWithMatch('Cannot find module'); + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Cannot find module')); + consoleSpy.mockRestore(); }); it('returns localesProps for default if locale missing', async function () { const results = await next.intlGetStaticProps('/locales')({ params: { locale: 'fr-CA' } }); - assume(results).eqls({ + expect(results).toEqual({ props: { localesProps: { locale: 'fr-CA', @@ -125,7 +118,7 @@ describe('Next.js functions', function () { it('uses locale on context from builtin i18n routing', async function () { const results = await next.intlGetStaticProps('/locales')({ locale: 'fr-CA' }); - assume(results).eqls({ + expect(results).toEqual({ props: { localesProps: { locale: 'fr-CA', @@ -140,12 +133,12 @@ describe('Next.js functions', function () { describe('intlGetServerSideProps', function () { it('makes getServerSideProps function', function () { const results = next.intlGetServerSideProps(); - assume(results).instanceOf(Function); + expect(typeof results).toBe('function'); }); it('returns localesProps for default path', async function () { - const results = await next.intlGetServerSideProps()({ res }); - assume(results).eqls({ + const results = await next.intlGetServerSideProps('/locales')({ res }); + expect(results).toEqual({ props: { localesProps: { locale: 'en-US', @@ -158,7 +151,7 @@ describe('Next.js functions', function () { it('returns localesProps for other path part', async function () { const results = await next.intlGetServerSideProps('/locales/extra')({ res }); - assume(results).eqls({ + expect(results).toEqual({ props: { localesProps: { locale: 'en-US', @@ -171,11 +164,11 @@ describe('Next.js functions', function () { it('handles thunks for locale path part', async function () { const mockContext = { res, extra: true }; - const mockThunk = sinon.stub().callsFake((context) => context.extra ? '/locales/extra' : '/locales'); + const mockThunk = jest.fn().mockImplementation((context) => context.extra ? '/locales/extra' : '/locales'); const results = await next.intlGetServerSideProps(mockThunk)(mockContext); - assume(mockThunk).calledWith(mockContext); - assume(results).eqls({ + expect(mockThunk).toHaveBeenCalledWith(mockContext); + expect(results).toEqual({ props: { localesProps: { locale: 'en-US', @@ -188,7 +181,7 @@ describe('Next.js functions', function () { it('returns localesProps for multiple locale path parts', async function () { const results = await next.intlGetServerSideProps(['/locales', '/locales/extra'])({ res }); - assume(results).eqls({ + expect(results).toEqual({ props: { localesProps: { locale: 'en-US', @@ -203,8 +196,9 @@ describe('Next.js functions', function () { }); it('returns localesProps with error for missing path', async function () { + const consoleSpy = jest.spyOn(console, 'error'); const results = await next.intlGetServerSideProps('/locales/missing')({ res }); - assume(results).eqls({ + expect(results).toEqual({ props: { localesProps: { locale: 'en-US', @@ -213,13 +207,14 @@ describe('Next.js functions', function () { } } }); - assume(console.error).is.calledWithMatch('Cannot find module'); + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Cannot find module')); + consoleSpy.mockRestore(); }); it('returns localesProps for default if locale missing', async function () { res.locals.gasketData.intl.locale = 'fr-CA'; const results = await next.intlGetServerSideProps('/locales')({ res }); - assume(results).eqls({ + expect(results).toEqual({ props: { localesProps: { locale: 'fr-CA', @@ -232,7 +227,7 @@ describe('Next.js functions', function () { it('uses locale on context from builtin i18n routing', async function () { const results = await next.intlGetServerSideProps('/locales')({ locale: 'fr-CA', res }); - assume(results).eqls({ + expect(results).toEqual({ props: { localesProps: { locale: 'fr-CA', diff --git a/packages/gasket-react-intl/test/use-locale-required.test.js b/packages/gasket-react-intl/test/use-locale-required.test.js index 460538ba0..9a99c2d7b 100644 --- a/packages/gasket-react-intl/test/use-locale-required.test.js +++ b/packages/gasket-react-intl/test/use-locale-required.test.js @@ -1,141 +1,138 @@ -import assume from 'assume'; -import sinon from 'sinon'; -import proxyquire from 'proxyquire'; -import mockManifest from './fixtures/mock-manifest.json'; +import { useContext } from 'react'; import { LocaleStatus } from '../src/utils'; +import useLocaleRequired from '../src/use-locale-required'; +import fetch from '@gasket/fetch'; + +jest.mock('react', () => ({ + ...jest.requireActual('react'), + useContext: jest.fn() +})); + +jest.mock('@gasket/fetch', () => jest.fn()); + +jest.mock('../src/config', () => ({ + isBrowser: true, + clientData: {}, + manifest: require('./fixtures/mock-manifest.json') +})); + const { ERROR, LOADED, LOADING } = LocaleStatus; // helper to wait for async actions const pause = ms => new Promise((resolve) => setTimeout(resolve, ms)); describe('useLocaleRequired', function () { - let mockConfig, mockContext, fetchStub, useLocaleRequired; - - const getModule = () => { - return proxyquire('../src/use-locale-required', { - 'react': { - useContext: sinon.stub().returns(mockContext) - }, - '@gasket/fetch': { - default: fetchStub - }, - './config': mockConfig, - './utils': proxyquire('../src/utils', { - './config': mockConfig - }) - }); - }; + let mockConfig, mockContext, dispatchMock; beforeEach(function () { - fetchStub = sinon.stub().resolves({ ok: true, json: () => ({ example: 'Example' }) }); + fetch.mockResolvedValue({ ok: true, json: () => ({ example: 'Example' }) }); + + dispatchMock = jest.fn(); mockContext = { locale: 'en', status: {}, - dispatch: sinon.stub() + dispatch: dispatchMock }; - mockConfig = { - defaultLocale: 'en-US', - manifest: { ...mockManifest, paths: { ...mockManifest.paths } }, - isBrowser: true - }; - useLocaleRequired = getModule().default; + useContext.mockReturnValue(mockContext); + + mockConfig = require('../src/config'); }); - afterEach(function () { - sinon.restore(); + afterEach(() => { + jest.clearAllMocks(); }); it('fetches locales url if not loaded', function () { const results = useLocaleRequired('/locales'); - assume(results).equals(LOADING); - assume(fetchStub).called(); - assume(fetchStub).calledWith('/locales/en.json'); + expect(results).toEqual(LOADING); + expect(fetch).toHaveBeenCalled(); + expect(fetch).toHaveBeenCalledWith('/locales/en.json'); }); it('handle thunks for locale paths', function () { - const mockThunk = sinon.stub().callsFake(() => '/custom/locales'); + const mockThunk = jest.fn().mockReturnValue('/custom/locales'); const results = useLocaleRequired(mockThunk); - assume(results).equals(LOADING); - assume(fetchStub).called(); - assume(fetchStub).calledWith('/custom/locales/en.json'); + expect(results).toEqual(LOADING); + expect(fetch).toHaveBeenCalled(); + expect(fetch).toHaveBeenCalledWith('/custom/locales/en.json'); }); it('returns LOADING if fetching', function () { const results = useLocaleRequired('/locales'); - assume(results).equals(LOADING); - assume(fetchStub).called(); + expect(results).toEqual(LOADING); + expect(fetch).toHaveBeenCalled(); }); it('returns status if set', function () { mockContext.status['/locales/en.json'] = LOADED; - assume(useLocaleRequired('/locales')).equals(LOADED); + expect(useLocaleRequired('/locales')).toEqual(LOADED); mockContext.status['/locales/en.json'] = ERROR; - assume(useLocaleRequired('/locales')).equals(ERROR); + expect(useLocaleRequired('/locales')).toEqual(ERROR); mockContext.status['/locales/en.json'] = LOADING; - assume(useLocaleRequired('/locales')).equals(LOADING); + expect(useLocaleRequired('/locales')).toEqual(LOADING); }); it('dispatches LOADED action when loaded', async function () { useLocaleRequired('/locales'); - assume(fetchStub).called(); + expect(fetch).toHaveBeenCalled(); await pause(20); - assume(mockContext.dispatch).calledWith( + expect(dispatchMock).toHaveBeenCalledWith( { type: 'loaded', payload: { locale: 'en', messages: { example: 'Example' }, file: '/locales/en.json' } } ); }); it('dispatches ERROR action on bad response', async function () { - const consoleStub = sinon.stub(console, 'error'); - fetchStub.resolves({ ok: false, status: 404 }); + console.error = jest.fn(); + fetch.mockResolvedValue({ ok: false, status: 404 }); useLocaleRequired('/locales'); - assume(fetchStub).called(); + expect(fetch).toHaveBeenCalled(); await pause(20); - assume(mockContext.dispatch).calledWith( + expect(dispatchMock).toHaveBeenCalledWith( { type: 'error', payload: { file: '/locales/en.json' } } ); - assume(consoleStub).calledWith('Error loading locale file (404): /locales/en.json'); + expect(console.error).toHaveBeenCalledWith('Error loading locale file (404): /locales/en.json'); + }); it('dispatches ERROR action on rejected fetch', async function () { - const consoleStub = sinon.stub(console, 'error'); - fetchStub.rejects(new Error('Bad things man!')); + console.error = jest.fn(); + fetch.mockRejectedValue(new Error('Bad things man!')); useLocaleRequired('/locales'); - assume(fetchStub).called(); + expect(fetch).toHaveBeenCalled(); await pause(20); - assume(mockContext.dispatch).calledWith( + expect(dispatchMock).toHaveBeenCalledWith( { type: 'error', payload: { file: '/locales/en.json' } } ); - assume(consoleStub).calledWith('Bad things man!'); + expect(console.error).toHaveBeenCalledWith('Bad things man!'); }); describe('SSR', function () { beforeEach(function () { mockConfig.isBrowser = false; - useLocaleRequired = getModule().default; }); it('returns LOADING if no locale file', function () { const results = useLocaleRequired('/locales'); - assume(results).equals(LOADING); + expect(results).toEqual(LOADING); }); it('returns status if set', function () { mockContext.status['/locales/en.json'] = LOADED; - assume(useLocaleRequired('/locales')).equals(LOADED); + expect(useLocaleRequired('/locales')).toEqual(LOADED); }); it('does not fetch', function () { useLocaleRequired('/locales'); - assume(fetchStub).not.called(); + expect(fetch).not.toHaveBeenCalled(); }); }); }); diff --git a/packages/gasket-react-intl/test/utils.test.js b/packages/gasket-react-intl/test/utils.test.js index 5dfd4828f..798d656de 100644 --- a/packages/gasket-react-intl/test/utils.test.js +++ b/packages/gasket-react-intl/test/utils.test.js @@ -1,62 +1,68 @@ -import assume from 'assume'; -import sinon from 'sinon'; -import proxyquire from 'proxyquire'; import { LocaleUtils } from '@gasket/helper-intl'; +import * as utils from '../src/utils'; -describe('utils', function () { - let mockConfig, utils; +jest.mock('../src/config', () => ({ + isBrowser: false, + clientData: {}, + manifest: require('./fixtures/mock-manifest.json') +})); - const getModule = () => { - return proxyquire('../src/utils', { - './config': mockConfig - }); - }; +describe('utils', function () { + let mockConfig; beforeEach(function () { - mockConfig = { isBrowser: false, clientData: {}, manifest: require('./fixtures/mock-manifest.json') }; - utils = getModule(); + mockConfig = require('../src/config'); }); afterEach(function () { - sinon.restore(); + jest.restoreAllMocks(); delete global.window.gasketIntlLocale; delete global.navigator.languages; }); it('exports localeUtils instance', function () { - assume(utils).property('localeUtils'); - assume(utils.localeUtils).instanceOf(LocaleUtils); + expect(utils).toHaveProperty('localeUtils'); + expect(utils.localeUtils).toBeInstanceOf(LocaleUtils); }); describe('getActiveLocale', function () { - it('returns defaultLocale from manifest', function () { const results = utils.getActiveLocale(); - assume(results).equals(mockConfig.manifest.defaultLocale); + expect(results).toEqual(mockConfig.manifest.defaultLocale); }); it('returns locale from window property', function () { mockConfig.isBrowser = true; mockConfig.clientData.locale = 'fr'; global.window.gasketIntlLocale = 'de'; - global.navigator.languages = ['jp']; + Object.defineProperty(global.navigator, 'languages', { + value: ['jp'], + configurable: true + }); const results = utils.getActiveLocale(); - assume(results).equals('de'); + expect(results).toEqual('de'); }); it('returns locale from clientData', function () { mockConfig.isBrowser = true; mockConfig.clientData.locale = 'fr'; - global.navigator.languages = ['jp']; - const results = getModule().getActiveLocale(); - assume(results).equals('fr'); + Object.defineProperty(global.navigator, 'languages', { + value: ['jp'], + configurable: true + }); + const results = utils.getActiveLocale(); + expect(results).toEqual('fr'); }); it('returns locale from first navigator.languages', function () { mockConfig.isBrowser = true; - global.navigator.languages = ['jp']; + mockConfig.clientData.locale = null; + Object.defineProperty(global.navigator, 'languages', { + value: ['jp'], + configurable: true + }); const results = utils.getActiveLocale(); - assume(results).equals('jp'); + expect(results).toEqual('jp'); }); }); }); diff --git a/packages/gasket-react-intl/test/with-intl-provider.test.js b/packages/gasket-react-intl/test/with-intl-provider.test.js index c45e57d8c..08e1bf0f0 100644 --- a/packages/gasket-react-intl/test/with-intl-provider.test.js +++ b/packages/gasket-react-intl/test/with-intl-provider.test.js @@ -1,8 +1,5 @@ import React from 'react'; -import assume from 'assume'; -import sinon from 'sinon'; -import proxyquire from 'proxyquire'; -import mockManifest from './fixtures/mock-manifest.json'; +import withIntlProviderDefault, { reducer, init } from '../src/with-intl-provider'; import { LocaleStatus } from '../src/utils'; const { ERROR, LOADED, LOADING } = LocaleStatus; @@ -13,47 +10,34 @@ const MockComponent = class extends React.Component { }; describe('withIntlProvider', function () { - let mockConfig, withIntlProvider, module; - - const getModule = () => { - return proxyquire('../src/with-intl-provider', { - './config': mockConfig, - './utils': proxyquire('../src/utils', { - './config': mockConfig - }) - }); - }; + let mockConfig; + let withIntlProvider; beforeEach(function () { - mockConfig = { - defaultLocale: 'en-US', - manifest: { ...mockManifest, paths: { ...mockManifest.paths } }, - isBrowser: false - }; - module = getModule(); - - withIntlProvider = module.default; - }); - - afterEach(function () { - sinon.restore(); + mockConfig = require('../src/config'); + withIntlProvider = withIntlProviderDefault(); }); it('adds display name', function () { - assume(withIntlProvider()(MockComponent)).property('displayName', 'withIntlProvider(MockComponent)'); + const WrappedComponent = withIntlProvider(MockComponent); + expect(WrappedComponent.displayName).toBe('withIntlProvider(MockComponent)'); }); it('hoists non-react statics', function () { - assume(withIntlProvider()(MockComponent)).not.property('bogus'); + const WrappedComponent = withIntlProvider(MockComponent); + expect(WrappedComponent).not.toHaveProperty('bogus'); MockComponent.bogus = 'BOGUS'; - assume(withIntlProvider()(MockComponent)).property('bogus', 'BOGUS'); + const WrappedComponentBogus = withIntlProvider(MockComponent); + expect(WrappedComponentBogus).toHaveProperty('bogus', 'BOGUS'); delete MockComponent.bogus; }); it('hoists getInitialProps if set', function () { - assume(withIntlProvider()(MockComponent)).not.property('getInitialProps'); + const WrappedComponent = withIntlProvider(MockComponent); + expect(WrappedComponent).not.toHaveProperty('getInitialProps'); MockComponent.getInitialProps = f => f; - assume(withIntlProvider()(MockComponent)).property('getInitialProps'); + const WrappedComponentSetIP = withIntlProvider(MockComponent); + expect(WrappedComponentSetIP).toHaveProperty('getInitialProps'); delete MockComponent.getInitialProps; }); @@ -69,12 +53,14 @@ describe('withIntlProvider', function () { it('LOADED actions add messages and file status', function () { const action = { type: LOADED, payload: { locale: 'en', messages: { example: 'Example' }, file: '/locales/en.json' } }; - const result = module.reducer(initState, action); - assume(result).eqls({ - messages: { en: { - first: 'First', - example: 'Example' - } }, + const result = reducer(initState, action); + expect(result).toEqual({ + messages: { + en: { + first: 'First', + example: 'Example' + } + }, status: { '/locales/en/first.json': LOADED, '/locales/en.json': LOADED @@ -84,11 +70,13 @@ describe('withIntlProvider', function () { it('ERROR actions add file status', function () { const action = { type: ERROR, payload: { file: '/locales/en.json' } }; - const result = module.reducer(initState, action); - assume(result).eqls({ - messages: { en: { - first: 'First' - } }, + const result = reducer(initState, action); + expect(result).toEqual({ + messages: { + en: { + first: 'First' + } + }, status: { '/locales/en/first.json': LOADED, '/locales/en.json': ERROR @@ -98,11 +86,13 @@ describe('withIntlProvider', function () { it('LOADING actions add file status', function () { const action = { type: LOADING, payload: { file: '/locales/en.json' } }; - const result = module.reducer(initState, action); - assume(result).eqls({ - messages: { en: { - first: 'First' - } }, + const result = reducer(initState, action); + expect(result).toEqual({ + messages: { + en: { + first: 'First' + } + }, status: { '/locales/en/first.json': LOADED, '/locales/en.json': LOADING @@ -112,46 +102,47 @@ describe('withIntlProvider', function () { }); describe('init', function () { - it('initializes state with empty objects', function () { - const result = module.init({}); - assume(result).eqls({ + const result = init({}); + expect(result).toEqual({ messages: {}, status: {} }); }); it('initializes state with locales props', function () { - const result = module.init({ + const result = init({ locale: 'en', messages: { en: { example: 'Example' } }, status: { '/locales/en.json': LOADED } }); - assume(result).eqls({ + expect(result).toEqual({ messages: { en: { example: 'Example' } }, status: { '/locales/en.json': LOADED } }); }); it('merges locales props data with client data', function () { - mockConfig = { isBrowser: true, clientData: { + mockConfig.clientData = { locale: 'en', messages: { en: { first: 'First' } }, status: { '/locales/en/first.json': LOADED } - } }; - - module = getModule(); + }; + mockConfig.isBrowser = true; - const result = module.init({ + const result = init({ locale: 'en', messages: { en: { example: 'Example' } }, status: { '/locales/en.json': LOADED } }); - assume(result).eqls({ - messages: { en: { - first: 'First', - example: 'Example' - } }, + + expect(result).toEqual({ + messages: { + en: { + first: 'First', + example: 'Example' + } + }, status: { '/locales/en/first.json': LOADED, '/locales/en.json': LOADED diff --git a/packages/gasket-react-intl/test/with-locale-required.test.js b/packages/gasket-react-intl/test/with-locale-required.test.js index 79403efab..2a0d1c743 100644 --- a/packages/gasket-react-intl/test/with-locale-required.test.js +++ b/packages/gasket-react-intl/test/with-locale-required.test.js @@ -1,11 +1,11 @@ import React from 'react'; import path from 'path'; -import assume from 'assume'; -import sinon from 'sinon'; -import proxyquire from 'proxyquire'; import { render, screen } from '@testing-library/react'; -import mockManifest from './fixtures/mock-manifest.json'; import { LocaleStatus } from '../src/utils'; +import withLocaleRequired from '../src/with-locale-required'; + +jest.mock('../src/use-locale-required', () => jest.fn()); + const { ERROR, LOADED, LOADING } = LocaleStatus; const loadingText = 'loading...'; @@ -16,45 +16,37 @@ const MockComponent = class extends React.Component { }; describe('withLocaleRequired', function () { - let mockConfig, useLocaleRequiredStub, withLocaleRequired, wrapper; + let useLocaleRequiredMock, wrapper; const doMount = (...args) => { const Wrapped = withLocaleRequired(...args)(MockComponent); - return render(); + return render(); }; beforeEach(function () { - useLocaleRequiredStub = sinon.stub(); - mockConfig = { - defaultLocale: 'en-US', - manifest: { ...mockManifest, paths: { ...mockManifest.paths } }, - isBrowser: false - }; - withLocaleRequired = proxyquire('../src/with-locale-required', { - './config': mockConfig, - './use-locale-required': { - default: useLocaleRequiredStub - } - }).default; + useLocaleRequiredMock = require('../src/use-locale-required'); }); afterEach(function () { - sinon.restore(); + jest.restoreAllMocks(); }); it('adds display name', function () { - assume(withLocaleRequired()(MockComponent)).property('displayName', 'withLocaleRequired(MockComponent)'); + const wrapped = withLocaleRequired()(MockComponent); + expect(wrapped.displayName).toBe('withLocaleRequired(MockComponent)'); }); it('adds display name with ForwardRef', function () { - assume(withLocaleRequired('/locales', { forwardRef: true })(MockComponent)) - .property('displayName', 'ForwardRef(withLocaleRequired/MockComponent))'); + const wrapped = withLocaleRequired('/locales', { forwardRef: true })(MockComponent); + expect(wrapped.displayName).toBe('ForwardRef(withLocaleRequired/MockComponent))'); }); it('hoists non-react statics', function () { - assume(withLocaleRequired()(MockComponent)).not.property('bogus'); + const wrapped = withLocaleRequired()(MockComponent); + expect(wrapped).not.toHaveProperty('bogus'); MockComponent.bogus = 'BOGUS'; - assume(withLocaleRequired()(MockComponent)).property('bogus', 'BOGUS'); + const wrappedBogus = withLocaleRequired()(MockComponent); + expect(wrappedBogus).toHaveProperty('bogus', 'BOGUS'); delete MockComponent.bogus; }); @@ -64,30 +56,30 @@ describe('withLocaleRequired', function () { }); it('hoists getInitialProps if set', function () { - assume(withLocaleRequired()(MockComponent)).not.property('getInitialProps'); - MockComponent.getInitialProps = sinon.stub(); - assume(withLocaleRequired()(MockComponent)).property('getInitialProps'); + const wrapped = withLocaleRequired()(MockComponent); + expect(wrapped).not.toHaveProperty('getInitialProps'); + MockComponent.getInitialProps = jest.fn(); + const wrappedGetInitialProps = withLocaleRequired()(MockComponent); + expect(wrappedGetInitialProps).toHaveProperty('getInitialProps'); }); it('adds getInitialProps if initialProps set', function () { const wrapped = withLocaleRequired('/locales', { initialProps: true })(MockComponent); - assume(wrapped).property('getInitialProps'); + expect(wrapped).toHaveProperty('getInitialProps'); }); it('executes wrapped getInitialProps', async function () { - MockComponent.getInitialProps = sinon.stub().returns({ bogus: true }); + MockComponent.getInitialProps = jest.fn().mockResolvedValue({ bogus: true }); const wrapped = withLocaleRequired('/locales', { initialProps: true })(MockComponent); - const ctx = {}; const props = await wrapped.getInitialProps(ctx); - assume(MockComponent.getInitialProps).calledWith(ctx); - assume(props).eqls({ bogus: true }); + expect(MockComponent.getInitialProps).toHaveBeenCalledWith(ctx); + expect(props).toEqual({ bogus: true }); }); it('loads localeProps on server', async function () { - MockComponent.getInitialProps = sinon.stub().returns({ bogus: true }); + MockComponent.getInitialProps = jest.fn().mockResolvedValue({ bogus: true }); const wrapped = withLocaleRequired('/locales', { initialProps: true })(MockComponent); - const ctx = { res: { locals: { @@ -101,8 +93,8 @@ describe('withLocaleRequired', function () { } }; const props = await wrapped.getInitialProps(ctx); - assume(MockComponent.getInitialProps).calledWith(ctx); - assume(props).eqls({ + expect(MockComponent.getInitialProps).toHaveBeenCalledWith(ctx); + expect(props).toEqual({ bogus: true, localesProps: { locale: 'fr-FR', @@ -113,9 +105,8 @@ describe('withLocaleRequired', function () { }); it('handles missing gasketData', async function () { - MockComponent.getInitialProps = sinon.stub().returns({ bogus: true }); + MockComponent.getInitialProps = jest.fn().mockResolvedValue({ bogus: true }); const wrapped = withLocaleRequired('/locales', { initialProps: true })(MockComponent); - const ctx = { res: { locals: { @@ -123,21 +114,19 @@ describe('withLocaleRequired', function () { } } }; - let error = null; try { await wrapped.getInitialProps(ctx); } catch (err) { error = err; } - assume(error).to.equal(null); + expect(error).toBe(null); }); it('resolve localePahThunk and passes as prop', async function () { - const mockThunk = sinon.stub().callsFake((context) => context.extra ? '/locales/extra' : '/locales'); - MockComponent.getInitialProps = sinon.stub().returns({ bogus: true }); + const mockThunk = jest.fn().mockImplementation((context) => (context.extra ? '/locales/extra' : '/locales')); + MockComponent.getInitialProps = jest.fn().mockResolvedValue({ bogus: true }); const wrapped = withLocaleRequired(mockThunk, { initialProps: true })(MockComponent); - const ctx = { extra: true, res: { @@ -152,8 +141,8 @@ describe('withLocaleRequired', function () { } }; const props = await wrapped.getInitialProps(ctx); - assume(MockComponent.getInitialProps).calledWith(ctx); - assume(props).eqls({ + expect(MockComponent.getInitialProps).toHaveBeenCalledWith(ctx); + expect(props).toEqual({ localePathPart: '/locales/extra', bogus: true, localesProps: { @@ -167,30 +156,30 @@ describe('withLocaleRequired', function () { describe('#render', function () { it('renders empty if loading', function () { - useLocaleRequiredStub.returns(LOADING); + useLocaleRequiredMock.mockReturnValue(LOADING); // Set the mock return value to LOADING; wrapper = doMount(); - assume(wrapper.baseElement.innerHTML).eqls('
'); + expect(wrapper.baseElement.innerHTML).toEqual('
'); }); it('renders custom loader if loading', async function () { - useLocaleRequiredStub.returns(LOADING); + useLocaleRequiredMock.mockReturnValue(LOADING); doMount('/locales', { loading: loadingText }); const textEl = await screen.findByText(loadingText); - assume(textEl.innerHTML).eqls(loadingText); + expect(textEl.innerHTML).toEqual(loadingText); }); it('renders wrapped component if LOADED', async function () { - useLocaleRequiredStub.returns(LOADED); + useLocaleRequiredMock.mockReturnValue(LOADED); doMount({ loading: loadingText }); const textEl = await screen.findByText('MockComponent'); - assume(textEl.innerHTML).eqls('MockComponent'); + expect(textEl.innerHTML).toEqual('MockComponent'); }); it('renders wrapped component if ERROR', async function () { - useLocaleRequiredStub.returns(ERROR); + useLocaleRequiredMock.mockReturnValue(ERROR); doMount({ loading: loadingText }); const textEl = await screen.findByText('MockComponent'); - assume(textEl.innerHTML).eqls('MockComponent'); + expect(textEl.innerHTML).toEqual('MockComponent'); }); it('forwards refs', async function () { @@ -201,9 +190,7 @@ describe('withLocaleRequired', function () { } render() { - return ( - - ); + return ; } } @@ -230,17 +217,15 @@ describe('withLocaleRequired', function () { return ( - { this.state.data } + {this.state.data} ); } } render(); - const element = await screen.getByTestId('data'); - - assume(element.innerHTML).equals('MOCK_DATA'); + expect(element.innerHTML).toEqual('MOCK_DATA'); }); }); });