diff --git a/src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.stories.js b/src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.stories.js new file mode 100644 index 00000000..4258da96 --- /dev/null +++ b/src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.stories.js @@ -0,0 +1,86 @@ +import UsaFooterSocialLinks from './UsaFooterSocialLinks.vue' + +const testItems = [ + { + id: 'facebook', + name: 'Facebook', + href: 'https://facebook.com', + icon: '/assets/img/usa-icons/facebook.svg', + }, + { + id: 'twitter', + name: 'Twitter', + href: 'https://twitter.com', + icon: '/assets/img/usa-icons/twitter.svg', + }, + { + id: 'youtube', + name: 'YouTube', + href: 'https://youtube.com', + icon: '/assets/img/usa-icons/youtube.svg', + }, + { + id: 'instagram', + name: 'Instagram', + href: 'https://instagram.com', + icon: '/assets/img/usa-icons/instagram.svg', + }, + { + id: 'rss', + name: 'RSS', + href: '#', + icon: '/assets/img/usa-icons/rss_feed.svg', + }, +] + +const defaultProps = { + items: UsaFooterSocialLinks.props.items.default(), + customClasses: UsaFooterSocialLinks.props.customClasses.default(), +} + +export default { + component: UsaFooterSocialLinks, + title: 'Components/UsaFooterSocialLinks', + argTypes: { + items: { + control: { type: 'object' }, + }, + customClasses: { + control: { type: 'object' }, + }, + }, + items: defaultProps.cols, + customClasses: defaultProps.customClasses, +} + +const DefaultTemplate = (args, { argTypes }) => ({ + components: { UsaFooterSocialLinks }, + props: Object.keys(argTypes), + setup() { + return { ...args } + }, + template: ``, +}) + +export const DefaultFooterSocialLinks = DefaultTemplate.bind({}) +DefaultFooterSocialLinks.args = { + ...defaultProps, + items: testItems, +} +DefaultFooterSocialLinks.storyName = 'Default' + +export const CustomClassesFooterSocialLinks = DefaultTemplate.bind({}) +CustomClassesFooterSocialLinks.args = { + ...defaultProps, + items: testItems, + customClasses: { + gridCol: ['grid-col-auto', 'test-grid-col-class'], + link: ['test-link-class'], + icon: ['test-icon-class'], + }, +} +CustomClassesFooterSocialLinks.storyName = 'Custom Classes' diff --git a/src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.test.js b/src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.test.js new file mode 100644 index 00000000..4f2eb76c --- /dev/null +++ b/src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.test.js @@ -0,0 +1,163 @@ +import '@module/uswds/dist/css/uswds.min.css' +import { mount } from '@cypress/vue' +import UsaFooterSocialLinks from './UsaFooterSocialLinks.vue' + +describe('UsaFooterSocialLinks', () => { + const testItems = [ + { + id: 'fb', + name: 'Facebook', + href: 'https://facebook.com', + icon: '/assets/img/usa-icons/facebook.svg', + }, + { + name: 'Twitter', + to: 'https://twitter.com', + icon: '/assets/img/usa-icons/twitter.svg', + }, + { + name: 'YouTube', + to: '/youtube', + icon: '/assets/img/usa-icons/youtube.svg', + routerComponentName: 'nuxt-link', + }, + ] + + it('renders the component', () => { + mount(UsaFooterSocialLinks, {}) + + cy.get('div.usa-footer__social-links').as('socialLink').should('exist') + cy.get('@socialLink').children().should('have.length', 0) + }) + + it('display social media icons', () => { + mount(UsaFooterSocialLinks, { + props: { + items: testItems, + }, + attrs: { + class: 'grid-row grid-gap-1', + }, + }) + + cy.get('.usa-footer__social-links').as('socialLink').should('exist') + cy.get('@socialLink') + .find('> div') + .should('have.length', 3) + .and('have.class', 'grid-col-auto') + + // Item 1 + cy.get('@socialLink').find('> div:nth-of-type(1)').as('item1') + + cy.get('@item1') + .find('> a') + .as('link1') + .should('have.class', 'usa-social-link') + .and('have.attr', 'href') + .and('contain', 'https://facebook.com') + + cy.get('@link1') + .find('> img') + .as('icon1') + .should('have.class', 'usa-social-link__icon') + .and('have.attr', 'src') + .and('contain', '/assets/img/usa-icons/facebook.svg') + + cy.get('@icon1').should('have.attr', 'alt').and('contain', 'Facebook') + + // Item 2 + cy.get('@socialLink').find('> div:nth-of-type(2)').as('item2') + + cy.get('@item2') + .find('> a') + .as('link2') + .should('have.class', 'usa-social-link') + .and('have.attr', 'href') + .and('contain', 'https://twitter.com') + + cy.get('@link2') + .find('> img') + .as('icon2') + .should('have.class', 'usa-social-link__icon') + .and('have.attr', 'src') + .and('contain', '/assets/img/usa-icons/twitter.svg') + + cy.get('@icon2').should('have.attr', 'alt').and('contain', 'Twitter') + + // Item 3 + cy.get('@socialLink').find('> div:nth-of-type(3)').as('item3') + + cy.get('@item3') + .find('> nuxt-link') + .as('link3') + .should('have.class', 'usa-social-link') + .and('have.attr', 'to') + .and('contain', '/youtube') + + cy.get('@link3') + .find('> img') + .as('icon3') + .should('have.class', 'usa-social-link__icon') + .and('have.attr', 'src') + .and('contain', '/assets/img/usa-icons/youtube.svg') + + cy.get('@icon3').should('have.attr', 'alt').and('contain', 'YouTube') + }) + + it('uses named icon scoped slots', () => { + mount(UsaFooterSocialLinks, { + props: { + items: testItems, + }, + slots: { + fb: ({ item }) => `${item.name}`, + twitter: ({ item }) => `${item.name}`, + youtube: ({ item }) => `${item.name}`, + }, + }) + + cy.get('.usa-footer__social-links').as('socialLink').should('exist') + + cy.get('@socialLink') + .find('> div:nth-of-type(1) > *') + .should('contain', 'Facebook') + + cy.get('@socialLink') + .find('> div:nth-of-type(2) > *') + .should('contain', 'Twitter') + + cy.get('@socialLink') + .find('> div:nth-of-type(3) > *') + .should('contain', 'YouTube') + }) + + it('adds custom CSS classes', () => { + mount(UsaFooterSocialLinks, { + props: { + items: testItems, + customClasses: { + gridCol: ['test-grid-col-class'], + link: ['test-link-class'], + icon: ['test-icon-class'], + }, + }, + }) + + cy.get('.usa-footer__social-links').as('socialLink').should('exist') + + cy.get('@socialLink') + .find('> div') + .should('have.length', 3) + .and('have.class', 'test-grid-col-class') + + cy.get('@socialLink') + .find('> div > *') + .should('have.length', 3) + .and('have.class', 'test-link-class') + + cy.get('@socialLink') + .find('> div img') + .should('have.length', 3) + .and('have.class', 'test-icon-class') + }) +}) diff --git a/src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.vue b/src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.vue new file mode 100644 index 00000000..20ae0a17 --- /dev/null +++ b/src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/components/UsaFooterSocialLinks/index.js b/src/components/UsaFooterSocialLinks/index.js new file mode 100644 index 00000000..5cb73aac --- /dev/null +++ b/src/components/UsaFooterSocialLinks/index.js @@ -0,0 +1,4 @@ +import UsaFooterSocialLinks from './UsaFooterSocialLinks.vue' + +export { UsaFooterSocialLinks } +export default UsaFooterSocialLinks