2
0
mirror of https://github.com/iconify/iconify.git synced 2025-01-22 14:48:24 +00:00

Update dependencies in icon components

This commit is contained in:
Vjacheslav Trushkin 2022-09-07 22:11:48 +03:00
parent 286a623085
commit 0ec3270dc1
12 changed files with 1060 additions and 1023 deletions

View File

@ -25,18 +25,18 @@
"devDependencies": { "devDependencies": {
"@iconify/core": "workspace:^", "@iconify/core": "workspace:^",
"@iconify/utils": "workspace:^", "@iconify/utils": "workspace:^",
"@microsoft/api-extractor": "^7.25.2", "@microsoft/api-extractor": "^7.30.0",
"@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-node-resolve": "^14.0.0",
"@rollup/plugin-typescript": "^8.3.3", "@rollup/plugin-typescript": "^8.5.0",
"rollup": "^2.75.6", "rollup": "^2.79.0",
"typescript": "^4.7.4" "typescript": "^4.8.2"
}, },
"dependencies": { "dependencies": {
"@glimmer/component": "^1.1.2", "@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2", "@glimmer/tracking": "^1.1.2",
"@iconify/types": "workspace:^", "@iconify/types": "workspace:^",
"ember-cli-babel": "^7.26.11", "ember-cli-babel": "^7.26.11",
"ember-cli-htmlbars": "^6.0.1" "ember-cli-htmlbars": "^6.1.0"
}, },
"ember": { "ember": {
"edition": "octane" "edition": "octane"

View File

@ -48,20 +48,20 @@
"@iconify/types": "workspace:^" "@iconify/types": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
"@babel/preset-env": "^7.18.2", "@babel/preset-env": "^7.19.0",
"@babel/preset-react": "^7.17.12", "@babel/preset-react": "^7.18.6",
"@iconify/core": "workspace:^", "@iconify/core": "workspace:^",
"@iconify/utils": "workspace:^", "@iconify/utils": "workspace:^",
"@microsoft/api-extractor": "^7.25.2", "@microsoft/api-extractor": "^7.30.0",
"@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-node-resolve": "^14.0.0",
"@types/react": "^17.0.47", "@types/react": "^17.0.49",
"babel-jest": "^27.5.1", "babel-jest": "^29.0.2",
"jest": "^28.1.1", "jest": "^29.0.2",
"react": "^17.0.2", "react": "^18.2.0",
"react-test-renderer": "^17.0.2", "react-test-renderer": "^18.2.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.75.6", "rollup": "^2.79.0",
"typescript": "^4.7.4" "typescript": "^4.8.2"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=16" "react": ">=16"

View File

@ -74,22 +74,22 @@
"devDependencies": { "devDependencies": {
"@iconify/core": "workspace:^", "@iconify/core": "workspace:^",
"@iconify/utils": "workspace:^", "@iconify/utils": "workspace:^",
"@microsoft/api-extractor": "^7.25.2", "@microsoft/api-extractor": "^7.30.0",
"@rollup/plugin-buble": "^0.21.3", "@rollup/plugin-buble": "^0.21.3",
"@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-node-resolve": "^14.0.0",
"@rollup/plugin-replace": "^4.0.0", "@rollup/plugin-replace": "^4.0.0",
"@types/jest": "^27.5.2", "@types/jest": "^29.0.0",
"@types/jsdom": "^16.2.14", "@types/jsdom": "^20.0.0",
"@types/node": "^17.0.45", "@types/node": "^18.7.15",
"@typescript-eslint/eslint-plugin": "^5.28.0", "@typescript-eslint/eslint-plugin": "^5.36.2",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^8.18.0", "eslint": "^8.23.0",
"jest": "^28.1.1", "jest": "^29.0.2",
"jsdom": "^19.0.0", "jsdom": "^20.0.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.75.6", "rollup": "^2.79.0",
"rollup-plugin-terser": "^7.0.2", "rollup-plugin-terser": "^7.0.2",
"ts-jest": "28.0.0-next.3", "ts-jest": "^29.0.0-next.1",
"typescript": "^4.7.4" "typescript": "^4.8.2"
} }
} }

View File

