Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import * as React from 'react';
import { BlueprintModernizationContext } from '@box/blueprint-web';
import { render } from '../../../test-utils/testing-library';
import { withBlueprintModernization } from '../withBlueprintModernization';

// Mock the Blueprint Web package with simple components
jest.mock('@box/blueprint-web', () => {
const ReactMock = jest.requireActual('react');
const mockContext = ReactMock.createContext({ enableModernizedComponents: false });

return {
BlueprintModernizationContext: mockContext,
BlueprintModernizationProvider: ({ children, enableModernizedComponents }) =>
ReactMock.createElement(
'div',
{
'data-testid': 'blueprint-provider',
'data-enabled': String(enableModernizedComponents),
},
children,
),
TooltipProvider: ({ children }) =>
ReactMock.createElement('div', { 'data-testid': 'tooltip-provider' }, children),
BlueprintModernizationContextValue: {},
};
});

type TestComponentProps = {
value?: string;
enableModernizedComponents?: boolean;
};

describe('src/elements/common/withBlueprintModernization', () => {
const TestComponent = ({ value }: TestComponentProps) => (
<div data-testid="test-component">{`Test ${value || 'default'}`}</div>
);

const WrappedComponent = withBlueprintModernization(TestComponent);

const renderComponent = (props?: TestComponentProps) => render(<WrappedComponent {...props} />);

test('should wrap component with BlueprintModernizationProvider', () => {
const { getByTestId } = renderComponent();

expect(getByTestId('test-component')).toBeInTheDocument();
expect(getByTestId('test-component')).toHaveTextContent('Test default');
expect(getByTestId('blueprint-provider')).toBeInTheDocument();
expect(getByTestId('blueprint-provider')).toHaveAttribute('data-enabled', 'false');
});

test('should pass props to wrapped component', () => {
const { getByTestId } = renderComponent({ value: 'test-value' });

expect(getByTestId('test-component')).toBeInTheDocument();
expect(getByTestId('test-component')).toHaveTextContent('Test test-value');
});

test('should handle enableModernizedComponents prop', () => {
const { getByTestId } = renderComponent({
value: 'modernized',
enableModernizedComponents: true,
});

expect(getByTestId('test-component')).toBeInTheDocument();
expect(getByTestId('test-component')).toHaveTextContent('Test modernized');
expect(getByTestId('blueprint-provider')).toBeInTheDocument();
expect(getByTestId('blueprint-provider')).toHaveAttribute('data-enabled', 'true');
});

test('should not wrap component when upstream BlueprintModernizationProvider exists', () => {
// Create a parent component with existing BlueprintModernizationContext
const ParentWithContext = ({ children }) => (
<BlueprintModernizationContext.Provider value={{ enableModernizedComponents: true }}>
{children}
</BlueprintModernizationContext.Provider>
);

const { getByTestId, queryByTestId } = render(
<ParentWithContext>
<WrappedComponent value="with-context" enableModernizedComponents={false} />
</ParentWithContext>,
);

// Component should render
expect(getByTestId('test-component')).toBeInTheDocument();
expect(getByTestId('test-component')).toHaveTextContent('Test with-context');

// HOC should NOT add its own BlueprintModernizationProvider since upstream context exists
expect(queryByTestId('blueprint-provider')).not.toBeInTheDocument();
});
});
24 changes: 24 additions & 0 deletions src/elements/common/withBlueprintModernization.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useContext } from 'react';
import {
BlueprintModernizationContext,
BlueprintModernizationContextValue,
BlueprintModernizationProvider,
} from '@box/blueprint-web';

export function withBlueprintModernization<P>(
Component: React.ComponentType<P & BlueprintModernizationContextValue>,
): React.FC<(P & BlueprintModernizationContextValue) | P> {
return function WithBlueprintModernization(props: P & BlueprintModernizationContextValue) {
const context = useContext(BlueprintModernizationContext);
// no context found from the parent component, so we need to provide our own
if (!context.enableModernizedComponents) {
return (
<BlueprintModernizationProvider enableModernizedComponents={!!props.enableModernizedComponents}>
<Component {...props} />
</BlueprintModernizationProvider>
);
}
// context found, so load the component with the existing context
return <Component {...props} />;
};
}
5 changes: 4 additions & 1 deletion src/elements/content-explorer/ContentExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import '../common/fonts.scss';
import '../common/base.scss';
import '../common/modal.scss';
import './ContentExplorer.scss';
import { withBlueprintModernization } from '../common/withBlueprintModernization';

const GRID_VIEW_MAX_COLUMNS = 7;
const GRID_VIEW_MIN_COLUMNS = 1;
Expand Down Expand Up @@ -1974,4 +1975,6 @@ class ContentExplorer extends Component<ContentExplorerProps, State> {
}

export { ContentExplorer as ContentExplorerComponent };
export default flow([makeResponsive, withFeatureConsumer, withFeatureProvider])(ContentExplorer);
export default flow([makeResponsive, withFeatureConsumer, withFeatureProvider, withBlueprintModernization])(
ContentExplorer,
);
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ export const basic = {
},
};

export const Modernization = {
args: {
enableModernizedComponents: true,
},
};

export const openExistingFolder = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
Expand Down
5 changes: 4 additions & 1 deletion src/elements/content-picker/ContentPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import React, { Component } from 'react';
import type { Node } from 'react';
import classNames from 'classnames';
import debounce from 'lodash/debounce';
import flow from 'lodash/flow';
import getProp from 'lodash/get';
import uniqueid from 'lodash/uniqueId';
import noop from 'lodash/noop';
Expand All @@ -18,6 +19,8 @@ import UploadDialog from '../common/upload-dialog';
import CreateFolderDialog from '../common/create-folder-dialog';
import Internationalize from '../common/Internationalize';
import makeResponsive from '../common/makeResponsive';
// $FlowFixMe
import { withBlueprintModernization } from '../common/withBlueprintModernization';
// $FlowFixMe TypeScript file
import ThemingStyles from '../common/theming';
import Pagination from '../../features/pagination';
Expand Down Expand Up @@ -1345,4 +1348,4 @@ class ContentPicker extends Component<Props, State> {
}

