Skip to content

Commit

Permalink
chore: updates
Browse files Browse the repository at this point in the history
  • Loading branch information
adamstankiewicz committed Feb 21, 2025
1 parent 1c2d2cf commit 14d12e3
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 40 deletions.
31 changes: 14 additions & 17 deletions src/react/AppProvider.test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { createStore } from 'redux';
import { render } from '@testing-library/react';
import { render, screen, waitFor } from '@testing-library/react';
import AppProvider from './AppProvider';
import { initialize } from '../initialize';

Expand Down Expand Up @@ -48,7 +48,7 @@ describe('AppProvider', () => {
});
});

it('should render its children with a router', () => {
it('should render its children with a router', async () => {
const component = (
<AppProvider store={createStore(state => state)}>
<div className="child">Child One</div>
Expand All @@ -57,16 +57,16 @@ describe('AppProvider', () => {
);

const wrapper = render(component);
const list = wrapper.container.querySelectorAll('div.child');
expect(list.length).toEqual(2);
expect(list[0].textContent).toEqual('Child One');
expect(list[1].textContent).toEqual('Child Two');
await waitFor(() => {
expect(screen.getByText('Child One')).toBeInTheDocument();
expect(screen.getByText('Child Two')).toBeInTheDocument();
});
expect(wrapper.getByTestId('browser-router')).toBeInTheDocument();
const reduxProvider = wrapper.getByTestId('redux-provider');
expect(reduxProvider).toBeInTheDocument();
});

it('should render its children without a router', () => {
it('should render its children without a router', async () => {
const component = (
<AppProvider store={createStore(state => state)} wrapWithRouter={false}>
<div className="child">Child One</div>
Expand All @@ -75,16 +75,16 @@ describe('AppProvider', () => {
);

const wrapper = render(component);
const list = wrapper.container.querySelectorAll('div.child');
expect(list.length).toEqual(2);
expect(list[0].textContent).toEqual('Child One');
expect(list[1].textContent).toEqual('Child Two');
await waitFor(() => {
expect(screen.getByText('Child One')).toBeInTheDocument();
expect(screen.getByText('Child Two')).toBeInTheDocument();
});
expect(wrapper.queryByTestId('browser-router')).not.toBeInTheDocument();
const reduxProvider = wrapper.getByTestId('redux-provider');
expect(reduxProvider).toBeInTheDocument();
});

it('should skip redux Provider if not given a store', () => {
it('should skip redux Provider if not given a store', async () => {
const component = (
<AppProvider>
<div className="child">Child One</div>
Expand All @@ -93,11 +93,8 @@ describe('AppProvider', () => {
);

const wrapper = render(component);
const list = wrapper.container.querySelectorAll('div.child');
expect(list.length).toEqual(2);
expect(list[0].textContent).toEqual('Child One');
expect(list[1].textContent).toEqual('Child Two');

expect(screen.getByText('Child One')).toBeInTheDocument();
expect(screen.getByText('Child Two')).toBeInTheDocument();
const reduxProvider = wrapper.queryByTestId('redux-provider');
expect(reduxProvider).not.toBeInTheDocument();
});
Expand Down
39 changes: 16 additions & 23 deletions src/react/OptionalReduxProvider.jsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
/* eslint-disable import/no-extraneous-dependencies */
import { logError } from '@edx/frontend-platform/logging';
/* eslint-enable import/no-extraneous-dependencies */

function useProvider(store) {
const [Provider, setProvider] = useState(null);
const [Provider, setProvider] = useState(null); // Initially null to prevent render children that expect a Provider

useEffect(() => {
if (!store) {
setProvider(() => ({ children: c }) => c);
setProvider(() => ({ children }) => children); // Ensure fallback if no store
return;
}
if (process.env.NODE_ENV === 'test') {
// In test environments, load react-redux synchronously to avoid async state updates.
const loadProvider = async () => {
try {
// eslint-disable-next-line global-require
const module = require('react-redux');
setProvider(() => module.Provider);
} catch {
setProvider(() => ({ children: c }) => c);
const { Provider: ReactReduxProvider } = await import('react-redux');
// Set the Provider from react-redux
setProvider(() => ReactReduxProvider);
} catch (error) {
logError('Failed to load react-redux', error);
}
} else {
// In production, load react-redux dynamically.
import('react-redux')
.then((module) => {
setProvider(() => module.Provider);
})
.catch(() => {
setProvider(() => ({ children: c }) => c);
});
}
};
loadProvider();
}, [store]);

return Provider;
}

Expand All @@ -38,17 +34,14 @@ function useProvider(store) {
export default function OptionalReduxProvider({ store = null, children }) {
const Provider = useProvider(store);

// If the Provider is not loaded yet, we return null to avoid rendering issues
if (!Provider) {
return null;
}

// If the store is null, we return the children directly as no Provider is needed
if (store === null) {
if (!store) {
return children;
}

// If the Provider is loaded and the store is not null, we render the Provider with the children
return (
<Provider store={store}>
<div data-testid="redux-provider">
Expand Down

0 comments on commit 14d12e3

Please sign in to comment.