core-api: migrate AppContext to use version bridge
Co-authored-by: Juan Lulkin <jmaiz@spotify.com> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -47,6 +47,7 @@
|
||||
"@backstage/test-utils-core": "^0.1.1",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/react-hooks": "^3.3.0",
|
||||
"@testing-library/user-event": "^12.0.7",
|
||||
"@types/jest": "^26.0.7",
|
||||
"@types/node": "^14.14.32",
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useContext, Context } from 'react';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { VersionedValue } from '../lib/versionedValues';
|
||||
import { getGlobalSingleton } from '../lib/globalObject';
|
||||
import { AppContext as AppContextV1 } from './types';
|
||||
import { AppContextProvider } from './AppContext';
|
||||
|
||||
describe('v1 consumer', () => {
|
||||
const AppContext = getGlobalSingleton<
|
||||
Context<VersionedValue<{ 1: AppContextV1 }>>
|
||||
>('app-context');
|
||||
|
||||
function useMockAppV1(): AppContextV1 {
|
||||
const impl = useContext(AppContext)?.atVersion(1);
|
||||
if (!impl) {
|
||||
throw new Error('no impl');
|
||||
}
|
||||
return impl;
|
||||
}
|
||||
|
||||
it('should provide an app context', () => {
|
||||
const mockContext: AppContextV1 = {
|
||||
getComponents: jest.fn(),
|
||||
getSystemIcon: jest.fn(),
|
||||
getPlugins: jest.fn(),
|
||||
getProvider: jest.fn(),
|
||||
getRouter: jest.fn(),
|
||||
getRoutes: jest.fn(),
|
||||
};
|
||||
|
||||
const renderedHook = renderHook(() => useMockAppV1(), {
|
||||
wrapper: ({ children }) => (
|
||||
<AppContextProvider appContext={mockContext} children={children} />
|
||||
),
|
||||
});
|
||||
const result = renderedHook.result.current;
|
||||
|
||||
expect(mockContext.getComponents).toHaveBeenCalledTimes(0);
|
||||
result.getComponents();
|
||||
expect(mockContext.getComponents).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(mockContext.getSystemIcon).toHaveBeenCalledTimes(0);
|
||||
result.getSystemIcon('icon');
|
||||
expect(mockContext.getSystemIcon).toHaveBeenCalledTimes(1);
|
||||
expect(mockContext.getSystemIcon).toHaveBeenCalledWith('icon');
|
||||
|
||||
expect(mockContext.getPlugins).toHaveBeenCalledTimes(0);
|
||||
result.getPlugins();
|
||||
expect(mockContext.getPlugins).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(mockContext.getProvider).toHaveBeenCalledTimes(0);
|
||||
result.getProvider();
|
||||
expect(mockContext.getProvider).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(mockContext.getRouter).toHaveBeenCalledTimes(0);
|
||||
result.getRouter();
|
||||
expect(mockContext.getRouter).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(mockContext.getRoutes).toHaveBeenCalledTimes(0);
|
||||
result.getRoutes();
|
||||
expect(mockContext.getRoutes).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@@ -14,26 +14,47 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { createContext, PropsWithChildren, useContext } from 'react';
|
||||
import { AppContext } from './types';
|
||||
import React, {
|
||||
createContext,
|
||||
PropsWithChildren,
|
||||
useContext,
|
||||
Context,
|
||||
} from 'react';
|
||||
import {
|
||||
VersionedValue,
|
||||
createVersionedValueMap,
|
||||
} from '../lib/versionedValues';
|
||||
import { getGlobalSingleton, setGlobalSingleton } from '../lib/globalObject';
|
||||
import { AppContext as AppContextV1 } from './types';
|
||||
|
||||
const Context = createContext<AppContext | undefined>(undefined);
|
||||
type AppContextType = VersionedValue<{ 1: AppContextV1 }> | undefined;
|
||||
const AppContext = createContext<AppContextType | undefined>(undefined);
|
||||
|
||||
setGlobalSingleton('app-context', AppContext);
|
||||
|
||||
type Props = {
|
||||
appContext: AppContext;
|
||||
appContext: AppContextV1;
|
||||
};
|
||||
|
||||
export const AppContextProvider = ({
|
||||
appContext,
|
||||
children,
|
||||
}: PropsWithChildren<Props>) => (
|
||||
<Context.Provider value={appContext} children={children} />
|
||||
);
|
||||
}: PropsWithChildren<Props>) => {
|
||||
const versionedValue = createVersionedValueMap({ 1: appContext });
|
||||
|
||||
export const useApp = (): AppContext => {
|
||||
const appContext = useContext(Context);
|
||||
if (!appContext) {
|
||||
return <AppContext.Provider value={versionedValue} children={children} />;
|
||||
};
|
||||
|
||||
export const useApp = (): AppContextV1 => {
|
||||
const versionedContext = useContext(
|
||||
getGlobalSingleton<Context<AppContextType>>('app-context'),
|
||||
);
|
||||
if (!versionedContext) {
|
||||
throw new Error('No app context available');
|
||||
}
|
||||
const appContext = versionedContext.atVersion(1);
|
||||
if (!appContext) {
|
||||
throw new Error('AppContext v1 not available');
|
||||
}
|
||||
return appContext;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user