Last active
September 20, 2022 17:12
-
-
Save theer1k/01198111f72bff068beb84ca5d2adc92 to your computer and use it in GitHub Desktop.
Componser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Context, createContext, useContext } from 'react'; | |
import { render, screen } from '@/test/testUtils'; | |
import { ComponentWithChildren, composer } from '.'; | |
type ContextTuple = [Context<string>, ComponentWithChildren]; | |
const createMockContext = (value: string): ContextTuple => { | |
const MockContext: Context<string> = createContext(''); | |
const MockContextProvider: ComponentWithChildren = ({ children }) => ( | |
<MockContext.Provider value={value}>{children}</MockContext.Provider> | |
); | |
return [MockContext, MockContextProvider]; | |
}; | |
const [MockContext1, MockContextProvider1] = createMockContext('context 1'); | |
const [MockContext2, MockContextProvider2] = createMockContext('context 2'); | |
const NestedContext = createContext(''); | |
const NestedContextProvider: ComponentWithChildren = ({ children }) => { | |
const nestedValue = useContext(MockContext1); | |
return ( | |
<NestedContext.Provider value={nestedValue}> | |
{children} | |
</NestedContext.Provider> | |
); | |
}; | |
const MockComponent = () => { | |
const contextValue1 = useContext(MockContext1); | |
const contextValue2 = useContext(MockContext2); | |
const nestedContextValue = useContext(NestedContext); | |
return ( | |
<> | |
<p>{contextValue1}</p> | |
<p>{contextValue2}</p> | |
{nestedContextValue && ( | |
<p data-testid="nestedValue">{nestedContextValue}</p> | |
)} | |
</> | |
); | |
}; | |
describe('composer', () => { | |
it('Should pass multiple context values to its children', () => { | |
const ComposedProvider = composer( | |
MockContextProvider1, | |
MockContextProvider2, | |
); | |
render( | |
<ComposedProvider> | |
<MockComponent /> | |
</ComposedProvider>, | |
); | |
const contextValue1 = screen.getByText('context 1'); | |
const contextValue2 = screen.getByText('context 2'); | |
expect(contextValue1).toBeInTheDocument(); | |
expect(contextValue2).toBeInTheDocument(); | |
}); | |
it('Should render multiple contexts from left to right', () => { | |
const ComposedProvider = composer( | |
MockContextProvider1, | |
MockContextProvider2, | |
NestedContextProvider, | |
); | |
render( | |
<ComposedProvider> | |
<MockComponent /> | |
</ComposedProvider>, | |
); | |
const contextValue1 = screen.getAllByText('context 1'); | |
const contextValue2 = screen.getByText('context 2'); | |
const nestedValue = screen.queryByTestId('nestedValue'); | |
expect(contextValue1).toHaveLength(2); | |
expect(contextValue2).toBeInTheDocument(); | |
expect(nestedValue).toBeInTheDocument(); | |
}); | |
it('Should fail to render contexts in the wrong order', () => { | |
const ComposedProvider = composer( | |
NestedContextProvider, | |
MockContextProvider1, | |
MockContextProvider2, | |
); | |
render( | |
<ComposedProvider> | |
<MockComponent /> | |
</ComposedProvider>, | |
); | |
const contextValue1 = screen.getByText('context 1'); | |
const contextValue2 = screen.getByText('context 2'); | |
const nestedValue = screen.queryByTestId('nestedValue'); | |
expect(contextValue1).toBeInTheDocument(); | |
expect(contextValue2).toBeInTheDocument(); | |
expect(nestedValue).not.toBeInTheDocument(); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ReactNode } from 'react'; | |
export type ComponentWithChildren = (props: { | |
children: ReactNode; | |
}) => JSX.Element; | |
export const composer = (...providers: ComponentWithChildren[]) => { | |
const ComposedComponents: ComponentWithChildren = ({ children }) => { | |
return ( | |
<> | |
{providers.reduceRight( | |
(child, Provider) => ( | |
<Provider>{child}</Provider> | |
), | |
children, | |
)} | |
</> | |
); | |
}; | |
return ComposedComponents; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment