import { iconLoaded } from '@iconify/core/lib/storage/functions';
import {
fakeAPI,
nextPrefix,
setupDOM,
waitDOMReady,
resetState,
mockAPIData,
awaitUntil,
nextTick,
} from './helpers';
import { addBodyNode } from '../src/observer/root';
import { scanDOM } from '../src/scanner/index';
import { elementDataProperty } from '../src/scanner/config';
import { initObserver } from '../src/observer';
describe('Observing DOM changes', () => {
const provider = nextPrefix();
beforeAll(() => {
fakeAPI(provider);
});
afterEach(resetState);
it('Loading icon, transforming icon', async () => {
const prefix = nextPrefix();
const iconName = `@${provider}:${prefix}:home`;
// Add icon with API
expect(iconLoaded(iconName)).toBe(false);
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
home: {
body: '',
},
},
},
});
// Setup DOM and wait for it to be ready
setupDOM(``);
await waitDOMReady();
// Observe body
addBodyNode();
initObserver(scanDOM);
// Check HTML and data
expect(document.body.innerHTML).toBe(
``
);
// Wait for re-render
const placeholder = document.body.childNodes[0];
await awaitUntil(() => document.body.childNodes[0] !== placeholder);
// Check HTML
expect(document.body.innerHTML).toBe(
``
);
const svg = document.body.childNodes[0] as SVGSVGElement;
const svgData = svg[elementDataProperty];
expect(svgData.status).toBe('loaded');
expect(svgData.name).toEqual(iconName);
// Rotate icon
svg.setAttribute('data-rotate', '90deg');
// Wait for re-render
await awaitUntil(
() => document.body.innerHTML.indexOf('transform=') !== -1
);
expect(document.body.innerHTML).toBe(
``
);
});
it('Changing icon name after rendering first icon', async () => {
const prefix1 = nextPrefix();
const prefix2 = nextPrefix();
const iconName = `@${provider}:${prefix1}:home`;
const iconName2 = `@${provider}:${prefix2}:arrow`;
let sendSecondIcon = null;
// Add icon with API
expect(iconLoaded(iconName)).toBe(false);
expect(iconLoaded(iconName2)).toBe(false);
mockAPIData({
type: 'icons',
provider,
prefix: prefix1,
response: {
prefix: prefix1,
icons: {
home: {
body: '',
},
},
},
});
mockAPIData({
type: 'icons',
provider,
prefix: prefix2,
response: {
prefix: prefix2,
icons: {
arrow: {
body: '',
width: 24,
height: 24,
},
},
},
delay: (send) => {
sendSecondIcon = send;
},
});
// Setup DOM and wait for it to be ready
setupDOM(``);
await waitDOMReady();
// Observe body
addBodyNode();
initObserver(scanDOM);
// Check HTML and data
expect(document.body.innerHTML).toBe(
``
);
// Wait for re-render
const placeholder = document.body.childNodes[0];
await awaitUntil(() => document.body.childNodes[0] !== placeholder);
// Check HTML
expect(document.body.innerHTML).toBe(
``
);
const svg = document.body.childNodes[0] as SVGSVGElement;
const svgData = svg[elementDataProperty];
expect(svgData.status).toBe('loaded');
expect(svgData.name).toEqual(iconName);
// Chang icon name
svg.setAttribute('data-icon', iconName2);
// Wait for DOM to be scanned again and API query to be sent
await awaitUntil(() => sendSecondIcon !== null);
// SVG should not have been replaced yet, but data should match new icon
expect(document.body.innerHTML).toBe(
``
);
expect(document.body.childNodes[0]).toBe(svg);
expect(svgData.status).toBe('loading');
expect(svgData.name).toEqual(iconName2);
// Send API query
sendSecondIcon();
// Wait for re-render
await awaitUntil(
() => document.body.innerHTML.indexOf('M0 0v2') !== -1
);
expect(document.body.innerHTML).toBe(
``
);
});
it('Changing icon name while loading first icon', async () => {
const prefix1 = nextPrefix();
const prefix2 = nextPrefix();
const iconName = `@${provider}:${prefix1}:home`;
const iconName2 = `@${provider}:${prefix2}:arrow`;
let sendFirstIcon = null;
let sendSecondIcon = null;
// Add icon with API
expect(iconLoaded(iconName)).toBe(false);
expect(iconLoaded(iconName2)).toBe(false);
mockAPIData({
type: 'icons',
provider,
prefix: prefix1,
response: {
prefix: prefix1,
icons: {
home: {
body: '',
},
},
},
delay: (send) => {
sendFirstIcon = send;
},
});
mockAPIData({
type: 'icons',
provider,
prefix: prefix2,
response: {
prefix: prefix2,
icons: {
arrow: {
body: '',
width: 24,
height: 24,
},
},
},
delay: (send) => {
sendSecondIcon = send;
},
});
// Setup DOM and wait for it to be ready
setupDOM(``);
await waitDOMReady();
// Observe body
addBodyNode();
initObserver(scanDOM);
// Check HTML and data
expect(document.body.innerHTML).toBe(
``
);
// Wait for DOM to be scanned again and API query to be sent
await awaitUntil(() => sendFirstIcon !== null);
// Check HTML
expect(document.body.innerHTML).toBe(
``
);
const placeholder = document.body.childNodes[0] as HTMLSpanElement;
const placeholderData = placeholder[elementDataProperty];
expect(placeholderData.status).toBe('loading');
expect(placeholderData.name).toEqual(iconName);
// Chang icon name
placeholder.setAttribute('data-icon', iconName2);
// Wait for DOM to be scanned again and API query to be sent
await awaitUntil(() => sendSecondIcon !== null);
// SVG should not have been rendered yet, but data should match new icon
expect(document.body.innerHTML).toBe(
``
);
expect(document.body.childNodes[0]).toBe(placeholder);
expect(placeholderData.status).toBe('loading');
expect(placeholderData.name).toEqual(iconName2);
// Send first API query
sendFirstIcon();
await awaitUntil(() => iconLoaded(iconName));
// Wait a bit more
await nextTick([0, 0, 0]);
// Nothing should have changed
expect(document.body.innerHTML).toBe(
``
);
expect(document.body.childNodes[0]).toBe(placeholder);
expect(placeholderData.status).toBe('loading');
expect(placeholderData.name).toEqual(iconName2);
// Send second API query
sendSecondIcon();
// Wait for re-render
await awaitUntil(
() => document.body.innerHTML.indexOf('M0 0v2') !== -1
);
expect(document.body.innerHTML).toBe(
``
);
});
});