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:
Patrik Oldsberg
2021-03-09 11:16:10 +01:00
parent d5c8bc8a01
commit 0095873736
3 changed files with 111 additions and 10 deletions
+1
View File
@@ -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);
});
});
+31 -10
View File
@@ -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;
};