import {
describe, it, expect,
} from 'vitest';
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import AppIcon from '@/presentation/components/Shared/Icon/AppIcon.vue';
import { IconName } from '@/presentation/components/Shared/Icon/IconName';
import { UseSvgLoaderStub } from '@tests/unit/shared/Stubs/UseSvgLoaderStub';
import { formatAssertionMessage } from '@tests/shared/FormatAssertionMessage';
describe('AppIcon.vue', () => {
it('renders the correct SVG content based on the icon prop', async () => {
// arrange
const expectedIconName: IconName = 'magnifying-glass';
const expectedIconContent = '';
const svgLoaderStub = new UseSvgLoaderStub();
svgLoaderStub.withSvgIcon(expectedIconName, expectedIconContent);
// act
const wrapper = mountComponent({
iconPropValue: expectedIconName,
loader: svgLoaderStub,
});
await nextTick();
// assert
const actualSvg = wrapper.html();
expectSvg(actualSvg, expectedIconContent);
});
it('updates the SVG content when the icon prop changes', async () => {
// arrange
const initialIconName: IconName = 'magnifying-glass';
const updatedIconName: IconName = 'copy';
const updatedIconContent = '';
const svgLoaderStub = new UseSvgLoaderStub();
svgLoaderStub.withSvgIcon(initialIconName, '');
svgLoaderStub.withSvgIcon(updatedIconName, updatedIconContent);
// act
const wrapper = mountComponent({
iconPropValue: initialIconName,
loader: svgLoaderStub,
});
await wrapper.setProps({ icon: updatedIconName });
await nextTick();
// assert
const actualSvg = wrapper.html();
expectSvg(actualSvg, updatedIconContent);
});
it('emits `click` event when clicked', async () => {
// arrange
const wrapper = mountComponent();
// act
await wrapper.trigger('click');
await nextTick();
// assert
expect(wrapper.emitted().click).to.have.lengthOf(1);
});
});
function mountComponent(options?: {
readonly iconPropValue?: IconName,
readonly loader?: UseSvgLoaderStub,
}) {
const iconName = options?.iconPropValue ?? 'globe';
const loaderStub = options?.loader ?? new UseSvgLoaderStub().withSvgIcon(iconName, '');
return shallowMount(AppIcon, {
props: {
icon: iconName,
},
global: {
provide: {
useSvgLoaderHook: loaderStub.get(),
},
},
});
}
function expectSvg(actualSvg: string, expectedSvg: string): ReturnType {
const normalizedExpectedSvg = extractAndNormalizeSvg(expectedSvg);
const normalizedActualSvg = extractAndNormalizeSvg(actualSvg);
return expect(normalizedActualSvg).to.equal(normalizedExpectedSvg, formatAssertionMessage([
'Expected:\n', normalizedExpectedSvg,
'Actual:\n', normalizedActualSvg,
]));
}
function extractAndNormalizeSvg(svgString: string): string {
const svg = extractSvg(svgString);
return normalizeSvg(svg);
}
function extractSvg(svgString: string): string {
const svgMatches = svgString.match(/