I am new to unit test cases, My project uses typescript with React. I would appreciate some help in writing the test cases for the following code for one of my components. I have been trying to write a test case to satisfy the two functions here getLogo and setupRegistry.Not being able to figure out the correct way to do that -
import {
getMediaToken,
isManifestRegistryItem,
MediaRegistryHelper,
RegistryItem,
SupportedRegistryMedia,
SvgUtils,
} from 'common';
import React, {
FunctionComponent,
useEffect,
useState,
useContext,
} from 'react';
import { Observable, of } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { downloadMedia, loadMediaRegistry } from '../media-registry';
import { LogoAssetContext } from '../media-context';
export interface RBCLogoProperties {
token: string;
srLabel: string;
}
type RBCLogoType = RBCLogoProperties & React.HTMLAttributes<HTMLLabelElement>;
export const RCLogo: FunctionComponent<RBCLogoType> = (props: RBCLogoType) => {
const { token, srLabel } = props;
const LOGOASSETREGISTRY = useContext(LogoAssetContext);
useEffect(() => {
setupRegistry(
LOGOASSETREGISTRY as Array<RegistryItem<SupportedRegistryMedia>>,
);
});
// Media Helper Instance to access the methods defined in media helper
const mediaHelperInstance = new MediaRegistryHelper();
// State to set the svg to html to show the logo
const [svg, setSVG] = useState<string>();
//Set up the registry for logo assets
const setupRegistry = (
registryConfig: Array<RegistryItem<SupportedRegistryMedia>>,
) => {
let config: Array<RegistryItem<SupportedRegistryMedia>> = [];
if (registryConfig && registryConfig.length > 0) {
const items = registryConfig;
config = [...config, ...items];
}
loadMediaRegistry?.('logo', config).subscribe(() => getLogo());
};
const getLogo = () => {
if (token) {
const logo = getMediaToken(token);
const registryItem = mediaHelperInstance?.getRegistryMediaItem(
'logo',
logo.scope || 'default',
);
let item$: Observable<RegistryItem<SupportedRegistryMedia> | undefined> =
of(registryItem);
if (isManifestRegistryItem(registryItem)) {
item$ = registryItem.data.pipe(
filter((v) => !!v),
map(() => registryItem),
);
}
const downLoadMediaResponse = downloadMedia('logo', logo);
downLoadMediaResponse
? downLoadMediaResponse.subscribe((data: any) => {
const svg = data as SVGElement;
setSVG(svg.outerHTML);
SvgUtils.setSvgAttributes(svg);
SvgUtils.addA11ytoSVG(
svg,
token,
srLabel ? srLabel : ' ',
document,
);
})
: console.log('Download Media Response is undefined for', token);
}
};
return (
<div
aria-label={srLabel}
dangerouslySetInnerHTML={{ __html: svg || '' }}
></div>
);
};
export default RCLogo;
Regarding unit testing of React components, you typically test the whole unit in terms of the component. You won't be able to test getLogo
and setupRegistry
(I assume it is what you have meant by setSubscription
? If not, you need to add a snippet for that function).
You can't test those specific functions because they are encapsulated within your component, and the test runner doesn't have access to them. More importantly, the test runner shouldn't have access to them since that would reveal the implementation detail of the component, and tests should be agnostic of that.
There is, however, a limited way to test functions inside the component, but only if the function is declared elsewhere and imported to the component. You can then use spy
to observe if the spied method has been called with what and how many times. Again you would use it only in specific cases (say you need to test that analytics event within the component has been only dispatched once, even if the component re-render etc..)
So, if I were to write a unit test for this component, I would have the following test cases:
I would not test getLogo
or any other encapsulated function because you care about the final SVG output.
So, you need three things from the code example you provided before testing this component.
There is also an argument about how much value the unit test brings to presentational components such as the logo that don't do anything other than display the image/svg.
Also, I would try to avoid using dangerously set HTML to render the SVG. Since it is returned as a string but also from the API call, I wouldn't trust the information returned from elsewhere to be used to set inner HTML. It exposes you to XSS attacks if svg is not actual svg.
I would use something like the below inside your div.
<img src={`data:image/svg+xml;utf8,${svg}`} />