export { ContentPicker as ContentPickerComponent };
export default makeResponsive(ContentPicker);
export default flow([makeResponsive, withBlueprintModernization])(ContentPicker);
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import { DEFAULT_HOSTNAME_API } from '../../../../constants';

export const basic = {};

export const Modernization = {
args: {
enableModernizedComponents: true,
},
};

export const withPagination = {
args: {
initialPageSize: 1,
Expand Down
3 changes: 3 additions & 0 deletions src/elements/content-preview/ContentPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import { withLogger } from '../common/logger';
import { PREVIEW_FIELDS_TO_FETCH } from '../../utils/fields';
import { mark } from '../../utils/performance';
import { withFeatureConsumer, withFeatureProvider } from '../common/feature-checking';
// $FlowFixMe
import { withBlueprintModernization } from '../common/withBlueprintModernization';
import { EVENT_JS_READY } from '../common/logger/constants';
import ReloadNotification from './ReloadNotification';
import API from '../../api';
Expand Down Expand Up @@ -1418,6 +1420,7 @@ export default flow([
withNavRouter,
withFeatureConsumer,
withFeatureProvider,
withBlueprintModernization,
withLogger(ORIGIN_CONTENT_PREVIEW),
withErrorBoundary(ORIGIN_CONTENT_PREVIEW),
])(ContentPreview);
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ export const basic = {
},
};

export const Modernization = {
args: {
enableModernizedComponents: true,
},
};

export const closeModal = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
Expand Down Expand Up @@ -92,7 +98,7 @@ export const hoverOverCitation = {

expect(modal.getByText('Based on:')).toBeInTheDocument();

const citations = await modal.getAllByTestId('content-answers-citation-status')
const citations = await modal.getAllByTestId('content-answers-citation-status');
const citation = citations[0];
expect(citation).toBeInTheDocument();
await userEvent.hover(citation);
Expand Down
5 changes: 4 additions & 1 deletion src/elements/content-sharing/ContentSharing.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import 'regenerator-runtime/runtime';
import * as React from 'react';
import API from '../../api';
// $FlowFixMe
import { withBlueprintModernization } from '../common/withBlueprintModernization';
import SharingModal from './SharingModal';
import { CLIENT_NAME_CONTENT_SHARING, DEFAULT_HOSTNAME_API } from '../../constants';
import type { ItemType, StringMap } from '../../common/types/core';
Expand Down Expand Up @@ -118,4 +120,5 @@ function ContentSharing({
);
}

export default ContentSharing;
export { ContentSharing as ContentSharingComponent };
export default withBlueprintModernization(ContentSharing);
3 changes: 3 additions & 0 deletions src/elements/content-sidebar/ContentSidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { EVENT_JS_READY } from '../common/logger/constants';
import { mark } from '../../utils/performance';
import { SIDEBAR_FIELDS_TO_FETCH, SIDEBAR_FIELDS_TO_FETCH_ARCHIVE } from '../../utils/fields';
import { withErrorBoundary } from '../common/error-boundary';
// $FlowFixMe
import { withBlueprintModernization } from '../common/withBlueprintModernization';
import {
isFeatureEnabled as isFeatureEnabledInContext,
withFeatureConsumer,
Expand Down Expand Up @@ -432,6 +434,7 @@ export { ContentSidebar as ContentSidebarComponent };
export default flow([
withFeatureConsumer,
withFeatureProvider,
withBlueprintModernization,
withLogger(ORIGIN_CONTENT_SIDEBAR),
withErrorBoundary(ORIGIN_CONTENT_SIDEBAR),
])(ContentSidebar);
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export default {
},
};

export const Modernization = {
args: {
enableModernizedComponents: true,
},
};

export const ContentSidebarWithBoxAIDisabled: StoryObj<typeof BoxAISidebar> = {
args: {
features: {
Expand Down
4 changes: 3 additions & 1 deletion src/elements/content-uploader/ContentUploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'regenerator-runtime/runtime';
import React, { Component } from 'react';
import classNames from 'classnames';
import cloneDeep from 'lodash/cloneDeep';
import flow from 'lodash/flow';
import getProp from 'lodash/get';
import noop from 'lodash/noop';
import uniqueid from 'lodash/uniqueId';
Expand All @@ -14,6 +15,7 @@ import API from '../../api';
import Browser from '../../utils/Browser';
import Internationalize from '../common/Internationalize';
import makeResponsive from '../common/makeResponsive';
import { withBlueprintModernization } from '../common/withBlueprintModernization';
import ThemingStyles, { Theme } from '../common/theming';
import FolderUpload from '../../api/uploads/FolderUpload';
import { getTypedFileId, getTypedFolderId } from '../../utils/file';
Expand Down Expand Up @@ -1323,5 +1325,5 @@ class ContentUploader extends Component<ContentUploaderProps, State> {
}
}

export default makeResponsive(ContentUploader);
export default flow([makeResponsive, withBlueprintModernization])(ContentUploader);
export { ContentUploader as ContentUploaderComponent, CHUNKED_UPLOAD_MIN_SIZE_BYTES };
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export const basic = {
},
};

export const Modernization = {
args: {
enableModernizedComponents: true,
},
};

export const singleUpload = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
Expand Down