Skip to content

Commit

Permalink
feat(UsaFooterSocialLinks): implement UsaFooterSocialLinks component
Browse files Browse the repository at this point in the history
ISSUES CLOSED: #31
  • Loading branch information
patrickcate committed Mar 18, 2022
1 parent 4b5cb3e commit aa68d9d
Show file tree
Hide file tree
Showing 4 changed files with 298 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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: `<UsaFooterSocialLinks
class="grid-row grid-gap-1"
:items="items"
:custom-classes="customClasses"
></UsaFooterSocialLinks>`,
})

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'
163 changes: 163 additions & 0 deletions src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.test.js
Original file line number Diff line number Diff line change
@@ -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')
})
})
45 changes: 45 additions & 0 deletions src/components/UsaFooterSocialLinks/UsaFooterSocialLinks.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script setup>
import BaseLink from '@/components/BaseLink'
defineProps({
items: {
type: Array,
default: () => [],
},
customClasses: {
type: Object,
default: () => ({
gridCol: ['grid-col-auto'],
link: [],
icon: [],
}),
},
})
</script>

<template>
<div class="usa-footer__social-links">
<div
v-for="item in items"
:key="item?.id || item.name"
:class="customClasses?.gridCol"
>
<BaseLink
:to="item.to"
:href="item.href"
class="usa-social-link"
:class="customClasses?.link"
:router-component-name="item.routerComponentName"
>
<slot :name="item?.id || item.name.toLowerCase()" :item="item">
<img
class="usa-social-link__icon"
:class="customClasses?.icon"
:src="item.icon"
:alt="item.name"
/>
</slot>
</BaseLink>
</div>
</div>
</template>
4 changes: 4 additions & 0 deletions src/components/UsaFooterSocialLinks/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import UsaFooterSocialLinks from './UsaFooterSocialLinks.vue'

export { UsaFooterSocialLinks }
export default UsaFooterSocialLinks

0 comments on commit aa68d9d

Please sign in to comment.