@ -4,21 +4,25 @@ import { onReady } from '../src/helpers/ready';
describe('Testing onReady callback', () => { describe('Testing onReady callback', () => {
afterEach(cleanupGlobals); afterEach(cleanupGlobals);
it('Testing onReady before DOM is loaded', (done) => { it('Testing onReady before DOM is loaded', () => {
setupDOM(''); return new Promise((fulfill) => {
expect(document.readyState).toBe('loading'); setupDOM('');
onReady(() => { expect(document.readyState).toBe('loading');
done(); onReady(() => {
fulfill(true);
});
}); });
}); });
it('Testing onReady after DOM is loaded', (done) => { it('Testing onReady after DOM is loaded', () => {
setupDOM(''); return new Promise((fulfill) => {
expect(document.readyState).toBe('loading'); setupDOM('');
document.addEventListener('DOMContentLoaded', () => { expect(document.readyState).toBe('loading');
expect(document.readyState).toBe('interactive'); document.addEventListener('DOMContentLoaded', () => {
onReady(() => { expect(document.readyState).toBe('interactive');
done(); onReady(() => {
fulfill(true);
});
}); });
}); });
}); });

View File

@ -45,19 +45,19 @@
"@iconify/types": "workspace:^" "@iconify/types": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
"@babel/preset-env": "^7.18.2", "@babel/preset-env": "^7.19.0",
"@iconify/core": "workspace:^", "@iconify/core": "workspace:^",
"@iconify/utils": "workspace:^", "@iconify/utils": "workspace:^",
"@microsoft/api-extractor": "^7.25.2", "@microsoft/api-extractor": "^7.30.0",
"@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-node-resolve": "^14.0.0",
"@types/jest": "^27.5.2", "@types/jest": "^29.0.0",
"@vitejs/plugin-vue": "^2.3.3", "@vitejs/plugin-vue": "^3.1.0",
"@vue/test-utils": "^2.0.1", "@vue/test-utils": "^2.0.2",
"jsdom": "^19.0.0", "jsdom": "^20.0.0",
"rollup": "^2.75.6", "rollup": "^2.79.0",
"typescript": "^4.7.4", "typescript": "^4.8.2",
"vitest": "^0.7.13", "vitest": "^0.23.1",
"vue": "^3.2.37" "vue": "^3.2.38"
}, },
"peerDependencies": { "peerDependencies": {
"vue": ">=3" "vue": ">=3"

View File

@ -3,39 +3,41 @@ import { mockAPIData } from '@iconify/core/lib/api/modules/mock';
import { provider, nextPrefix } from './load'; import { provider, nextPrefix } from './load';
describe('Testing fake API', () => { describe('Testing fake API', () => {
test('using fake API to load icon', (done) => { test('using fake API to load icon', () => {
const prefix = nextPrefix(); return new Promise((fulfill) => {
const name = 'mock-test'; const prefix = nextPrefix();
const iconName = `@${provider}:${prefix}:${name}`; const name = 'mock-test';
mockAPIData({ const iconName = `@${provider}:${prefix}:${name}`;
type: 'icons', mockAPIData({
provider, type: 'icons',
prefix, provider,
response: {
prefix, prefix,
icons: { response: {
[name]: { prefix,
body: '<g />', icons: {
[name]: {
body: '<g />',
},
}, },
}, },
}, });
});
// Check if icon has been loaded // Check if icon has been loaded
expect(iconExists(iconName)).toEqual(false); expect(iconExists(iconName)).toEqual(false);
// Load icon // Load icon
loadIcons([iconName], (loaded, missing, pending) => { loadIcons([iconName], (loaded, missing, pending) => {
expect(loaded).toMatchObject([ expect(loaded).toMatchObject([
{ {
provider, provider,
prefix, prefix,
name, name,
}, },
]); ]);
expect(missing).toMatchObject([]); expect(missing).toMatchObject([]);
expect(pending).toMatchObject([]); expect(pending).toMatchObject([]);
done(); fulfill(true);
});
}); });
}); });
}); });

View File

@ -12,204 +12,210 @@ const iconData = {
}; };
describe('Rendering icon', () => { describe('Rendering icon', () => {
test('rendering icon after loading it', (done) => { test('rendering icon after loading it', () => {
const prefix = nextPrefix(); return new Promise((fulfill, reject) => {
const name = 'render-test'; const prefix = nextPrefix();
const iconName = `@${provider}:${prefix}:${name}`; const name = 'render-test';
const className = `iconify iconify--${prefix} iconify--${provider}`; const iconName = `@${provider}:${prefix}:${name}`;
let onLoadCalled = false; const className = `iconify iconify--${prefix} iconify--${provider}`;
let onLoadCalled = false;
mockAPIData({ mockAPIData({
type: 'icons', type: 'icons',
provider, provider,
prefix,
response: {
prefix, prefix,
icons: { response: {
[name]: iconData,
},
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toEqual(false);
// Load icon
loadIcons([iconName], (loaded, missing, pending) => {
// Make sure icon has been loaded
expect(loaded).toMatchObject([
{
provider,
prefix, prefix,
name, icons: {
[name]: iconData,
},
}, },
]); });
expect(missing).toMatchObject([]);
expect(pending).toMatchObject([]); // Check if icon has been loaded
expect(iconExists(iconName)).toEqual(true); expect(iconExists(iconName)).toEqual(false);
// Load icon
loadIcons([iconName], (loaded, missing, pending) => {
// Make sure icon has been loaded
expect(loaded).toMatchObject([
{
provider,
prefix,
name,
},
]);
expect(missing).toMatchObject([]);
expect(pending).toMatchObject([]);
expect(iconExists(iconName)).toEqual(true);
// Render component
const Wrapper = {
components: { Icon },
// Also test class string
template: `<Icon icon="${iconName}" :onLoad="onLoad" class="test" />`,
methods: {
onLoad(name) {
expect(name).toEqual(iconName);
expect(onLoadCalled).toEqual(false);
onLoadCalled = true;
},
},
};
const wrapper = mount(Wrapper, {});
// Check HTML on next tick
nextTick()
.then(() => {
const html = wrapper.html().replace(/\s*\n\s*/g, '');
expect(html).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="test ' +
className +
'" width="1em" height="1em" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
// Make sure onLoad has been called
expect(onLoadCalled).toEqual(true);
fulfill(true);
})
.catch(reject);
});
});
});
test('rendering icon before loading it', () => {
return new Promise((fulfill, reject) => {
const prefix = nextPrefix();
const name = 'mock-test';
const iconName = `@${provider}:${prefix}:${name}`;
const className = `iconify iconify--${prefix} iconify--${provider}`;
let onLoadCalled = false;
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
},
},
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toEqual(false);
// onLoad should not have been called yet
expect(onLoadCalled).toEqual(false);
// Send icon data
next();
// Test it again
expect(iconExists(iconName)).toEqual(true);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toEqual(false);
// Render component // Render component
const Wrapper = { const Wrapper = {
components: { Icon }, components: { Icon },
// Also test class string template: `<Icon icon="${iconName}" :onLoad="onLoad" :class="testClass" />`,
template: `<Icon icon="${iconName}" :onLoad="onLoad" class="test" />`,
methods: { methods: {
onLoad(name) { onLoad(name) {
expect(name).toEqual(iconName); expect(name).toEqual(iconName);
expect(onLoadCalled).toEqual(false); expect(onLoadCalled).toEqual(false);
onLoadCalled = true; onLoadCalled = true;
// Test component on next tick
nextTick()
.then(() => {
// Check HTML
expect(
wrapper.html().replace(/\s*\n\s*/g, '')
).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="foo ' +
className +
'" width="1em" height="1em" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
fulfill(true);
})
.catch(reject);
}, },
}, },
data() {
// Test dynamic class
return {
testClass: {
foo: true,
bar: false,
},
};
},
}; };
const wrapper = mount(Wrapper, {}); const wrapper = mount(Wrapper, {});
// Check HTML on next tick // onLoad should not have been called yet
nextTick() expect(onLoadCalled).toEqual(false);
.then(() => {
const html = wrapper.html().replace(/\s*\n\s*/g, '');
expect(html).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="test ' +
className +
'" width="1em" height="1em" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
// Make sure onLoad has been called
expect(onLoadCalled).toEqual(true);
done();
})
.catch(done);
}); });
}); });
test('rendering icon before loading it', (done) => { test('missing icon', () => {
const prefix = nextPrefix(); return new Promise((fulfill, reject) => {
const name = 'mock-test'; const prefix = nextPrefix();
const iconName = `@${provider}:${prefix}:${name}`; const name = 'missing-icon';
const className = `iconify iconify--${prefix} iconify--${provider}`; const iconName = `@${provider}:${prefix}:${name}`;
let onLoadCalled = false; mockAPIData({
type: 'icons',
mockAPIData({ provider,
type: 'icons',
provider,
prefix,
response: {
prefix, prefix,
icons: { response: 404,
[name]: iconData, delay: (next) => {
}, // Icon should not have loaded yet
}, expect(iconExists(iconName)).toEqual(false);
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toEqual(false);
// onLoad should not have been called yet // Send icon data
expect(onLoadCalled).toEqual(false); next();
// Send icon data // Test it again
next(); expect(iconExists(iconName)).toEqual(false);
// Test it again // Check if state was changed on next few ticks
expect(iconExists(iconName)).toEqual(true);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toEqual(false);
// Render component
const Wrapper = {
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad="onLoad" :class="testClass" />`,
methods: {
onLoad(name) {
expect(name).toEqual(iconName);
expect(onLoadCalled).toEqual(false);
onLoadCalled = true;
// Test component on next tick
nextTick() nextTick()
.then(() => { .then(() => {
// Check HTML expect(wrapper.html()).toEqual(defaultIconResult);
expect( return nextTick();
wrapper.html().replace(/\s*\n\s*/g, '')
).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="foo ' +
className +
'" width="1em" height="1em" viewBox="0 0 24 24"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
done();
}) })
.catch(done); .then(() => {
expect(wrapper.html()).toEqual(defaultIconResult);
return nextTick();
})
.then(() => {
expect(wrapper.html()).toEqual(defaultIconResult);
fulfill(true);
})
.catch(reject);
}, },
}, });
data() {
// Test dynamic class // Check if icon has been loaded
return { expect(iconExists(iconName)).toEqual(false);
testClass: {
foo: true, // Render component
bar: false, const Wrapper = {
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
methods: {
onLoad() {
throw new Error('onLoad called for empty icon!');
}, },
};
},
};
const wrapper = mount(Wrapper, {});
// onLoad should not have been called yet
expect(onLoadCalled).toEqual(false);
});
test('missing icon', (done) => {
const prefix = nextPrefix();
const name = 'missing-icon';
const iconName = `@${provider}:${prefix}:${name}`;
mockAPIData({
type: 'icons',
provider,
prefix,
response: 404,
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toEqual(false);
// Send icon data
next();
// Test it again
expect(iconExists(iconName)).toEqual(false);
// Check if state was changed on next few ticks
nextTick()
.then(() => {
expect(wrapper.html()).toEqual(defaultIconResult);
return nextTick();
})
.then(() => {
expect(wrapper.html()).toEqual(defaultIconResult);
return nextTick();
})
.then(() => {
expect(wrapper.html()).toEqual(defaultIconResult);
done();
})
.catch(done);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toEqual(false);
// Render component
const Wrapper = {
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad='onLoad' />`,
methods: {
onLoad() {
throw new Error('onLoad called for empty icon!');
}, },
}, };
}; const wrapper = mount(Wrapper, {});
const wrapper = mount(Wrapper, {}); });
}); });
}); });

View File

@ -17,318 +17,324 @@ const iconData2 = {
}; };
describe('Rendering icon', () => { describe('Rendering icon', () => {
test('changing icon property', (done) => { test('changing icon property', () => {
const prefix = nextPrefix(); return new Promise((fulfill, reject) => {
const name = 'changing-prop'; const prefix = nextPrefix();
const name2 = 'changing-prop2'; const name = 'changing-prop';
const iconName = `@${provider}:${prefix}:${name}`; const name2 = 'changing-prop2';
const iconName2 = `@${provider}:${prefix}:${name2}`; const iconName = `@${provider}:${prefix}:${name}`;
const className = `iconify iconify--${prefix} iconify--${provider}`; const iconName2 = `@${provider}:${prefix}:${name2}`;
let onLoadCalled = ''; // Name of icon from last onLoad call const className = `iconify iconify--${prefix} iconify--${provider}`;
let onLoadCalled = ''; // Name of icon from last onLoad call
const onLoad = (name) => { const onLoad = (name) => {
// onLoad should be called only once per icon // onLoad should be called only once per icon
switch (name) { switch (name) {
// First onLoad call // First onLoad call
case iconName: case iconName:
expect(onLoadCalled).toEqual('');
// Wait 1 tick, then test rendered icon
nextTick()
.then(() => {
expect(
wrapper.html().replace(/\s*\n\s*/g, '')
).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className +
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
wrapper.setProps({
icon: iconName2,
});
})
.catch(reject);
break;
// Second onLoad call
case iconName2:
expect(onLoadCalled).toEqual(iconName);
// Wait 1 tick, then test rendered icon
nextTick()
.then(() => {
expect(
wrapper.html().replace(/\s*\n\s*/g, '')
).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 32 32" class="' +
className +
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
);
fulfill(true);
})
.catch(reject);
break;
default:
throw new Error(`Unexpected onLoad('${name}') call`);
}
onLoadCalled = name;
};
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
},
},
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toEqual(false);
// onLoad should not have been called yet
expect(onLoadCalled).toEqual(''); expect(onLoadCalled).toEqual('');
// Wait 1 tick, then test rendered icon // Send icon data
nextTick() next();
.then(() => {
expect(
wrapper.html().replace(/\s*\n\s*/g, '')
).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className +
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
wrapper.setProps({ // Make sure icon data is available
icon: iconName2, expect(iconExists(iconName)).toEqual(true);
}); },
}) });
.catch(done);
break; mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name2]: iconData2,
},
},
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName2)).toEqual(false);
// Second onLoad call // onLoad should have been called only once for previous icon
case iconName2:
expect(onLoadCalled).toEqual(iconName); expect(onLoadCalled).toEqual(iconName);
// Wait 1 tick, then test rendered icon // Send icon data
nextTick() next();
.then(() => {
expect(
wrapper.html().replace(/\s*\n\s*/g, '')
).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 32 32" class="' +
className +
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
);
done(); // Make sure icon data is available
}) expect(iconExists(iconName2)).toEqual(true);
.catch(done);
break;
default:
throw new Error(`Unexpected onLoad('${name}') call`);
}
onLoadCalled = name;
};
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
}, },
}, });
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toEqual(false);
// onLoad should not have been called yet // Check if icon has been loaded
expect(onLoadCalled).toEqual(''); expect(iconExists(iconName)).toEqual(false);
// Send icon data // Render component
next(); const Wrapper = {
components: { Icon },
// Make sure icon data is available template: `<Icon icon="${iconName}" :onLoad="onLoad" />`,
expect(iconExists(iconName)).toEqual(true); methods: {
}, onLoad,
});
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name2]: iconData2,
}, },
}, };
delay: (next) => { const wrapper = mount(Wrapper, {});
// Icon should not have loaded yet
expect(iconExists(iconName2)).toEqual(false);
// onLoad should have been called only once for previous icon // onLoad should not have been called yet
expect(onLoadCalled).toEqual(iconName); expect(onLoadCalled).toEqual('');
// Send icon data
next();
// Make sure icon data is available
expect(iconExists(iconName2)).toEqual(true);
},
}); });
// Check if icon has been loaded
expect(iconExists(iconName)).toEqual(false);
// Render component
const Wrapper = {
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad="onLoad" />`,
methods: {
onLoad,
},
};
const wrapper = mount(Wrapper, {});
// onLoad should not have been called yet
expect(onLoadCalled).toEqual('');
}); });
test('changing icon property while loading', (done) => { test('changing icon property while loading', () => {
const prefix = nextPrefix(); return new Promise((fulfill, reject) => {
const name = 'changing-prop'; const prefix = nextPrefix();
const name2 = 'changing-prop2'; const name = 'changing-prop';
const iconName = `@${provider}:${prefix}:${name}`; const name2 = 'changing-prop2';
const iconName2 = `@${provider}:${prefix}:${name2}`; const iconName = `@${provider}:${prefix}:${name}`;
const className = `iconify iconify--${prefix} iconify--${provider}`; const iconName2 = `@${provider}:${prefix}:${name2}`;
let isSync = true; const className = `iconify iconify--${prefix} iconify--${provider}`;
let isSync = true;
const onLoad = (name) => { const onLoad = (name) => {
switch (name) { switch (name) {
case iconName: case iconName:
done('onLoad should not be called for initial icon'); reject('onLoad should not be called for initial icon');
break; break;
case iconName2: case iconName2:
// Wait 1 tick, then test rendered icon // Wait 1 tick, then test rendered icon
nextTick() nextTick()
.then(() => { .then(() => {
expect( expect(
wrapper.html().replace(/\s*\n\s*/g, '') wrapper.html().replace(/\s*\n\s*/g, '')
).toEqual( ).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 32 32" class="' + '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 32 32" class="' +
className + className +
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>' '"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
); );
done(); fulfill(true);
}) })
.catch(done); .catch(reject);
break; break;
default: default:
throw new Error(`Unexpected onLoad('${name}') call`); throw new Error(`Unexpected onLoad('${name}') call`);
}
};
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
},
},
delay: (next) => {
// Should have been called asynchronously, which means icon name has changed
expect(isSync).toEqual(false);
// Send icon data
next();
},
});
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name2]: iconData2,
},
},
delay: (next) => {
// Should have been called asynchronously
expect(isSync).toEqual(false);
// Icon should not have loaded yet
expect(iconExists(iconName2)).toEqual(false);
// Send icon data
next();
// Make sure icon was loaded
expect(iconExists(iconName2)).toEqual(true);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toEqual(false);
// Render component
const Wrapper = {
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad="onLoad" />`,
methods: {
onLoad,
},
};
const wrapper = mount(Wrapper, {});
// Change icon name
wrapper.setProps({
icon: iconName2,
});
// Async
isSync = false;
});
test('changing multiple properties', (done) => {
const prefix = nextPrefix();
const name = 'multiple-props';
const iconName = `@${provider}:${prefix}:${name}`;
const className = `iconify iconify--${prefix} iconify--${provider}`;
const onLoad = (name) => {
expect(name).toBe(iconName);
(async () => {
try {
// Wait 1 tick, test rendered icon
await nextTick();
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className +
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
// Add horizontal flip and style
wrapper.setProps({
icon: iconName,
hFlip: true,
style: {
color: 'red',
},
});
// Wait 1 tick
await nextTick();
// Test
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className +
'" style="color: red;"><g transform="translate(24 0) scale(-1 1)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
);
done();
} catch (err) {
done(err);
} }
})(); };
};
mockAPIData({ mockAPIData({
type: 'icons', type: 'icons',
provider, provider,
prefix,
response: {
prefix, prefix,
icons: { response: {
[name]: iconData, prefix,
icons: {
[name]: iconData,
},
}, },
}, delay: (next) => {
delay: (next) => { // Should have been called asynchronously, which means icon name has changed
// Icon should not have loaded yet expect(isSync).toEqual(false);
expect(iconExists(iconName)).toEqual(false);
// Send icon data // Send icon data
next(); next();
},
});
// Make sure icon was loaded mockAPIData({
expect(iconExists(iconName)).toEqual(true); type: 'icons',
}, provider,
prefix,
response: {
prefix,
icons: {
[name2]: iconData2,
},
},
delay: (next) => {
// Should have been called asynchronously
expect(isSync).toEqual(false);
// Icon should not have loaded yet
expect(iconExists(iconName2)).toEqual(false);
// Send icon data
next();
// Make sure icon was loaded
expect(iconExists(iconName2)).toEqual(true);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toEqual(false);
// Render component
const Wrapper = {
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad="onLoad" />`,
methods: {
onLoad,
},
};
const wrapper = mount(Wrapper, {});
// Change icon name
wrapper.setProps({
icon: iconName2,
});
// Async
isSync = false;
}); });
});
// Check if icon has been loaded test('changing multiple properties', () => {
expect(iconExists(iconName)).toEqual(false); return new Promise((fulfill, reject) => {
const prefix = nextPrefix();
const name = 'multiple-props';
const iconName = `@${provider}:${prefix}:${name}`;
const className = `iconify iconify--${prefix} iconify--${provider}`;
// Render component with placeholder text const onLoad = (name) => {
const Wrapper = { expect(name).toBe(iconName);
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad="onLoad" />`, (async () => {
methods: { try {
onLoad, // Wait 1 tick, test rendered icon
}, await nextTick();
};
const wrapper = mount(Wrapper, {}); expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className +
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
// Add horizontal flip and style
wrapper.setProps({
icon: iconName,
hFlip: true,
style: {
color: 'red',
},
});
// Wait 1 tick
await nextTick();
// Test
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toEqual(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className +
'" style="color: red;"><g transform="translate(24 0) scale(-1 1)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
);
fulfill(true);
} catch (err) {
reject(err);
}
})();
};
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
},
},
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toEqual(false);
// Send icon data
next();
// Make sure icon was loaded
expect(iconExists(iconName)).toEqual(true);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toEqual(false);
// Render component with placeholder text
const Wrapper = {
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad="onLoad" />`,
methods: {
onLoad,
},
};
const wrapper = mount(Wrapper, {});
});
}); });
}); });

View File

@ -45,19 +45,19 @@
"@iconify/types": "workspace:^" "@iconify/types": "workspace:^"
}, },
"devDependencies": { "devDependencies": {
"@babel/preset-env": "^7.18.2", "@babel/preset-env": "^7.19.0",
"@iconify/core": "workspace:^", "@iconify/core": "workspace:^",
"@iconify/utils": "workspace:^", "@iconify/utils": "workspace:^",
"@microsoft/api-extractor": "^7.25.2", "@microsoft/api-extractor": "^7.30.0",
"@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-node-resolve": "^13.3.0",
"@types/jest": "^27.5.2", "@types/jest": "^29.0.0",
"@vue/test-utils": "^1.3.0", "@vue/test-utils": "^1.3.0",
"@vue/vue2-jest": "^27.0.0", "@vue/vue2-jest": "^29.0.0",
"babel-jest": "^27.5.1", "babel-jest": "^29.0.2",
"jest": "28.0.0-alpha.11", "jest": "^29.0.2",
"rollup": "^2.75.6", "rollup": "^2.79.0",
"typescript": "^4.7.4", "typescript": "^4.8.2",
"vue": "^2.6.14" "vue": "^2.7.10"
}, },
"peerDependencies": { "peerDependencies": {
"vue": "2.x" "vue": "2.x"

View File

@ -6,39 +6,41 @@ import { mockAPIData } from '@iconify/core/lib/api/modules/mock.cjs';
import { provider, nextPrefix } from './load'; import { provider, nextPrefix } from './load';
describe('Testing fake API', () => { describe('Testing fake API', () => {
test('using fake API to load icon', done => { test('using fake API to load icon', () => {
const prefix = nextPrefix(); return new Promise((fulfill) => {
const name = 'mock-test'; const prefix = nextPrefix();
const iconName = `@${provider}:${prefix}:${name}`; const name = 'mock-test';
mockAPIData({ const iconName = `@${provider}:${prefix}:${name}`;
type: 'icons', mockAPIData({
provider, type: 'icons',
prefix, provider,
response: {
prefix, prefix,
icons: { response: {
[name]: { prefix,
body: '<g />', icons: {
[name]: {
body: '<g />',
},
}, },
}, },
}, });
});
// Check if icon has been loaded // Check if icon has been loaded
expect(iconExists(iconName)).toBe(false); expect(iconExists(iconName)).toBe(false);
// Load icon // Load icon
loadIcons([iconName], (loaded, missing, pending) => { loadIcons([iconName], (loaded, missing, pending) => {
expect(loaded).toMatchObject([ expect(loaded).toMatchObject([
{ {
provider, provider,
prefix, prefix,
name, name,
}, },
]); ]);
expect(missing).toMatchObject([]); expect(missing).toMatchObject([]);
expect(pending).toMatchObject([]); expect(pending).toMatchObject([]);
done(); fulfill(true);
});
}); });
}); });
}); });

View File

@ -9,207 +9,214 @@ import { provider, nextPrefix } from './load';
import { defaultIconResult } from '../empty'; import { defaultIconResult } from '../empty';
const iconData = { const iconData = {
body: body: '<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
width: 24, width: 24,
height: 24, height: 24,
}; };
describe('Rendering icon', () => { describe('Rendering icon', () => {
test('rendering icon after loading it', done => { test('rendering icon after loading it', () => {
const prefix = nextPrefix(); return new Promise((fulfill) => {
const name = 'render-test'; const prefix = nextPrefix();
const iconName = `@${provider}:${prefix}:${name}`; const name = 'render-test';
const className = `iconify iconify--${prefix} iconify--${provider}`; const iconName = `@${provider}:${prefix}:${name}`;
let onLoadCalled = false; const className = `iconify iconify--${prefix} iconify--${provider}`;
let onLoadCalled = false;
mockAPIData({ mockAPIData({
type: 'icons', type: 'icons',
provider, provider,
prefix,
response: {
prefix, prefix,
icons: { response: {
[name]: iconData,
},
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toBe(false);
// Load icon
loadIcons([iconName], (loaded, missing, pending) => {
// Make sure icon has been loaded
expect(loaded).toMatchObject([
{
provider,
prefix, prefix,
name, icons: {
[name]: iconData,
},
}, },
]); });
expect(missing).toMatchObject([]);
expect(pending).toMatchObject([]); // Check if icon has been loaded
expect(iconExists(iconName)).toBe(true); expect(iconExists(iconName)).toBe(false);
// Load icon
loadIcons([iconName], (loaded, missing, pending) => {
// Make sure icon has been loaded
expect(loaded).toMatchObject([
{
provider,
prefix,
name,
},
]);
expect(missing).toMatchObject([]);
expect(pending).toMatchObject([]);
expect(iconExists(iconName)).toBe(true);
// Render component
const Wrapper = {
components: { Icon },
// Also test class string
template: `<Icon icon="${iconName}" :onLoad="onLoad" class="test" />`,
methods: {
onLoad(name) {
expect(name).toBe(iconName);
expect(onLoadCalled).toBe(false);
onLoadCalled = true;
},
},
};
const wrapper = mount(Wrapper, {});
const html = wrapper.html().replace(/\s*\n\s*/g, '');
// Check HTML on next tick
Vue.nextTick(() => {
expect(html).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="test ' +
className +
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
// Make sure onLoad has been called
expect(onLoadCalled).toBe(true);
fulfill(true);
});
});
});
});
test('rendering icon before loading it', () => {
return new Promise((fulfill) => {
const prefix = nextPrefix();
const name = 'mock-test';
const iconName = `@${provider}:${prefix}:${name}`;
const className = `iconify iconify--${prefix} iconify--${provider}`;
let onLoadCalled = false;
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
},
},
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toBe(false);
// onLoad should not have been called yet
expect(onLoadCalled).toBe(false);
// Send icon data
next();
// Test it again
expect(iconExists(iconName)).toBe(true);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toBe(false);
// Render component // Render component
const Wrapper = { const Wrapper = {
components: { Icon }, components: { Icon },
// Also test class string template: `<Icon icon="${iconName}" :onLoad="onLoad" :class="testClass" />`,
template: `<Icon icon="${iconName}" :onLoad="onLoad" class="test" />`,
methods: { methods: {
onLoad(name) { onLoad(name) {
expect(name).toBe(iconName); expect(name).toBe(iconName);
expect(onLoadCalled).toBe(false); expect(onLoadCalled).toBe(false);
onLoadCalled = true; onLoadCalled = true;
// Test component on next tick
Vue.nextTick(() => {
// Check HTML
expect(
wrapper.html().replace(/\s*\n\s*/g, '')
).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className +
// 'foo' is appended because of weird Vue 2 behavior. Fixed in Vue 3
' foo"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
// onLoad should have been called
expect(onLoadCalled).toBe(true);
fulfill(true);
});
},
},
data() {
// Test dynamic class
return {
testClass: {
foo: true,
bar: false,
},
};
},
};
const wrapper = mount(Wrapper, {});
// onLoad should not have been called yet
expect(onLoadCalled).toBe(false);
});
});
test('missing icon', () => {
return new Promise((fulfill) => {
const prefix = nextPrefix();
const name = 'missing-icon';
const iconName = `@${provider}:${prefix}:${name}`;
mockAPIData({
type: 'icons',
provider,
prefix,
response: 404,
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toBe(false);
// Send icon data
next();
// Test it again
expect(iconExists(iconName)).toBe(false);
// Check if state was changed after few ticks
Vue.nextTick(() => {
Vue.nextTick(() => {
Vue.nextTick(() => {
expect(wrapper.html()).toBe(defaultIconResult);
fulfill(true);
});
});
});
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toBe(false);
// Render component
const Wrapper = {
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad="onLoad" />`,
methods: {
onLoad() {
throw new Error('onLoad called for empty icon!');
}, },
}, },
}; };
const wrapper = mount(Wrapper, {}); const wrapper = mount(Wrapper, {});
const html = wrapper.html().replace(/\s*\n\s*/g, '');
// Check HTML on next tick // Should render empty icon
Vue.nextTick(() => { expect(wrapper.html()).toBe(defaultIconResult);
expect(html).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="test ' +
className +
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
// Make sure onLoad has been called
expect(onLoadCalled).toBe(true);
done();
});
}); });
}); });
test('rendering icon before loading it', done => {
const prefix = nextPrefix();
const name = 'mock-test';
const iconName = `@${provider}:${prefix}:${name}`;
const className = `iconify iconify--${prefix} iconify--${provider}`;
let onLoadCalled = false;
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
},
},
delay: next => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toBe(false);
// onLoad should not have been called yet
expect(onLoadCalled).toBe(false);
// Send icon data
next();
// Test it again
expect(iconExists(iconName)).toBe(true);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toBe(false);
// Render component
const Wrapper = {
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad="onLoad" :class="testClass" />`,
methods: {
onLoad(name) {
expect(name).toBe(iconName);
expect(onLoadCalled).toBe(false);
onLoadCalled = true;
// Test component on next tick
Vue.nextTick(() => {
// Check HTML
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className +
// 'foo' is appended because of weird Vue 2 behavior. Fixed in Vue 3
' foo"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
// onLoad should have been called
expect(onLoadCalled).toBe(true);
done();
});
},
},
data() {
// Test dynamic class
return {
testClass: {
foo: true,
bar: false,
},
};
},
};
const wrapper = mount(Wrapper, {});
// onLoad should not have been called yet
expect(onLoadCalled).toBe(false);
});
test('missing icon', done => {
const prefix = nextPrefix();
const name = 'missing-icon';
const iconName = `@${provider}:${prefix}:${name}`;
mockAPIData({
type: 'icons',
provider,
prefix,
response: 404,
delay: next => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toBe(false);
// Send icon data
next();
// Test it again
expect(iconExists(iconName)).toBe(false);
// Check if state was changed after few ticks
Vue.nextTick(() => {
Vue.nextTick(() => {
Vue.nextTick(() => {
expect(wrapper.html()).toBe(defaultIconResult);
done();
});
});
});
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toBe(false);
// Render component
const Wrapper = {
components: { Icon },
template: `<Icon icon="${iconName}" :onLoad="onLoad" />`,
methods: {
onLoad() {
throw new Error('onLoad called for empty icon!');
},
},
};
const wrapper = mount(Wrapper, {});
// Should render empty icon
expect(wrapper.html()).toBe(defaultIconResult);
});
}); });

View File

@ -9,320 +9,330 @@ import { provider, nextPrefix } from './load';
import { defaultIconResult } from '../empty'; import { defaultIconResult } from '../empty';
const iconData = { const iconData = {
body: body: '<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
'<path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"/>',
width: 24, width: 24,
height: 24, height: 24,
}; };
const iconData2 = { const iconData2 = {
body: body: '<path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"/>',
'<path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"/>',
width: 32, width: 32,
height: 32, height: 32,
}; };
describe('Rendering icon', () => { describe('Rendering icon', () => {
test('changing icon property', done => { test('changing icon property', () => {
const prefix = nextPrefix(); return new Promise((fulfill) => {
const name = 'changing-prop'; const prefix = nextPrefix();
const name2 = 'changing-prop2'; const name = 'changing-prop';
const iconName = `@${provider}:${prefix}:${name}`; const name2 = 'changing-prop2';
const iconName2 = `@${provider}:${prefix}:${name2}`; const iconName = `@${provider}:${prefix}:${name}`;
const className = `iconify iconify--${prefix} iconify--${provider}`; const iconName2 = `@${provider}:${prefix}:${name2}`;
let onLoadCalled = ''; // Name of icon from last onLoad call const className = `iconify iconify--${prefix} iconify--${provider}`;
let onLoadCalled = ''; // Name of icon from last onLoad call
const onLoad = name => { const onLoad = (name) => {
// onLoad should be called only once per icon // onLoad should be called only once per icon
switch (name) { switch (name) {
// First onLoad call // First onLoad call
case iconName: case iconName:
expect(onLoadCalled).toBe(''); expect(onLoadCalled).toBe('');
// Wait 1 tick, then test rendered icon // Wait 1 tick, then test rendered icon
Vue.nextTick(() => { Vue.nextTick(() => {
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toBe( expect(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' + wrapper.html().replace(/\s*\n\s*/g, '')
className + ).toBe(
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>' '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
); className +
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
// onLoad should have been called // onLoad should have been called
expect(onLoadCalled).toBe(iconName);
wrapper.setProps({
icon: iconName2,
});
});
break;
// Second onLoad call
case iconName2:
expect(onLoadCalled).toBe(iconName); expect(onLoadCalled).toBe(iconName);
wrapper.setProps({ // Wait 1 tick, then test rendered icon
icon: iconName2, Vue.nextTick(() => {
}); expect(
}); wrapper.html().replace(/\s*\n\s*/g, '')
break; ).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 32 32" class="' +
className +
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
);
// Second onLoad call // onLoad should have been called for second icon
case iconName2: expect(onLoadCalled).toBe(iconName2);
fulfill(true);
});
break;
default:
throw new Error(`Unexpected onLoad('${name}') call`);
}
onLoadCalled = name;
};
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
},
},
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toBe(false);
// onLoad should not have been called yet
expect(onLoadCalled).toBe('');
// Send icon data
next();
// Make sure icon data is available
expect(iconExists(iconName)).toBe(true);
},
});
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name2]: iconData2,
},
},
delay: (next) => {
// Icon should not have loaded yet
expect(iconExists(iconName2)).toBe(false);
// onLoad should have been called only once for previous icon
expect(onLoadCalled).toBe(iconName); expect(onLoadCalled).toBe(iconName);
// Wait 1 tick, then test rendered icon // Send icon data
Vue.nextTick(() => { next();
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 32 32" class="' +
className +
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
);
// onLoad should have been called for second icon // Make sure icon data is available
expect(onLoadCalled).toBe(iconName2); expect(iconExists(iconName2)).toBe(true);
done();
});
break;
default:
throw new Error(`Unexpected onLoad('${name}') call`);
}
onLoadCalled = name;
};
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
}, },
}, });
delay: next => {
// Icon should not have loaded yet
expect(iconExists(iconName)).toBe(false);
// onLoad should not have been called yet // Check if icon has been loaded
expect(onLoadCalled).toBe(''); expect(iconExists(iconName)).toBe(false);
// Send icon data // Render component
next(); const wrapper = mount(Icon, {
propsData: {
// Make sure icon data is available
expect(iconExists(iconName)).toBe(true);
},
});
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name2]: iconData2,
},
},
delay: next => {
// Icon should not have loaded yet
expect(iconExists(iconName2)).toBe(false);
// onLoad should have been called only once for previous icon
expect(onLoadCalled).toBe(iconName);
// Send icon data
next();
// Make sure icon data is available
expect(iconExists(iconName2)).toBe(true);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toBe(false);
// Render component
const wrapper = mount(Icon, {
propsData: {
icon: iconName,
onLoad,
},
});
// Should render placeholder
expect(wrapper.html()).toBe(defaultIconResult);
// onLoad should not have been called yet
expect(onLoadCalled).toBe('');
});
test('changing icon property while loading', done => {
const prefix = nextPrefix();
const name = 'changing-prop';
const name2 = 'changing-prop2';
const iconName = `@${provider}:${prefix}:${name}`;
const iconName2 = `@${provider}:${prefix}:${name2}`;
const className = `iconify iconify--${prefix} iconify--${provider}`;
let isSync = true;
const onLoad = name => {
switch (name) {
case iconName:
done('onLoad should not be called for initial icon');
break;
case iconName2:
// Wait 1 tick, then test rendered icon
Vue.nextTick(() => {
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 32 32" class="' +
className +
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
);
done();
});
break;
default:
throw new Error(`Unexpected onLoad('${name}') call`);
}
};
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
},
},
delay: next => {
// Should have been called asynchronously, which means icon name has changed
expect(isSync).toBe(false);
// Send icon data
next();
},
});
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name2]: iconData2,
},
},
delay: next => {
// Should have been called asynchronously
expect(isSync).toBe(false);
// Icon should not have loaded yet
expect(iconExists(iconName2)).toBe(false);
// Send icon data
next();
// Test it again
expect(iconExists(iconName2)).toBe(true);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toBe(false);
// Render component
const wrapper = mount(Icon, {
propsData: {
icon: iconName,
onLoad,
},
});
// Should render placeholder
expect(wrapper.html()).toBe(defaultIconResult);
// Change icon name
wrapper.setProps({
icon: iconName2,
});
// Async
isSync = false;
});
test('changing multiple properties', done => {
const prefix = nextPrefix();
const name = 'multiple-props';
const iconName = `@${provider}:${prefix}:${name}`;
const className = `iconify iconify--${prefix} iconify--${provider}`;
const onLoad = name => {
expect(name).toBe(iconName);
// Wait 1 tick, test rendered icon
Vue.nextTick(() => {
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className +
'"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
);
// Add horizontal flip and style
wrapper.setProps({
icon: iconName, icon: iconName,
hFlip: true, onLoad,
// Vue 2 issue: changing style in unit test doesn't work, so changing color },
// TODO: test changing style in live demo to see if its a unit test bug or component issue });
color: 'red',
});
// Wait for 1 tick and test again // Should render placeholder
expect(wrapper.html()).toBe(defaultIconResult);
// onLoad should not have been called yet
expect(onLoadCalled).toBe('');
});
});
test('changing icon property while loading', () => {
return new Promise((fulfill, reject) => {
const prefix = nextPrefix();
const name = 'changing-prop';
const name2 = 'changing-prop2';
const iconName = `@${provider}:${prefix}:${name}`;
const iconName2 = `@${provider}:${prefix}:${name2}`;
const className = `iconify iconify--${prefix} iconify--${provider}`;
let isSync = true;
const onLoad = (name) => {
switch (name) {
case iconName:
reject('onLoad should not be called for initial icon');
break;
case iconName2:
// Wait 1 tick, then test rendered icon
Vue.nextTick(() => {
expect(
wrapper.html().replace(/\s*\n\s*/g, '')
).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 32 32" class="' +
className +
'"><path d="M19.031 4.281l-11 11l-.687.719l.687.719l11 11l1.438-1.438L10.187 16L20.47 5.719z" fill="currentColor"></path></svg>'
);
fulfill(true);
});
break;
default:
throw new Error(`Unexpected onLoad('${name}') call`);
}
};
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name]: iconData,
},
},
delay: (next) => {
// Should have been called asynchronously, which means icon name has changed
expect(isSync).toBe(false);
// Send icon data
next();
},
});
mockAPIData({
type: 'icons',
provider,
prefix,
response: {
prefix,
icons: {
[name2]: iconData2,
},
},
delay: (next) => {
// Should have been called asynchronously
expect(isSync).toBe(false);
// Icon should not have loaded yet
expect(iconExists(iconName2)).toBe(false);
// Send icon data
next();
// Test it again
expect(iconExists(iconName2)).toBe(true);
},
});
// Check if icon has been loaded
expect(iconExists(iconName)).toBe(false);
// Render component
const wrapper = mount(Icon, {
propsData: {
icon: iconName,
onLoad,
},
});
// Should render placeholder
expect(wrapper.html()).toBe(defaultIconResult);
// Change icon name
wrapper.setProps({
icon: iconName2,
});
// Async
isSync = false;
});
});
test('changing multiple properties', () => {
return new Promise((fulfill) => {
const prefix = nextPrefix();
const name = 'multiple-props';
const iconName = `@${provider}:${prefix}:${name}`;
const className = `iconify iconify--${prefix} iconify--${provider}`;
const onLoad = (name) => {
expect(name).toBe(iconName);
// Wait 1 tick, test rendered icon
Vue.nextTick(() => { Vue.nextTick(() => {
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toBe( expect(wrapper.html().replace(/\s*\n\s*/g, '')).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' + '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className + className +
'" style="color: red;"><g transform="translate(24 0) scale(-1 1)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>' '"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></svg>'
); );
done(); // Add horizontal flip and style
wrapper.setProps({
icon: iconName,
hFlip: true,
// Vue 2 issue: changing style in unit test doesn't work, so changing color
// TODO: test changing style in live demo to see if its a unit test bug or component issue
color: 'red',
});
// Wait for 1 tick and test again
Vue.nextTick(() => {
expect(wrapper.html().replace(/\s*\n\s*/g, '')).toBe(
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 24 24" class="' +
className +
'" style="color: red;"><g transform="translate(24 0) scale(-1 1)"><path d="M4 19h16v2H4zm5-4h11v2H9zm-5-4h16v2H4zm0-8h16v2H4zm5 4h11v2H9z" fill="currentColor"></path></g></svg>'
);
fulfill(true);
});
}); });
}); };
};
mockAPIData({ mockAPIData({
type: 'icons', type: 'icons',
provider, provider,
prefix,
response: {
prefix, prefix,
icons: { response: {
[name]: iconData, prefix,
icons: {
[name]: iconData,
},
}, },
}, delay: (next) => {
delay: next => { // Icon should not have loaded yet
// Icon should not have loaded yet expect(iconExists(iconName)).toBe(false);
expect(iconExists(iconName)).toBe(false);
// Send icon data // Send icon data
next(); next();
// Make sure icon was loaded // Make sure icon was loaded
expect(iconExists(iconName)).toBe(true); expect(iconExists(iconName)).toBe(true);
}, },
});
// Check if icon has been loaded
expect(iconExists(iconName)).toBe(false);
// Render component with placeholder text
const wrapper = mount(Icon, {
propsData: {
icon: iconName,
onLoad,
},
});
// Should be empty
expect(wrapper.html()).toBe(defaultIconResult);
}); });
// Check if icon has been loaded
expect(iconExists(iconName)).toBe(false);
// Render component with placeholder text
const wrapper = mount(Icon, {
propsData: {
icon: iconName,
onLoad,
},
});
// Should be empty
expect(wrapper.html()).toBe(defaultIconResult);
}); });
}); });